From f758c4b3910e8cb4d09c284db245e66de8cb5e5e Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 14 Jun 2024 16:55:05 +0200 Subject: Start implementing lcd --- examples/stm32u0/.cargo/config.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u0/src/bin/lcd.rs | 76 +++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 examples/stm32u0/src/bin/lcd.rs (limited to 'examples') diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml index 688347084..06eed6c8f 100644 --- a/examples/stm32u0/.cargo/config.toml +++ b/examples/stm32u0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace stm32u083rctx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip stm32u083rctx" +runner = "probe-rs run --chip stm32u083rctx --catch-hardfault" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index afeb4dc34..6c310b0f6 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083mc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs new file mode 100644 index 000000000..8612c3dfc --- /dev/null +++ b/examples/stm32u0/src/bin/lcd.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::lcd::{Bias, Config, Duty, Lcd, VoltageSource}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + // The RTC clock = the LCD clock and must be running + { + use embassy_stm32::rcc::*; + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL7, // 16 * 7 = 112 MHz + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz + }); + config.rcc.ls = LsConfig::default(); + } + + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut config = Config::default(); + config.bias = Bias::Third; + config.duty = Duty::Quarter; + + let mut lcd = Lcd::new( + p.LCD, + config, + [ + p.PC4.into(), + p.PC5.into(), + p.PB1.into(), + p.PE7.into(), + p.PE8.into(), + p.PE9.into(), + p.PB11.into(), + p.PB14.into(), + p.PB15.into(), + p.PD8.into(), + p.PD9.into(), + p.PD12.into(), + p.PB9.into(), + p.PA10.into(), + p.PA9.into(), + p.PA8.into(), + p.PD13.into(), + p.PC6.into(), + p.PC8.into(), + p.PC9.into(), + p.PC10.into(), + p.PD0.into(), + p.PD1.into(), + p.PD3.into(), + p.PD4.into(), + p.PD5.into(), + p.PD6.into(), + p.PC11.into(), + ], + ); + + loop { + defmt::info!("Writing frame"); + lcd.write_frame(&[0xAAAAAAAA; 16]); + defmt::info!("Writing frame"); + lcd.write_frame(&[!0xAAAAAAAA; 16]); + } +} -- cgit From 10a1a19e9470b96664f94cb9fc3aa53ea51695a4 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 15 Jun 2024 11:46:22 +0200 Subject: More debugging --- examples/stm32u0/src/bin/lcd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index 8612c3dfc..7a7c3a8a1 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { divq: None, divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz }); - config.rcc.ls = LsConfig::default(); + config.rcc.ls = LsConfig::default_lse(); } let p = embassy_stm32::init(config); -- cgit From 663732d85abbae400f2dbab2c411802a5b60e9b1 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 15 Jun 2024 13:51:16 +0200 Subject: Things work! --- examples/stm32u0/src/bin/lcd.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index 7a7c3a8a1..5551dd819 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::lcd::{Bias, Config, Duty, Lcd, VoltageSource}; +use embassy_stm32::{lcd::{Bias, Config, Duty, Lcd, VoltageSource}, time::Hertz}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { divq: None, divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz }); - config.rcc.ls = LsConfig::default_lse(); + config.rcc.ls = LsConfig::default_lsi(); } let p = embassy_stm32::init(config); @@ -31,46 +31,53 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.bias = Bias::Third; config.duty = Duty::Quarter; + config.target_fps = Hertz(60); let mut lcd = Lcd::new( p.LCD, config, + p.PC3, [ - p.PC4.into(), - p.PC5.into(), + p.PA8.into(), + p.PA9.into(), + p.PA10.into(), p.PB1.into(), - p.PE7.into(), - p.PE8.into(), - p.PE9.into(), + p.PB9.into(), p.PB11.into(), p.PB14.into(), p.PB15.into(), - p.PD8.into(), - p.PD9.into(), - p.PD12.into(), - p.PB9.into(), - p.PA10.into(), - p.PA9.into(), - p.PA8.into(), - p.PD13.into(), + p.PC4.into(), + p.PC5.into(), p.PC6.into(), p.PC8.into(), p.PC9.into(), p.PC10.into(), + p.PC11.into(), + p.PD8.into(), + p.PD9.into(), + p.PD12.into(), + p.PD13.into(), p.PD0.into(), p.PD1.into(), p.PD3.into(), p.PD4.into(), p.PD5.into(), p.PD6.into(), - p.PC11.into(), + p.PE7.into(), + p.PE8.into(), + p.PE9.into(), ], ); loop { defmt::info!("Writing frame"); lcd.write_frame(&[0xAAAAAAAA; 16]); + + embassy_time::Timer::after_secs(1).await; + defmt::info!("Writing frame"); lcd.write_frame(&[!0xAAAAAAAA; 16]); + + embassy_time::Timer::after_secs(1).await; } } -- cgit From d111eceb4ba0094d34f58a4695bb3d43d188e591 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 20 Nov 2025 14:16:43 +0100 Subject: Update LCD to modern embassy --- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u0/src/bin/lcd.rs | 63 +++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 31 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 9f5227e3f..42d349cda 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] # Change stm32u083rc to your chip name, if necessary. -embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } +embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083mc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index 5551dd819..f27c4458b 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -3,7 +3,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{lcd::{Bias, Config, Duty, Lcd, VoltageSource}, time::Hertz}; +use embassy_stm32::{ + lcd::{Bias, Config, Duty, Lcd, LcdPin}, + time::Hertz, +}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -31,41 +34,41 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.bias = Bias::Third; config.duty = Duty::Quarter; - config.target_fps = Hertz(60); + config.target_fps = Hertz(100); let mut lcd = Lcd::new( p.LCD, config, p.PC3, [ - p.PA8.into(), - p.PA9.into(), - p.PA10.into(), - p.PB1.into(), - p.PB9.into(), - p.PB11.into(), - p.PB14.into(), - p.PB15.into(), - p.PC4.into(), - p.PC5.into(), - p.PC6.into(), - p.PC8.into(), - p.PC9.into(), - p.PC10.into(), - p.PC11.into(), - p.PD8.into(), - p.PD9.into(), - p.PD12.into(), - p.PD13.into(), - p.PD0.into(), - p.PD1.into(), - p.PD3.into(), - p.PD4.into(), - p.PD5.into(), - p.PD6.into(), - p.PE7.into(), - p.PE8.into(), - p.PE9.into(), + LcdPin::from(p.PA8), + LcdPin::from(p.PA9), + LcdPin::from(p.PA10), + LcdPin::from(p.PB1), + LcdPin::from(p.PB9), + LcdPin::from(p.PB11), + LcdPin::from(p.PB14), + LcdPin::from(p.PB15), + LcdPin::from(p.PC4), + LcdPin::from(p.PC5), + LcdPin::from(p.PC6), + LcdPin::from(p.PC8), + LcdPin::from(p.PC9), + LcdPin::from(p.PC10), + LcdPin::from(p.PC11), + LcdPin::from(p.PD8), + LcdPin::from(p.PD9), + LcdPin::from(p.PD12), + LcdPin::from(p.PD13), + LcdPin::from(p.PD0), + LcdPin::from(p.PD1), + LcdPin::from(p.PD3), + LcdPin::from(p.PD4), + LcdPin::from(p.PD5), + LcdPin::from(p.PD6), + LcdPin::from(p.PE7), + LcdPin::from(p.PE8), + LcdPin::from(p.PE9), ], ); -- cgit From dd2a4d6126988d13e6ff21b26dc15deac1977531 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 20 Nov 2025 17:48:04 +0100 Subject: Create demo --- examples/stm32u0/src/bin/lcd.rs | 331 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 325 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index f27c4458b..f401b1dcd 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -5,8 +5,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::{ lcd::{Bias, Config, Duty, Lcd, LcdPin}, + peripherals::LCD, time::Hertz, }; +use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -72,15 +74,332 @@ async fn main(_spawner: Spawner) { ], ); + { + let mut buffer = DisplayBuffer::new(); + for i in 0..4 { + buffer.write_colon(i); + buffer.write(&mut lcd); + embassy_time::Timer::after_millis(200).await; + buffer.write_dot(i); + buffer.write(&mut lcd); + embassy_time::Timer::after_millis(200).await; + } + for i in 0..4 { + buffer.write_bar(i); + buffer.write(&mut lcd); + embassy_time::Timer::after_millis(200).await; + } + } + + embassy_time::Timer::after_millis(1000).await; + + const MESSAGE: &str = "Hello embassy people. Hope you like this LCD demo :} "; loop { - defmt::info!("Writing frame"); - lcd.write_frame(&[0xAAAAAAAA; 16]); + print_message(MESSAGE, &mut lcd, Duration::from_millis(250)).await; + print_message(characters::ALL_CHARS, &mut lcd, Duration::from_millis(500)).await; + } +} + +async fn print_message(message: &str, lcd: &mut Lcd<'_, LCD>, delay: Duration) { + let mut display_buffer = DisplayBuffer::new(); + + let mut char_buffer = [' '; 6]; + for char in message.chars() { + char_buffer.copy_within(1.., 0); + char_buffer[5] = char; + + display_buffer.clear(); + for (i, char) in char_buffer.iter().enumerate() { + display_buffer.write_char(i, *char); + } + display_buffer.write(lcd); + + embassy_time::Timer::after(delay).await; + } +} + +/// Display layout for the U0-DK +mod display_layout { + // Character layout. There are 6 characters, left-to-right + // T + // ───────── + // │ N │ + // │ │ │ │ │ + // TL │ └┐ │ ┌┘ │ TR + // │NW│ │ │NE│ + // │ │ │ + // W─── ───E + // │ │ │ + // │SW│ │ │SE│ + // BL │ ┌┘ │ └┐ │ BR + // │ │ │ │ │ + // │ S │ + // ───────── + // B + + pub const CHAR_N_COM: u8 = 3; + pub const CHAR_N_SEG: [u8; 6] = [39, 37, 35, 48, 26, 33]; + pub const CHAR_NW_COM: u8 = 3; + pub const CHAR_NW_SEG: [u8; 6] = [49, 38, 36, 34, 27, 24]; + pub const CHAR_W_COM: u8 = 0; + pub const CHAR_W_SEG: [u8; 6] = CHAR_NW_SEG; + pub const CHAR_SW_COM: u8 = 2; + pub const CHAR_SW_SEG: [u8; 6] = CHAR_NW_SEG; + pub const CHAR_S_COM: u8 = 2; + pub const CHAR_S_SEG: [u8; 6] = [22, 6, 46, 11, 15, 29]; + pub const CHAR_SE_COM: u8 = 3; + pub const CHAR_SE_SEG: [u8; 6] = CHAR_S_SEG; + pub const CHAR_E_COM: u8 = 0; + pub const CHAR_E_SEG: [u8; 6] = [23, 45, 47, 14, 28, 32]; + pub const CHAR_NE_COM: u8 = 2; + pub const CHAR_NE_SEG: [u8; 6] = CHAR_N_SEG; + pub const CHAR_T_COM: u8 = 1; + pub const CHAR_T_SEG: [u8; 6] = CHAR_N_SEG; + pub const CHAR_TL_COM: u8 = 1; + pub const CHAR_TL_SEG: [u8; 6] = CHAR_NW_SEG; + pub const CHAR_BL_COM: u8 = 0; + pub const CHAR_BL_SEG: [u8; 6] = CHAR_S_SEG; + pub const CHAR_B_COM: u8 = 1; + pub const CHAR_B_SEG: [u8; 6] = CHAR_S_SEG; + pub const CHAR_BR_COM: u8 = 1; + pub const CHAR_BR_SEG: [u8; 6] = CHAR_E_SEG; + pub const CHAR_TR_COM: u8 = 0; + pub const CHAR_TR_SEG: [u8; 6] = CHAR_N_SEG; + + pub const COLON_COM: u8 = 2; + pub const COLON_SEG: [u8; 4] = [23, 45, 47, 14]; + pub const DOT_COM: u8 = 3; + pub const DOT_SEG: [u8; 4] = COLON_SEG; + /// COM + SEG, bar from top to bottom + pub const BAR: [(u8, u8); 4] = [(2, 28), (3, 28), (2, 32), (3, 32)]; +} + +mod characters { + use super::CharSegment::{self, *}; + + pub const CHAR_0: &[CharSegment] = &[T, TL, BL, B, BR, TR, NW, SE]; + pub const CHAR_1: &[CharSegment] = &[NE, TR, BR]; + pub const CHAR_2: &[CharSegment] = &[T, BL, B, TR, E, W]; + pub const CHAR_3: &[CharSegment] = &[T, B, BR, TR, E]; + pub const CHAR_4: &[CharSegment] = &[TL, BR, TR, E, W]; + pub const CHAR_5: &[CharSegment] = &[T, TL, B, BR, E, W]; + pub const CHAR_6: &[CharSegment] = &[T, TL, BL, B, BR, E, W]; + pub const CHAR_7: &[CharSegment] = &[T, NE, S]; + pub const CHAR_8: &[CharSegment] = &[T, TL, BL, B, BR, TR, E, W]; + pub const CHAR_9: &[CharSegment] = &[T, TL, BR, TR, E, W]; + + pub const CHAR_COLON: &[CharSegment] = &[N, S]; + pub const CHAR_SEMICOLON: &[CharSegment] = &[N, SW]; + pub const CHAR_EQUALS: &[CharSegment] = &[E, W, B]; + pub const CHAR_SLASH: &[CharSegment] = &[SW, NE]; + pub const CHAR_BACKSLASH: &[CharSegment] = &[SE, NW]; + pub const CHAR_PLUS: &[CharSegment] = &[N, E, S, W]; + pub const CHAR_STAR: &[CharSegment] = &[NE, N, NW, SE, S, SW]; + pub const CHAR_QUOTE: &[CharSegment] = &[N]; + pub const CHAR_BACKTICK: &[CharSegment] = &[NW]; + pub const CHAR_DASH: &[CharSegment] = &[W, E]; + pub const CHAR_COMMA: &[CharSegment] = &[SW]; + pub const CHAR_DOT: &[CharSegment] = &[S]; + pub const CHAR_CURLYOPEN: &[CharSegment] = &[T, NW, W, SW, B]; + pub const CHAR_CURLYCLOSE: &[CharSegment] = &[T, NE, E, SE, B]; + pub const CHAR_AMPERSAND: &[CharSegment] = &[T, NE, NW, W, BL, B, SE]; + + pub const CHAR_A: &[CharSegment] = &[T, TL, TR, E, W, BL, BR]; + pub const CHAR_B: &[CharSegment] = &[T, TR, BR, B, N, S, E]; + pub const CHAR_C: &[CharSegment] = &[T, TL, BL, B]; + pub const CHAR_D: &[CharSegment] = &[T, TR, BR, B, N, S]; + pub const CHAR_E: &[CharSegment] = &[T, TL, BL, B, W]; + pub const CHAR_F: &[CharSegment] = &[T, TL, BL, W]; + pub const CHAR_G: &[CharSegment] = &[T, TL, BL, B, BR, E]; + pub const CHAR_H: &[CharSegment] = &[TL, BL, E, W, TR, BR]; + pub const CHAR_I: &[CharSegment] = &[T, N, S, B]; + pub const CHAR_J: &[CharSegment] = &[TR, BR, B, BL]; + pub const CHAR_K: &[CharSegment] = &[TL, BL, W, NE, SE]; + pub const CHAR_L: &[CharSegment] = &[TL, BL, B]; + pub const CHAR_M: &[CharSegment] = &[BL, TL, NW, NE, TR, BR]; + pub const CHAR_N: &[CharSegment] = &[BL, TL, NW, SE, BR, TR]; + pub const CHAR_O: &[CharSegment] = &[T, TL, BL, B, BR, TR]; + pub const CHAR_P: &[CharSegment] = &[BL, TL, T, TR, E, W]; + pub const CHAR_Q: &[CharSegment] = &[T, TL, BL, B, BR, TR, SE]; + pub const CHAR_R: &[CharSegment] = &[BL, TL, T, TR, E, W, SE]; + pub const CHAR_S: &[CharSegment] = &[T, NW, E, BR, B]; + pub const CHAR_T: &[CharSegment] = &[T, N, S]; + pub const CHAR_U: &[CharSegment] = &[TL, BL, B, BR, TR]; + pub const CHAR_V: &[CharSegment] = &[TL, BL, SW, NE]; + pub const CHAR_W: &[CharSegment] = &[TL, BL, SW, SE, BR, TR]; + pub const CHAR_X: &[CharSegment] = &[NE, NW, SE, SW]; + pub const CHAR_Y: &[CharSegment] = &[NE, NW, S]; + pub const CHAR_Z: &[CharSegment] = &[T, NE, SW, B]; + + pub const CHAR_UNKNOWN: &[CharSegment] = &[N, NW, W, SW, S, SE, E, NE, T, TL, BL, B, BR, TR]; + + pub const ALL_CHARS: &str = + "0 1 2 3 4 5 6 7 8 9 : ; = / \\ + * ' ` - , . { } & A B C D E F G H I J K L M N O P Q R S T U V W X Y Z � "; + + pub fn get_char_segments(val: char) -> &'static [CharSegment] { + match val { + val if val.is_whitespace() => &[], + + '0' => CHAR_0, + '1' => CHAR_1, + '2' => CHAR_2, + '3' => CHAR_3, + '4' => CHAR_4, + '5' => CHAR_5, + '6' => CHAR_6, + '7' => CHAR_7, + '8' => CHAR_8, + '9' => CHAR_9, + + ':' => CHAR_COLON, + ';' => CHAR_SEMICOLON, + '=' => CHAR_EQUALS, + '/' => CHAR_SLASH, + '\\' => CHAR_BACKSLASH, + '+' => CHAR_PLUS, + '*' => CHAR_STAR, + '\'' => CHAR_QUOTE, + '`' => CHAR_BACKTICK, + '-' => CHAR_DASH, + ',' => CHAR_COMMA, + '.' => CHAR_DOT, + '{' => CHAR_CURLYOPEN, + '}' => CHAR_CURLYCLOSE, + '&' => CHAR_AMPERSAND, - embassy_time::Timer::after_secs(1).await; + 'A' | 'a' => CHAR_A, + 'B' | 'b' => CHAR_B, + 'C' | 'c' => CHAR_C, + 'D' | 'd' => CHAR_D, + 'E' | 'e' => CHAR_E, + 'F' | 'f' => CHAR_F, + 'G' | 'g' => CHAR_G, + 'H' | 'h' => CHAR_H, + 'I' | 'i' => CHAR_I, + 'J' | 'j' => CHAR_J, + 'K' | 'k' => CHAR_K, + 'L' | 'l' => CHAR_L, + 'M' | 'm' => CHAR_M, + 'N' | 'n' => CHAR_N, + 'O' | 'o' => CHAR_O, + 'P' | 'p' => CHAR_P, + 'Q' | 'q' => CHAR_Q, + 'R' | 'r' => CHAR_R, + 'S' | 's' => CHAR_S, + 'T' | 't' => CHAR_T, + 'U' | 'u' => CHAR_U, + 'V' | 'v' => CHAR_V, + 'W' | 'w' => CHAR_W, + 'X' | 'x' => CHAR_X, + 'Y' | 'y' => CHAR_Y, + 'Z' | 'z' => CHAR_Z, - defmt::info!("Writing frame"); - lcd.write_frame(&[!0xAAAAAAAA; 16]); + _ => CHAR_UNKNOWN, + } + } +} + +pub struct DisplayBuffer { + pixels: [u64; 4], +} + +impl DisplayBuffer { + pub const fn new() -> Self { + Self { pixels: [0; 4] } + } + + pub fn clear(&mut self) { + *self = Self::new(); + } + + fn write_char_segment(&mut self, index: usize, value: CharSegment) { + defmt::assert!(index < 6); + let (com, segments) = value.get_com_seg(); + self.pixels[com as usize] |= 1 << segments[index]; + } + + pub fn write_char(&mut self, index: usize, val: char) { + let segments = characters::get_char_segments(val); + + for segment in segments { + self.write_char_segment(index, *segment); + } + } + + pub fn write(&self, lcd: &mut Lcd<'_, LCD>) { + lcd.write_com_segments(0, self.pixels[0]); + lcd.write_com_segments(1, self.pixels[1]); + lcd.write_com_segments(2, self.pixels[2]); + lcd.write_com_segments(3, self.pixels[3]); + lcd.submit_frame(); + } + + pub fn write_colon(&mut self, index: usize) { + defmt::assert!(index < 4); + self.pixels[display_layout::COLON_COM as usize] |= 1 << display_layout::COLON_SEG[index]; + } + + pub fn write_dot(&mut self, index: usize) { + defmt::assert!(index < 4); + self.pixels[display_layout::DOT_COM as usize] |= 1 << display_layout::DOT_SEG[index]; + } + + pub fn write_bar(&mut self, index: usize) { + defmt::assert!(index < 4); + let (bar_com, bar_seg) = display_layout::BAR[index]; + self.pixels[bar_com as usize] |= 1 << bar_seg; + } +} + +#[derive(Debug, Clone, Copy)] +enum CharSegment { + /// North + N, + /// North west + NW, + /// West + W, + /// South west + SW, + /// South + S, + /// South East + SE, + /// East + E, + /// North East + NE, + /// Top + T, + /// Top left + TL, + /// Bottom left + BL, + /// Bottom + B, + /// Bottom right + BR, + /// Top right + TR, +} - embassy_time::Timer::after_secs(1).await; +impl CharSegment { + fn get_com_seg(&self) -> (u8, [u8; 6]) { + match self { + CharSegment::N => (display_layout::CHAR_N_COM, display_layout::CHAR_N_SEG), + CharSegment::NW => (display_layout::CHAR_NW_COM, display_layout::CHAR_NW_SEG), + CharSegment::W => (display_layout::CHAR_W_COM, display_layout::CHAR_W_SEG), + CharSegment::SW => (display_layout::CHAR_SW_COM, display_layout::CHAR_SW_SEG), + CharSegment::S => (display_layout::CHAR_S_COM, display_layout::CHAR_S_SEG), + CharSegment::SE => (display_layout::CHAR_SE_COM, display_layout::CHAR_SE_SEG), + CharSegment::E => (display_layout::CHAR_E_COM, display_layout::CHAR_E_SEG), + CharSegment::NE => (display_layout::CHAR_NE_COM, display_layout::CHAR_NE_SEG), + CharSegment::T => (display_layout::CHAR_T_COM, display_layout::CHAR_T_SEG), + CharSegment::TL => (display_layout::CHAR_TL_COM, display_layout::CHAR_TL_SEG), + CharSegment::BL => (display_layout::CHAR_BL_COM, display_layout::CHAR_BL_SEG), + CharSegment::B => (display_layout::CHAR_B_COM, display_layout::CHAR_B_SEG), + CharSegment::BR => (display_layout::CHAR_BR_COM, display_layout::CHAR_BR_SEG), + CharSegment::TR => (display_layout::CHAR_TR_COM, display_layout::CHAR_TR_SEG), + } } } -- cgit From 1479fbbee76b52e04bf658244fc535e462e17637 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 22 Nov 2025 00:37:19 +0100 Subject: Restructure build script and pin traits a little bit --- examples/stm32u0/src/bin/lcd.rs | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index f401b1dcd..39db5c9c8 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -43,34 +43,34 @@ async fn main(_spawner: Spawner) { config, p.PC3, [ - LcdPin::from(p.PA8), - LcdPin::from(p.PA9), - LcdPin::from(p.PA10), - LcdPin::from(p.PB1), - LcdPin::from(p.PB9), - LcdPin::from(p.PB11), - LcdPin::from(p.PB14), - LcdPin::from(p.PB15), - LcdPin::from(p.PC4), - LcdPin::from(p.PC5), - LcdPin::from(p.PC6), - LcdPin::from(p.PC8), - LcdPin::from(p.PC9), - LcdPin::from(p.PC10), - LcdPin::from(p.PC11), - LcdPin::from(p.PD8), - LcdPin::from(p.PD9), - LcdPin::from(p.PD12), - LcdPin::from(p.PD13), - LcdPin::from(p.PD0), - LcdPin::from(p.PD1), - LcdPin::from(p.PD3), - LcdPin::from(p.PD4), - LcdPin::from(p.PD5), - LcdPin::from(p.PD6), - LcdPin::from(p.PE7), - LcdPin::from(p.PE8), - LcdPin::from(p.PE9), + LcdPin::new_com(p.PA8), + LcdPin::new_com(p.PA9), + LcdPin::new_com(p.PA10), + LcdPin::new_seg(p.PB1), + LcdPin::new_com(p.PB9), + LcdPin::new_seg(p.PB11), + LcdPin::new_seg(p.PB14), + LcdPin::new_seg(p.PB15), + LcdPin::new_seg(p.PC4), + LcdPin::new_seg(p.PC5), + LcdPin::new_seg(p.PC6), + LcdPin::new_seg(p.PC8), + LcdPin::new_seg(p.PC9), + LcdPin::new_seg(p.PC10), + LcdPin::new_seg(p.PC11), + LcdPin::new_seg(p.PD8), + LcdPin::new_seg(p.PD9), + LcdPin::new_seg(p.PD12), + LcdPin::new_seg(p.PD13), + LcdPin::new_seg(p.PD0), + LcdPin::new_seg(p.PD1), + LcdPin::new_seg(p.PD3), + LcdPin::new_seg(p.PD4), + LcdPin::new_seg(p.PD5), + LcdPin::new_seg(p.PD6), + LcdPin::new_seg(p.PE7), + LcdPin::new_seg(p.PE8), + LcdPin::new_seg(p.PE9), ], ); -- cgit From 11a5cd2c753fc39ec9fcf22c805ed7769ed6e0ec Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 22 Nov 2025 00:40:29 +0100 Subject: fmt + clippy + changelog --- examples/stm32u0/src/bin/lcd.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index 39db5c9c8..c3f489ea9 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -351,6 +351,12 @@ impl DisplayBuffer { } } +impl Default for DisplayBuffer { + fn default() -> Self { + Self::new() + } +} + #[derive(Debug, Clone, Copy)] enum CharSegment { /// North -- cgit From 8c9a6521e813f7ab9cfe787bd46a583c8173bac2 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 22 Nov 2025 00:46:18 +0100 Subject: Minimize cargo toml + revert probe-rs config --- examples/stm32u0/.cargo/config.toml | 4 ++-- examples/stm32u0/Cargo.toml | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml index 06eed6c8f..e9212cacb 100644 --- a/examples/stm32u0/.cargo/config.toml +++ b/examples/stm32u0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace stm32u083rctx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip stm32u083rctx --catch-hardfault" +# replace stm32u083mctx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip stm32u083mctx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 42d349cda..8cc894cb3 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] -# Change stm32u083rc to your chip name, if necessary. +# Change stm32u083mc to your chip name, if necessary. embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083mc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } @@ -19,9 +19,7 @@ defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -embedded-hal = "0.2.6" panic-probe = { version = "1.0.0", features = ["print-defmt"] } -heapless = { version = "0.8", default-features = false } micromath = "2.0.0" chrono = { version = "0.4.38", default-features = false } -- cgit From 992ab2ec63d4ca41045d52f50be487a001023396 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 22 Nov 2025 01:47:54 +0100 Subject: Add L0 family --- examples/stm32u0/src/bin/lcd.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index c3f489ea9..6e4378074 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -3,11 +3,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - lcd::{Bias, Config, Duty, Lcd, LcdPin}, - peripherals::LCD, - time::Hertz, -}; +use embassy_stm32::lcd::{Bias, Config, Duty, Lcd, LcdPin}; +use embassy_stm32::peripherals::LCD; +use embassy_stm32::time::Hertz; use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; -- cgit From f686ce9ebb19081e12eae203e92273f8ecb6eaf2 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 22 Nov 2025 15:25:54 +0100 Subject: Impl blink --- examples/stm32u0/src/bin/lcd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs index 6e4378074..2b34d4ef1 100644 --- a/examples/stm32u0/src/bin/lcd.rs +++ b/examples/stm32u0/src/bin/lcd.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::lcd::{Bias, Config, Duty, Lcd, LcdPin}; +use embassy_stm32::lcd::{Bias, BlinkFreq, BlinkSelector, Config, Duty, Lcd, LcdPin}; use embassy_stm32::peripherals::LCD; use embassy_stm32::time::Hertz; use embassy_time::Duration; @@ -72,6 +72,7 @@ async fn main(_spawner: Spawner) { ], ); + lcd.set_blink(BlinkSelector::All, BlinkFreq::Hz4); { let mut buffer = DisplayBuffer::new(); for i in 0..4 { @@ -91,6 +92,8 @@ async fn main(_spawner: Spawner) { embassy_time::Timer::after_millis(1000).await; + lcd.set_blink(BlinkSelector::None, BlinkFreq::Hz4); + const MESSAGE: &str = "Hello embassy people. Hope you like this LCD demo :} "; loop { print_message(MESSAGE, &mut lcd, Duration::from_millis(250)).await; -- cgit