diff --git a/Cargo.lock b/Cargo.lock index bb828ca..1772741 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -693,6 +693,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + [[package]] name = "const-oid" version = "0.9.6" @@ -1057,6 +1063,18 @@ dependencies = [ "serde 1.0.218", ] +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + [[package]] name = "embedded-dma" version = "0.2.0" @@ -2870,6 +2888,12 @@ dependencies = [ "fixed", ] +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -3540,6 +3564,7 @@ name = "pico-st7789" version = "0.1.0" dependencies = [ "cortex-m-rt", + "embedded-alloc", "embedded-hal 1.0.0", "fugit", "panic-halt", @@ -4131,6 +4156,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + [[package]] name = "rp-pico" version = "0.9.0" @@ -4844,6 +4881,19 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64 0.9.3", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/pico-st7789/Cargo.toml b/pico-st7789/Cargo.toml index 6d8012e..001c708 100644 --- a/pico-st7789/Cargo.toml +++ b/pico-st7789/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] cortex-m-rt = "0.7.3" +embedded-alloc = "0.6.0" embedded-hal = "1.0.0" fugit = "0.3.7" panic-halt = "1.0.0" diff --git a/pico-st7789/src/drawing.rs b/pico-st7789/src/drawing.rs new file mode 100644 index 0000000..e02e868 --- /dev/null +++ b/pico-st7789/src/drawing.rs @@ -0,0 +1,125 @@ +// a a a +// f b +// f b +// f b +// g g g +// e c +// e c +// e c +// d d d + +use alloc::{boxed::Box, vec::Vec}; + +pub struct Canvas<'a> { + pub buf: &'a mut [u8], + pub width: usize, +} + +impl<'a> Canvas<'a> { + pub fn new(buf: &'a mut [u8], columns: usize) -> Self { + Self { + buf, + width: columns, + } + } + + pub fn set_pixel(&mut self, x: usize, y: usize, color: (u8, u8, u8)) { + self.buf[(y * self.width + x) * 3 + 0] = color.0 << 2; + self.buf[(y * self.width + x) * 3 + 1] = color.1 << 2; + self.buf[(y * self.width + x) * 3 + 2] = color.2 << 2; + } +} + +/* +pub const DIGIT_WIDTH: usize = 5; +pub const DIGIT_HEIGHT: usize = 9; + +pub const ZERO_SEVEN_SEGMENT: [bool; 7] = [true, true, true, true, true, true, false]; + +pub const ONE_SEVEN_SEGMENT: [bool; 7] = [false, true, true, false, false, false, false]; + +pub const TWO_SEVEN_SEGMENT: [bool; 7] = [true, true, false, true, true, false, true]; + +pub const THREE_SEVEN_SEGMENT: [bool; 7] = [true, true, true, true, false, false, true]; + +pub const FOUR_SEVEN_SEGMENT: [bool; 7] = [false, true, true, false, false, true, true]; + +pub const FIVE_SEVEN_SEGMENT: [bool; 7] = [true, false, true, true, false, true, true]; + +pub const SIX_SEVEN_SEGMENT: [bool; 7] = [true, false, true, true, true, true, true]; + +pub const SEVEN_SEVEN_SEGMENT: [bool; 7] = [true, true, true, false, false, false, false]; + +pub const EIGHT_SEVEN_SEGMENT: [bool; 7] = [true, true, true, true, true, true, true]; + +pub const NINE_SEVEN_SEGMENT: [bool; 7] = [true, true, true, false, false, true, true]; + +pub const SEVEN_SEGMENT_FONT: [[bool; 7]; 10] = [ + ZERO_SEVEN_SEGMENT, + ONE_SEVEN_SEGMENT, + TWO_SEVEN_SEGMENT, + THREE_SEVEN_SEGMENT, + FOUR_SEVEN_SEGMENT, + FIVE_SEVEN_SEGMENT, + SIX_SEVEN_SEGMENT, + SEVEN_SEVEN_SEGMENT, + EIGHT_SEVEN_SEGMENT, + NINE_SEVEN_SEGMENT, +]; +*/ + +/* +pub fn draw_pixel(frame: &mut Canvas, x: usize, y: usize, color: (u8, u8, u8)) { + frame.buf[(y * frame.width + x) * 3 + 0] = color.0 << 2; + frame.buf[(y * frame.width + x) * 3 + 1] = color.1 << 2; + frame.buf[(y * frame.width + x) * 3 + 2] = color.2 << 2; +} +*/ + +/* +pub fn draw_seven_segment( + digit: u8, + frame: &mut [u8], + width: usize, + x: usize, + y: usize, + color: (u8, u8, u8), +) { + let segments = SEVEN_SEGMENT_FONT[digit as usize]; + if segments[0] { + write_pixel(frame, x + 1, y, color); + write_pixel(frame, x + 2, y, color); + write_pixel(frame, x + 3, y, color); + } + if segments[1] { + write_pixel(frame, x + 4, y + 1, color); + write_pixel(frame, x + 4, y + 2, color); + write_pixel(frame, x + 4, y + 3, color); + } + if segments[2] { + write_pixel(frame, x + 4, y + 5, color); + write_pixel(frame, x + 4, y + 6, color); + write_pixel(frame, x + 4, y + 7, color); + } + if segments[3] { + write_pixel(frame, x + 1, y + 8, color); + write_pixel(frame, x + 2, y + 8, color); + write_pixel(frame, x + 3, y + 8, color); + } + if segments[4] { + write_pixel(frame, x, y + 5, color); + write_pixel(frame, x, y + 6, color); + write_pixel(frame, x, y + 7, color); + } + if segments[5] { + write_pixel(frame, x, y + 1, color); + write_pixel(frame, x, y + 2, color); + write_pixel(frame, x, y + 3, color); + } + if segments[6] { + write_pixel(frame, x + 1, y + 4, color); + write_pixel(frame, x + 2, y + 4, color); + write_pixel(frame, x + 3, y + 4, color); + } +} +*/ diff --git a/pico-st7789/src/font.rs b/pico-st7789/src/font.rs new file mode 100644 index 0000000..a2f4c3e --- /dev/null +++ b/pico-st7789/src/font.rs @@ -0,0 +1,398 @@ +use alloc::collections::btree_map::BTreeMap; + +use crate::drawing::Canvas; + +pub trait Font { + fn glyph(&self, c: char) -> &A; +} + +pub trait Glyph { + fn draw(&self, canvas: &mut Canvas, x: usize, y: usize, color: (u8, u8, u8)); +} + +// Sixteen Segments +// +// a1 a2 +// f h i jb +// f i j b +// f hij b +// g1 g2 +// e klm c +// e k l m c +// ek l mc +// d1 d2 + +pub struct SixteenSegmentGlyph { + a1: bool, + a2: bool, + b: bool, + c: bool, + d1: bool, + d2: bool, + e: bool, + f: bool, + g1: bool, + g2: bool, + h: bool, + i: bool, + j: bool, + k: bool, + l: bool, + m: bool, +} + +pub struct SixteenSegmentFont(BTreeMap); + +impl SixteenSegmentFont { + pub fn new() -> Self { + let mut font = BTreeMap::new(); + font.insert( + '*', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: true, + d2: true, + e: true, + f: true, + g1: true, + g2: true, + h: true, + i: true, + j: true, + k: true, + l: true, + m: true, + }, + ); + font.insert( + '0', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: true, + d2: true, + e: true, + f: true, + g1: false, + g2: false, + h: false, + i: false, + j: true, + k: true, + l: false, + m: false, + }, + ); + font.insert( + '1', + SixteenSegmentGlyph { + a1: false, + a2: false, + b: true, + c: true, + d1: false, + d2: false, + e: false, + f: false, + g1: false, + g2: false, + h: false, + i: false, + j: true, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '2', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: false, + d1: true, + d2: true, + e: true, + f: false, + g1: true, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '3', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: true, + d2: true, + e: false, + f: false, + g1: false, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '4', + SixteenSegmentGlyph { + a1: false, + a2: false, + b: true, + c: true, + d1: false, + d2: false, + e: false, + f: true, + g1: true, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '5', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: false, + c: false, + d1: true, + d2: true, + e: false, + f: true, + g1: true, + g2: false, + h: false, + i: false, + j: false, + k: false, + l: false, + m: true, + }, + ); + font.insert( + '6', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: false, + c: true, + d1: true, + d2: true, + e: true, + f: true, + g1: true, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '7', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: false, + d2: false, + e: false, + f: false, + g1: false, + g2: false, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '8', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: true, + d2: true, + e: true, + f: true, + g1: true, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + font.insert( + '9', + SixteenSegmentGlyph { + a1: true, + a2: true, + b: true, + c: true, + d1: true, + d2: true, + e: false, + f: true, + g1: true, + g2: true, + h: false, + i: false, + j: false, + k: false, + l: false, + m: false, + }, + ); + + Self(font) + } +} + +impl Font for SixteenSegmentFont { + fn glyph(&self, c: char) -> &SixteenSegmentGlyph { + self.0.get(&c).unwrap() + } +} + +impl Glyph for SixteenSegmentGlyph { + fn draw(&self, canvas: &mut Canvas, x: usize, y: usize, color: (u8, u8, u8)) { + if self.a1 { + canvas.set_pixel(x + 1, y, color); + canvas.set_pixel(x + 2, y, color); + canvas.set_pixel(x + 3, y, color); + } + if self.a2 { + canvas.set_pixel(x + 5, y, color); + canvas.set_pixel(x + 6, y, color); + canvas.set_pixel(x + 7, y, color); + } + if self.b { + canvas.set_pixel(x + 8, y + 1, color); + canvas.set_pixel(x + 8, y + 2, color); + canvas.set_pixel(x + 8, y + 3, color); + canvas.set_pixel(x + 8, y + 4, color); + canvas.set_pixel(x + 8, y + 5, color); + } + if self.c { + canvas.set_pixel(x + 8, y + 7, color); + canvas.set_pixel(x + 8, y + 8, color); + canvas.set_pixel(x + 8, y + 9, color); + canvas.set_pixel(x + 8, y + 10, color); + canvas.set_pixel(x + 8, y + 11, color); + } + + if self.d1 { + canvas.set_pixel(x + 1, y + 12, color); + canvas.set_pixel(x + 2, y + 12, color); + canvas.set_pixel(x + 3, y + 12, color); + } + if self.d2 { + canvas.set_pixel(x + 5, y + 12, color); + canvas.set_pixel(x + 6, y + 12, color); + canvas.set_pixel(x + 7, y + 12, color); + } + + if self.e { + canvas.set_pixel(x, y + 7, color); + canvas.set_pixel(x, y + 8, color); + canvas.set_pixel(x, y + 9, color); + canvas.set_pixel(x, y + 10, color); + canvas.set_pixel(x, y + 11, color); + } + if self.f { + canvas.set_pixel(x, y + 1, color); + canvas.set_pixel(x, y + 2, color); + canvas.set_pixel(x, y + 3, color); + canvas.set_pixel(x, y + 4, color); + canvas.set_pixel(x, y + 5, color); + } + + if self.g1 { + canvas.set_pixel(x + 1, y + 6, color); + canvas.set_pixel(x + 2, y + 6, color); + canvas.set_pixel(x + 3, y + 6, color); + } + if self.g2 { + canvas.set_pixel(x + 5, y + 6, color); + canvas.set_pixel(x + 6, y + 6, color); + canvas.set_pixel(x + 7, y + 6, color); + } + + if self.h { + canvas.set_pixel(x + 1, y + 1, color); + canvas.set_pixel(x + 1, y + 2, color); + canvas.set_pixel(x + 2, y + 3, color); + canvas.set_pixel(x + 3, y + 4, color); + canvas.set_pixel(x + 3, y + 5, color); + } + if self.i { + canvas.set_pixel(x + 4, y + 1, color); + canvas.set_pixel(x + 4, y + 2, color); + canvas.set_pixel(x + 4, y + 3, color); + canvas.set_pixel(x + 4, y + 4, color); + canvas.set_pixel(x + 4, y + 5, color); + } + if self.j { + canvas.set_pixel(x + 7, y + 1, color); + canvas.set_pixel(x + 7, y + 2, color); + canvas.set_pixel(x + 6, y + 3, color); + canvas.set_pixel(x + 5, y + 4, color); + canvas.set_pixel(x + 5, y + 5, color); + } + if self.k { + canvas.set_pixel(x + 3, y + 7, color); + canvas.set_pixel(x + 3, y + 8, color); + canvas.set_pixel(x + 2, y + 9, color); + canvas.set_pixel(x + 1, y + 10, color); + canvas.set_pixel(x + 1, y + 11, color); + } + if self.l { + canvas.set_pixel(x + 4, y + 7, color); + canvas.set_pixel(x + 4, y + 8, color); + canvas.set_pixel(x + 4, y + 9, color); + canvas.set_pixel(x + 4, y + 10, color); + canvas.set_pixel(x + 4, y + 11, color); + } + if self.m { + canvas.set_pixel(x + 5, y + 7, color); + canvas.set_pixel(x + 5, y + 8, color); + canvas.set_pixel(x + 6, y + 9, color); + canvas.set_pixel(x + 7, y + 10, color); + canvas.set_pixel(x + 7, y + 11, color); + } + } +} diff --git a/pico-st7789/src/main.rs b/pico-st7789/src/main.rs index cdb6130..33deb64 100644 --- a/pico-st7789/src/main.rs +++ b/pico-st7789/src/main.rs @@ -1,23 +1,26 @@ #![no_main] #![no_std] -use embedded_hal::{delay::DelayNs, digital::OutputPin, spi::SpiBus}; +extern crate alloc; + +use embedded_alloc::LlffHeap as Heap; +use embedded_hal::{delay::DelayNs, digital::OutputPin}; use fugit::RateExtU32; use panic_halt as _; use rp_pico::{ entry, - hal::{ - clocks::init_clocks_and_plls, - gpio::{FunctionSio, Pin, PinId, PullDown, SioOutput}, - spi::{Enabled, Spi, SpiDevice, ValidSpiPinout}, - Clock, Sio, Timer, Watchdog, - }, + hal::{clocks::init_clocks_and_plls, spi::Spi, Clock, Sio, Timer, Watchdog}, pac, Pins, }; +mod drawing; +use drawing::{Canvas}; + +mod font; +use font::{Font, Glyph, SixteenSegmentFont}; + mod st7789; use st7789::{ST7789Display, SETUP_PROGRAM}; -pub use st7789::Step; const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; // MHz, https://forums.raspberrypi.com/viewtopic.php?t=356764 @@ -25,15 +28,21 @@ const ROWS: usize = 320; const COLUMNS: usize = 170; const FRAMEBUF: usize = ROWS * COLUMNS * 3; -/* -struct Frame { - columns: usize, - buf: [u8; FRAMEBUF], -} -*/ +#[global_allocator] +static HEAP: Heap = Heap::empty(); + #[entry] unsafe fn main() -> ! { + { + use core::mem::MaybeUninit; + const HEAP_SIZE: usize = 1024; + static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; + unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) } + } + + let font_sixteen = SixteenSegmentFont::new(); + // rp_pico::pac::Peripherals is a reference to physical hardware defined on the Pico. let mut peripherals = pac::Peripherals::take().unwrap(); @@ -92,8 +101,8 @@ unsafe fn main() -> ! { &mut peripherals.RESETS, // The SPI system uses the peripheral clock clocks.peripheral_clock.freq(), - // Transmit data at a rate of 1Mbit. - 1_u32.MHz(), + // Transmit data at a rate of 32Mbit. + 32_u32.MHz(), // Run with SPI Mode 1. This means that the clock line should start high and that data will // be sampled starting at the first falling edge. embedded_hal::spi::MODE_3, @@ -110,31 +119,52 @@ unsafe fn main() -> ! { timer.delay_ms(1000); - let mut frame: [u8; FRAMEBUF] = [0; FRAMEBUF]; + let mut framebuf = [0; FRAMEBUF]; + let mut canvas = Canvas::new(&mut framebuf, COLUMNS); - let mut strength = 0; loop { - led.set_high(); { let display = display.acquire(); - display.send_buf(&frame); + let _ = led.set_high(); + timer.delay_ms(100); + display.send_buf(&canvas.buf); + let _ = led.set_low(); } + /* + draw_seven_segment(0, &mut frame, 0, 0, (255, 255, 255)); + draw_seven_segment(1, &mut frame, 7, 0, (255, 255, 255)); + draw_seven_segment(2, &mut frame, 14, 0, (255, 255, 255)); + draw_seven_segment(3, &mut frame, 21, 0, (255, 255, 255)); + draw_seven_segment(4, &mut frame, 28, 0, (255, 255, 255)); + draw_seven_segment(5, &mut frame, 35, 0, (255, 255, 255)); + draw_seven_segment(6, &mut frame, 42, 0, (255, 255, 255)); + draw_seven_segment(7, &mut frame, 49, 0, (255, 255, 255)); + draw_seven_segment(8, &mut frame, 56, 0, (255, 255, 255)); + draw_seven_segment(9, &mut frame, 63, 0, (255, 255, 255)); + */ + + font_sixteen.glyph('*').draw(&mut canvas, 0, 10, (255, 255, 255)); + font_sixteen.glyph('0').draw(&mut canvas, 11, 10, (255, 255, 255)); + font_sixteen.glyph('1').draw(&mut canvas, 22, 10, (255, 255, 255)); + font_sixteen.glyph('2').draw(&mut canvas, 33, 10, (255, 255, 255)); + font_sixteen.glyph('3').draw(&mut canvas, 44, 10, (255, 255, 255)); + font_sixteen.glyph('4').draw(&mut canvas, 55, 10, (255, 255, 255)); + font_sixteen.glyph('5').draw(&mut canvas, 66, 10, (255, 255, 255)); + font_sixteen.glyph('6').draw(&mut canvas, 77, 10, (255, 255, 255)); + font_sixteen.glyph('7').draw(&mut canvas, 88, 10, (255, 255, 255)); + font_sixteen.glyph('8').draw(&mut canvas, 99, 10, (255, 255, 255)); + font_sixteen.glyph('9').draw(&mut canvas, 110, 10, (255, 255, 255)); + + /* for x in 80..90 { for y in 155..165 { - write_pixel(&mut frame, x, y, (0, 0, 63)); + draw_pixel(&mut frame, x, y, (0, 0, 63)); } } - - timer.delay_ms(10); - led.set_low(); + */ timer.delay_ms(1000); } } -fn write_pixel(framebuf: &mut [u8], x: usize, y: usize, color: (u8, u8, u8)) { - framebuf[(y * COLUMNS + x) * 3 + 0] = color.0 << 2; - framebuf[(y * COLUMNS + x) * 3 + 1] = color.1 << 2; - framebuf[(y * COLUMNS + x) * 3 + 2] = color.2 << 2; -}