diff options
| author | Dion Dokter <[email protected]> | 2025-11-22 15:25:54 +0100 |
|---|---|---|
| committer | Dion Dokter <[email protected]> | 2025-11-22 15:25:54 +0100 |
| commit | f686ce9ebb19081e12eae203e92273f8ecb6eaf2 (patch) | |
| tree | 1a139c7265d29388c621409b081d8aed0ebc7735 /embassy-stm32/src/lcd.rs | |
| parent | 2649ba2a49fad0c04e3323d17373707f2eb03097 (diff) | |
Impl blink
Diffstat (limited to 'embassy-stm32/src/lcd.rs')
| -rw-r--r-- | embassy-stm32/src/lcd.rs | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs index 348865fbd..ea29f1398 100644 --- a/embassy-stm32/src/lcd.rs +++ b/embassy-stm32/src/lcd.rs | |||
| @@ -152,6 +152,7 @@ pub enum Drive { | |||
| 152 | pub struct Lcd<'d, T: Instance> { | 152 | pub struct Lcd<'d, T: Instance> { |
| 153 | _peri: PhantomData<&'d mut T>, | 153 | _peri: PhantomData<&'d mut T>, |
| 154 | duty: Duty, | 154 | duty: Duty, |
| 155 | ck_div: u32, | ||
| 155 | } | 156 | } |
| 156 | 157 | ||
| 157 | impl<'d, T: Instance> Lcd<'d, T> { | 158 | impl<'d, T: Instance> Lcd<'d, T> { |
| @@ -227,9 +228,11 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 227 | } | 228 | } |
| 228 | } | 229 | } |
| 229 | 230 | ||
| 231 | let ck_div = lcd_clk.0 / ((1 << ps) * (div + 16)); | ||
| 232 | |||
| 230 | trace!( | 233 | trace!( |
| 231 | "lcd_clk: {}, fps: {}, ps: {}, div: {}", | 234 | "lcd_clk: {}, fps: {}, ps: {}, div: {}, ck_div: {}", |
| 232 | lcd_clk, best_fps_match, ps, div | 235 | lcd_clk, best_fps_match, ps, div, ck_div |
| 233 | ); | 236 | ); |
| 234 | 237 | ||
| 235 | if best_fps_match == u32::MAX || ps > 0xF { | 238 | if best_fps_match == u32::MAX || ps > 0xF { |
| @@ -271,6 +274,7 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 271 | Self { | 274 | Self { |
| 272 | _peri: PhantomData, | 275 | _peri: PhantomData, |
| 273 | duty: config.duty, | 276 | duty: config.duty, |
| 277 | ck_div, | ||
| 274 | } | 278 | } |
| 275 | } | 279 | } |
| 276 | 280 | ||
| @@ -371,6 +375,42 @@ impl<'d, T: Instance> Lcd<'d, T> { | |||
| 371 | pub fn num_com_pins(&self) -> u8 { | 375 | pub fn num_com_pins(&self) -> u8 { |
| 372 | self.duty.num_com_pins() | 376 | self.duty.num_com_pins() |
| 373 | } | 377 | } |
| 378 | |||
| 379 | /// Set the blink behavior on some pixels. | ||
| 380 | /// | ||
| 381 | /// The blink frequency is an approximation. It's divided from the clock selected by the FPS. | ||
| 382 | /// Play with the FPS value if you want the blink frequency to be more accurate. | ||
| 383 | /// | ||
| 384 | /// If a blink frequency cannot be attained, this function will panic. | ||
| 385 | pub fn set_blink(&mut self, selector: BlinkSelector, freq: BlinkFreq) { | ||
| 386 | // Freq * 100 to be able to do integer math | ||
| 387 | let scaled_blink_freq = match freq { | ||
| 388 | BlinkFreq::Hz0_25 => 25, | ||
| 389 | BlinkFreq::Hz0_5 => 50, | ||
| 390 | BlinkFreq::Hz1 => 100, | ||
| 391 | BlinkFreq::Hz2 => 200, | ||
| 392 | BlinkFreq::Hz4 => 400, | ||
| 393 | }; | ||
| 394 | |||
| 395 | let desired_divider = self.ck_div * 100 / scaled_blink_freq; | ||
| 396 | let target_divider = desired_divider.next_power_of_two(); | ||
| 397 | let power_divisions = target_divider.trailing_zeros(); | ||
| 398 | |||
| 399 | trace!( | ||
| 400 | "Setting LCD blink frequency -> desired_divider: {}, target_divider: {}", | ||
| 401 | desired_divider, target_divider | ||
| 402 | ); | ||
| 403 | |||
| 404 | assert!( | ||
| 405 | (8..=1024).contains(&target_divider), | ||
| 406 | "LCD blink frequency cannot be attained" | ||
| 407 | ); | ||
| 408 | |||
| 409 | T::regs().fcr().modify(|reg| { | ||
| 410 | reg.set_blinkf((power_divisions - 3) as u8); | ||
| 411 | reg.set_blink(selector as u8); | ||
| 412 | }) | ||
| 413 | } | ||
| 374 | } | 414 | } |
| 375 | 415 | ||
| 376 | impl<'d, T: Instance> Drop for Lcd<'d, T> { | 416 | impl<'d, T: Instance> Drop for Lcd<'d, T> { |
| @@ -381,6 +421,35 @@ impl<'d, T: Instance> Drop for Lcd<'d, T> { | |||
| 381 | } | 421 | } |
| 382 | } | 422 | } |
| 383 | 423 | ||
| 424 | /// Blink frequency | ||
| 425 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 426 | pub enum BlinkFreq { | ||
| 427 | /// 0.25 hz | ||
| 428 | Hz0_25, | ||
| 429 | /// 0.5 hz | ||
| 430 | Hz0_5, | ||
| 431 | /// 1 hz | ||
| 432 | Hz1, | ||
| 433 | /// 2 hz | ||
| 434 | Hz2, | ||
| 435 | /// 4 hz | ||
| 436 | Hz4, | ||
| 437 | } | ||
| 438 | |||
| 439 | /// Blink pixel selector | ||
| 440 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 441 | #[repr(u8)] | ||
| 442 | pub enum BlinkSelector { | ||
| 443 | /// No pixels blink | ||
| 444 | None = 0b00, | ||
| 445 | /// The SEG0, COM0 pixel blinks if the pixel is set | ||
| 446 | Seg0Com0 = 0b01, | ||
| 447 | /// The SEG0 pixel of all COMs blinks if the pixel is set | ||
| 448 | Seg0ComAll = 0b10, | ||
| 449 | /// All pixels blink if the pixel is set | ||
| 450 | All = 0b11, | ||
| 451 | } | ||
| 452 | |||
| 384 | /// A type-erased pin that can be configured as an LCD pin. | 453 | /// A type-erased pin that can be configured as an LCD pin. |
| 385 | /// This is used for passing pins to the new function in the array. | 454 | /// This is used for passing pins to the new function in the array. |
| 386 | pub struct LcdPin<'d, T: Instance> { | 455 | pub struct LcdPin<'d, T: Instance> { |
