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 --- embassy-stm32/src/lcd.rs | 58 +++++++++++++++++++------------------ examples/stm32u0/Cargo.toml | 2 +- examples/stm32u0/src/bin/lcd.rs | 63 +++++++++++++++++++++-------------------- 3 files changed, 64 insertions(+), 59 deletions(-) diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs index 15d3e8fbc..7c1877a38 100644 --- a/embassy-stm32/src/lcd.rs +++ b/embassy-stm32/src/lcd.rs @@ -1,12 +1,12 @@ //! LCD use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; -use crate::gpio::{AFType, AnyPin, SealedPin}; +use crate::gpio::{AfType, AnyPin, SealedPin}; +use crate::peripherals; use crate::rcc::{self, RccPeripheral}; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; #[non_exhaustive] #[derive(Debug, Clone, Copy)] @@ -123,21 +123,24 @@ pub struct Lcd<'d, T: Instance> { impl<'d, T: Instance> Lcd<'d, T> { /// Initialize the lcd driver pub fn new( - _peri: impl Peripheral

+ 'd, + _peripheral: Peri<'d, T>, config: Config, - vlcd_pin: impl Peripheral

> + 'd, + vlcd_pin: Peri<'_, impl VlcdPin>, pins: [LcdPin<'d, T>; N], ) -> Self { rcc::enable_and_reset::(); - into_ref!(vlcd_pin); - vlcd_pin.set_as_af(vlcd_pin.af_num(), AFType::OutputPushPull); - vlcd_pin.set_speed(crate::gpio::Speed::VeryHigh); + vlcd_pin.set_as_af( + vlcd_pin.af_num(), + AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh), + ); // Set the pins for pin in pins { - pin.pin.set_as_af(pin.af_num, AFType::OutputPushPull); - pin.pin.set_speed(crate::gpio::Speed::VeryHigh); + pin.pin.set_as_af( + pin.af_num, + AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh), + ); } // Initialize the display ram to 0 @@ -147,7 +150,7 @@ impl<'d, T: Instance> Lcd<'d, T> { } // Calculate the clock dividers - let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc }) else { + let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc.to_hertz() }) else { panic!("The LCD driver needs the RTC/LCD clock to be running"); }; let duty_divider = match config.duty { @@ -183,10 +186,7 @@ impl<'d, T: Instance> Lcd<'d, T> { trace!( "lcd_clk: {}, fps: {}, ps: {}, div: {}", - lcd_clk, - best_fps_match, - ps, - div + lcd_clk, best_fps_match, ps, div ); if best_fps_match == u32::MAX || ps > 0xF { @@ -228,7 +228,7 @@ impl<'d, T: Instance> Lcd<'d, T> { } /// Change the contrast by changing the voltage being used. - /// + /// /// This from low at 0 to high at 7. pub fn set_contrast_control(&mut self, value: u8) { T::regs().fcr().modify(|w| w.set_cc(value)); @@ -236,17 +236,19 @@ impl<'d, T: Instance> Lcd<'d, T> { /// Change the contrast by introducing a deadtime to the signals /// where the voltages are held at 0V. - /// + /// /// This from no dead time at 0 to high dead time at 7. pub fn set_dead_time(&mut self, value: u8) { - T::regs().fcr().modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value)); + T::regs() + .fcr() + .modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value)); } /// Write frame data to the peripheral. - /// + /// /// What each bit means depends on the exact microcontroller you use, /// which pins are connected to your LCD and also the LCD layout itself. - /// + /// /// This function blocks until the last update display request has been processed. pub fn write_frame(&mut self, data: &[u32; 16]) { while T::regs().sr().read().udr() {} @@ -265,37 +267,37 @@ impl<'d, T: Instance> Lcd<'d, T> { impl<'d, T: Instance> Drop for Lcd<'d, T> { fn drop(&mut self) { + // Disable the lcd + T::regs().cr().modify(|w| w.set_lcden(false)); rcc::disable::(); } } pub struct LcdPin<'d, T: Instance> { - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, af_num: u8, _phantom: PhantomData, } -impl<'d, T: Instance, Pin: Peripheral> + 'd> From for LcdPin<'d, T> { - fn from(value: Pin) -> Self { +impl<'d, T: Instance, Pin: SegComPin> From> for LcdPin<'d, T> { + fn from(value: Peri<'d, Pin>) -> Self { Self::new(value) } } impl<'d, T: Instance> LcdPin<'d, T> { - pub fn new(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); - + pub fn new(pin: Peri<'d, impl SegComPin>) -> Self { let af = pin.af_num(); Self { - pin: pin.map_into(), + pin: pin.into(), af_num: af, _phantom: PhantomData, } } } -trait SealedInstance: crate::rcc::SealedRccPeripheral { +trait SealedInstance: crate::rcc::SealedRccPeripheral + PeripheralType { fn regs() -> crate::pac::lcd::Lcd; } 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