embassy-rs/embassy · error

Lcd clock error

Error message

Lcd clock error

What it means

After scanning prescaler (PS) and divider values, the driver could not find a combination that brings the LCD clock into the target frame-rate range: either no match was found (best_fps_match == u32::MAX) or the required prescaler exceeds the 4-bit field (>0xF). The requested frame rate is unreachable from the given RTC clock, so the driver panics.

Solutions

  1. Lower the requested fps (or widen the fps range) in the LcdConfig so a valid PS/div exists.
  2. Change the RTC/LCD clock source or frequency so the target fps is reachable within PS<=0xF and div<=3.
  3. Keep the RTC clock near 32.768 kHz, the frequency the LCD timing math is designed around.

Example fix

// before
let config = LcdConfig::default().fps(120); // unreachable with 32.768 kHz LSE
// after
let config = LcdConfig::default().fps(30); // reachable PS/div combination
Defensive patterns

Strategy: validation

Validate before calling

// sanity-check the target fps against a 32.768 kHz LCD clock before Lcd::new
fn fps_reachable(rtc_hz: u32, fps: u32, duty_div: u32) -> bool {
    // max division is ps(0xF -> 2^16) * div(3) * duty; fps * divs must stay under rtc_hz
    fps * duty_div * (1 << 16) * 3 >= rtc_hz / 4 && fps <= rtc_hz / (duty_div * 2)
}

Prevention

When it happens

Trigger: Calling Lcd::new() with a config whose target fps is impossible for the configured rtc clock and duty divider; an RTC clock so high or low that even PS=0xF/div=15 cannot hit the fps window.

Common situations: Unusual LSE/LSI frequencies combined with aggressive fps targets in the config; copying a config from another board with a different RTC clock; duty setting change (e.g. Duty::Quarter) shifting the divider math out of range.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/1c1520f4a8e5c458. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/lcd.rs:242

                continue;
            }

            if fps < best_fps_match {
                ps = trial_ps;
                div = trial_div;
                best_fps_match = fps;
            }
        }

        let ck_div = lcd_clk.0 / ((1 << ps) * (div + 16));

        trace!(
            "lcd_clk: {}, fps: {}, ps: {}, div: {}, ck_div: {}",
            lcd_clk, best_fps_match, ps, div, ck_div
        );

        if best_fps_match == u32::MAX || ps > 0xF {
            panic!("Lcd clock error");
        }

        // Set the frame control
        T::regs().fcr().modify(|w| {
            w.set_ps(ps as u8);
            w.set_div(div as u8);
            w.set_cc(0b100); // Init in the middle-ish
            w.set_dead(0b000);
            w.set_pon(config.drive as u8 & 0x07);
            w.set_hd((config.drive as u8 & !0x07) != 0);
        });

        // Wait for the frame control to synchronize
        while !T::regs().sr().read().fcrsf() {}

        // Set the control register values
        T::regs().cr().modify(|w| {
            #[cfg(lcd_v2)]

View on GitHub (pinned to 463a07b963)