diff options
| author | Dion Dokter <[email protected]> | 2025-11-20 14:16:43 +0100 |
|---|---|---|
| committer | Dion Dokter <[email protected]> | 2025-11-20 14:16:43 +0100 |
| commit | d111eceb4ba0094d34f58a4695bb3d43d188e591 (patch) | |
| tree | 75f9824731af674208d357c01e4208804cec3ec6 | |
| parent | 4f2c36e447455e8d33607d586859d3d075cabf1d (diff) | |
Update LCD to modern embassy
| -rw-r--r-- | embassy-stm32/src/lcd.rs | 58 | ||||
| -rw-r--r-- | examples/stm32u0/Cargo.toml | 2 | ||||
| -rw-r--r-- | 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 @@ | |||
| 1 | //! LCD | 1 | //! LCD |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | 3 | ||
| 4 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 4 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 5 | 5 | ||
| 6 | use crate::gpio::{AFType, AnyPin, SealedPin}; | 6 | use crate::gpio::{AfType, AnyPin, SealedPin}; |
| 7 | use crate::peripherals; | ||
| 7 | use crate::rcc::{self, RccPeripheral}; | 8 | use crate::rcc::{self, RccPeripheral}; |
| 8 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 9 | use crate::{peripherals, Peripheral}; | ||
| 10 | 10 | ||
| 11 | #[non_exhaustive] | 11 | #[non_exhaustive] |
| 12 | #[derive(Debug, Clone, Copy)] | 12 | #[derive(Debug, Clone, Copy)] |
| @@ -123,21 +123,24 @@ pub struct Lcd<'d, T: Instance> { | |||
| 123 | impl<'d, T: Instance> Lcd<'d, T> { | 123 | impl<'d, T: Instance> Lcd<'d, T> { |
| 124 | /// Initialize the lcd driver | 124 | /// Initialize the lcd driver |
| 125 | pub fn new<const N: usize>( | 125 | pub fn new<const N: usize>( |
| 126 | _peri: impl Peripheral<P = T> + 'd, | 126 | _peripheral: Peri<'d, T>, |
| 127 | config: Config, | 127 | config: Config, |
| 128 | vlcd_pin: impl Peripheral<P = impl VlcdPin<T>> + 'd, | 128 | vlcd_pin: Peri<'_, impl VlcdPin<T>>, |
| 129 | pins: [LcdPin<'d, T>; N], | 129 | pins: [LcdPin<'d, T>; N], |
| 130 | ) -> Self { | 130 | ) -> Self { |
| 131 | rcc::enable_and_reset::<T>(); | 131 | rcc::enable_and_reset::<T>(); |
| 132 | 132 | ||
| 133 | into_ref!(vlcd_pin); | 133 | vlcd_pin.set_as_af( |
| 134 | vlcd_pin.set_as_af(vlcd_pin.af_num(), AFType::OutputPushPull); | 134 | vlcd_pin.af_num(), |
| 135 | vlcd_pin.set_speed(crate::gpio::Speed::VeryHigh); | 135 | AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh), |
| 136 | ); | ||
| 136 | 137 | ||
| 137 | // Set the pins | 138 | // Set the pins |
| 138 | for pin in pins { | 139 | for pin in pins { |
| 139 | pin.pin.set_as_af(pin.af_num, AFType::OutputPushPull); | 140 | pin.pin.set_as_af( |
| 140 | pin.pin.set_speed(crate::gpio::Speed::VeryHigh); | 141 | pin.af_num, |
| 142 | AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh), | ||
| 143 | ); | ||
| 141 | } | 144 | } |
| 142 | 145 | ||
| 143 | // Initialize the display ram to 0 | 146 | // Initialize the display ram to 0 |
| @@ -147,7 +150,7 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 147 | } | 150 | } |
| 148 | 151 | ||
| 149 | // Calculate the clock dividers | 152 | // Calculate the clock dividers |
| 150 | let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc }) else { | 153 | let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc.to_hertz() }) else { |
| 151 | panic!("The LCD driver needs the RTC/LCD clock to be running"); | 154 | panic!("The LCD driver needs the RTC/LCD clock to be running"); |
| 152 | }; | 155 | }; |
| 153 | let duty_divider = match config.duty { | 156 | let duty_divider = match config.duty { |
| @@ -183,10 +186,7 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 183 | 186 | ||
| 184 | trace!( | 187 | trace!( |
| 185 | "lcd_clk: {}, fps: {}, ps: {}, div: {}", | 188 | "lcd_clk: {}, fps: {}, ps: {}, div: {}", |
| 186 | lcd_clk, | 189 | lcd_clk, best_fps_match, ps, div |
| 187 | best_fps_match, | ||
| 188 | ps, | ||
| 189 | div | ||
| 190 | ); | 190 | ); |
| 191 | 191 | ||
| 192 | if best_fps_match == u32::MAX || ps > 0xF { | 192 | if best_fps_match == u32::MAX || ps > 0xF { |
| @@ -228,7 +228,7 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | /// Change the contrast by changing the voltage being used. | 230 | /// Change the contrast by changing the voltage being used. |
| 231 | /// | 231 | /// |
| 232 | /// This from low at 0 to high at 7. | 232 | /// This from low at 0 to high at 7. |
| 233 | pub fn set_contrast_control(&mut self, value: u8) { | 233 | pub fn set_contrast_control(&mut self, value: u8) { |
| 234 | T::regs().fcr().modify(|w| w.set_cc(value)); | 234 | T::regs().fcr().modify(|w| w.set_cc(value)); |
| @@ -236,17 +236,19 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 236 | 236 | ||
| 237 | /// Change the contrast by introducing a deadtime to the signals | 237 | /// Change the contrast by introducing a deadtime to the signals |
| 238 | /// where the voltages are held at 0V. | 238 | /// where the voltages are held at 0V. |
| 239 | /// | 239 | /// |
| 240 | /// This from no dead time at 0 to high dead time at 7. | 240 | /// This from no dead time at 0 to high dead time at 7. |
| 241 | pub fn set_dead_time(&mut self, value: u8) { | 241 | pub fn set_dead_time(&mut self, value: u8) { |
| 242 | T::regs().fcr().modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value)); | 242 | T::regs() |
| 243 | .fcr() | ||
| 244 | .modify(|w: &mut stm32_metapac::lcd::regs::Fcr| w.set_dead(value)); | ||
| 243 | } | 245 | } |
| 244 | 246 | ||
| 245 | /// Write frame data to the peripheral. | 247 | /// Write frame data to the peripheral. |
| 246 | /// | 248 | /// |
| 247 | /// What each bit means depends on the exact microcontroller you use, | 249 | /// What each bit means depends on the exact microcontroller you use, |
| 248 | /// which pins are connected to your LCD and also the LCD layout itself. | 250 | /// which pins are connected to your LCD and also the LCD layout itself. |
| 249 | /// | 251 | /// |
| 250 | /// This function blocks until the last update display request has been processed. | 252 | /// This function blocks until the last update display request has been processed. |
| 251 | pub fn write_frame(&mut self, data: &[u32; 16]) { | 253 | pub fn write_frame(&mut self, data: &[u32; 16]) { |
| 252 | while T::regs().sr().read().udr() {} | 254 | while T::regs().sr().read().udr() {} |
| @@ -265,37 +267,37 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 265 | 267 | ||
| 266 | impl<'d, T: Instance> Drop for Lcd<'d, T> { | 268 | impl<'d, T: Instance> Drop for Lcd<'d, T> { |
| 267 | fn drop(&mut self) { | 269 | fn drop(&mut self) { |
| 270 | // Disable the lcd | ||
| 271 | T::regs().cr().modify(|w| w.set_lcden(false)); | ||
| 268 | rcc::disable::<T>(); | 272 | rcc::disable::<T>(); |
| 269 | } | 273 | } |
| 270 | } | 274 | } |
| 271 | 275 | ||
| 272 | pub struct LcdPin<'d, T: Instance> { | 276 | pub struct LcdPin<'d, T: Instance> { |
| 273 | pin: PeripheralRef<'d, AnyPin>, | 277 | pin: Peri<'d, AnyPin>, |
| 274 | af_num: u8, | 278 | af_num: u8, |
| 275 | _phantom: PhantomData<T>, | 279 | _phantom: PhantomData<T>, |
| 276 | } | 280 | } |
| 277 | 281 | ||
| 278 | impl<'d, T: Instance, Pin: Peripheral<P: SegComPin<T>> + 'd> From<Pin> for LcdPin<'d, T> { | 282 | impl<'d, T: Instance, Pin: SegComPin<T>> From<Peri<'d, Pin>> for LcdPin<'d, T> { |
| 279 | fn from(value: Pin) -> Self { | 283 | fn from(value: Peri<'d, Pin>) -> Self { |
| 280 | Self::new(value) | 284 | Self::new(value) |
| 281 | } | 285 | } |
| 282 | } | 286 | } |
| 283 | 287 | ||
| 284 | impl<'d, T: Instance> LcdPin<'d, T> { | 288 | impl<'d, T: Instance> LcdPin<'d, T> { |
| 285 | pub fn new(pin: impl Peripheral<P = impl SegComPin<T>> + 'd) -> Self { | 289 | pub fn new(pin: Peri<'d, impl SegComPin<T>>) -> Self { |
| 286 | into_ref!(pin); | ||
| 287 | |||
| 288 | let af = pin.af_num(); | 290 | let af = pin.af_num(); |
| 289 | 291 | ||
| 290 | Self { | 292 | Self { |
| 291 | pin: pin.map_into(), | 293 | pin: pin.into(), |
| 292 | af_num: af, | 294 | af_num: af, |
| 293 | _phantom: PhantomData, | 295 | _phantom: PhantomData, |
| 294 | } | 296 | } |
| 295 | } | 297 | } |
| 296 | } | 298 | } |
| 297 | 299 | ||
| 298 | trait SealedInstance: crate::rcc::SealedRccPeripheral { | 300 | trait SealedInstance: crate::rcc::SealedRccPeripheral + PeripheralType { |
| 299 | fn regs() -> crate::pac::lcd::Lcd; | 301 | fn regs() -> crate::pac::lcd::Lcd; |
| 300 | } | 302 | } |
| 301 | 303 | ||
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 | |||
| 7 | 7 | ||
| 8 | [dependencies] | 8 | [dependencies] |
| 9 | # Change stm32u083rc to your chip name, if necessary. | 9 | # Change stm32u083rc to your chip name, if necessary. |
| 10 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } | 10 | embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083mc", "memory-x", "unstable-pac", "exti", "chrono"] } |
| 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } | 12 | embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 13 | embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | 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 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::{lcd::{Bias, Config, Duty, Lcd, VoltageSource}, time::Hertz}; | 6 | use embassy_stm32::{ |
| 7 | lcd::{Bias, Config, Duty, Lcd, LcdPin}, | ||
| 8 | time::Hertz, | ||
| 9 | }; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 8 | 11 | ||
| 9 | #[embassy_executor::main] | 12 | #[embassy_executor::main] |
| @@ -31,41 +34,41 @@ async fn main(_spawner: Spawner) { | |||
| 31 | let mut config = Config::default(); | 34 | let mut config = Config::default(); |
| 32 | config.bias = Bias::Third; | 35 | config.bias = Bias::Third; |
| 33 | config.duty = Duty::Quarter; | 36 | config.duty = Duty::Quarter; |
| 34 | config.target_fps = Hertz(60); | 37 | config.target_fps = Hertz(100); |
| 35 | 38 | ||
| 36 | let mut lcd = Lcd::new( | 39 | let mut lcd = Lcd::new( |
| 37 | p.LCD, | 40 | p.LCD, |
| 38 | config, | 41 | config, |
| 39 | p.PC3, | 42 | p.PC3, |
| 40 | [ | 43 | [ |
| 41 | p.PA8.into(), | 44 | LcdPin::from(p.PA8), |
| 42 | p.PA9.into(), | 45 | LcdPin::from(p.PA9), |
| 43 | p.PA10.into(), | 46 | LcdPin::from(p.PA10), |
| 44 | p.PB1.into(), | 47 | LcdPin::from(p.PB1), |
| 45 | p.PB9.into(), | 48 | LcdPin::from(p.PB9), |
| 46 | p.PB11.into(), | 49 | LcdPin::from(p.PB11), |
| 47 | p.PB14.into(), | 50 | LcdPin::from(p.PB14), |
| 48 | p.PB15.into(), | 51 | LcdPin::from(p.PB15), |
| 49 | p.PC4.into(), | 52 | LcdPin::from(p.PC4), |
| 50 | p.PC5.into(), | 53 | LcdPin::from(p.PC5), |
| 51 | p.PC6.into(), | 54 | LcdPin::from(p.PC6), |
| 52 | p.PC8.into(), | 55 | LcdPin::from(p.PC8), |
| 53 | p.PC9.into(), | 56 | LcdPin::from(p.PC9), |
| 54 | p.PC10.into(), | 57 | LcdPin::from(p.PC10), |
| 55 | p.PC11.into(), | 58 | LcdPin::from(p.PC11), |
| 56 | p.PD8.into(), | 59 | LcdPin::from(p.PD8), |
| 57 | p.PD9.into(), | 60 | LcdPin::from(p.PD9), |
| 58 | p.PD12.into(), | 61 | LcdPin::from(p.PD12), |
| 59 | p.PD13.into(), | 62 | LcdPin::from(p.PD13), |
| 60 | p.PD0.into(), | 63 | LcdPin::from(p.PD0), |
| 61 | p.PD1.into(), | 64 | LcdPin::from(p.PD1), |
| 62 | p.PD3.into(), | 65 | LcdPin::from(p.PD3), |
| 63 | p.PD4.into(), | 66 | LcdPin::from(p.PD4), |
| 64 | p.PD5.into(), | 67 | LcdPin::from(p.PD5), |
| 65 | p.PD6.into(), | 68 | LcdPin::from(p.PD6), |
| 66 | p.PE7.into(), | 69 | LcdPin::from(p.PE7), |
| 67 | p.PE8.into(), | 70 | LcdPin::from(p.PE8), |
| 68 | p.PE9.into(), | 71 | LcdPin::from(p.PE9), |
| 69 | ], | 72 | ], |
| 70 | ); | 73 | ); |
| 71 | 74 | ||
