{"record":{"id":"1c1520f4a8e5c458","repo":"embassy-rs/embassy","slug":"lcd-clock-error","errorCode":null,"errorMessage":"Lcd clock error","messagePattern":"Lcd clock error","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/lcd.rs","lineNumber":242,"sourceCode":"                continue;\n            }\n\n            if fps < best_fps_match {\n                ps = trial_ps;\n                div = trial_div;\n                best_fps_match = fps;\n            }\n        }\n\n        let ck_div = lcd_clk.0 / ((1 << ps) * (div + 16));\n\n        trace!(\n            \"lcd_clk: {}, fps: {}, ps: {}, div: {}, ck_div: {}\",\n            lcd_clk, best_fps_match, ps, div, ck_div\n        );\n\n        if best_fps_match == u32::MAX || ps > 0xF {\n            panic!(\"Lcd clock error\");\n        }\n\n        // Set the frame control\n        T::regs().fcr().modify(|w| {\n            w.set_ps(ps as u8);\n            w.set_div(div as u8);\n            w.set_cc(0b100); // Init in the middle-ish\n            w.set_dead(0b000);\n            w.set_pon(config.drive as u8 & 0x07);\n            w.set_hd((config.drive as u8 & !0x07) != 0);\n        });\n\n        // Wait for the frame control to synchronize\n        while !T::regs().sr().read().fcrsf() {}\n\n        // Set the control register values\n        T::regs().cr().modify(|w| {\n            #[cfg(lcd_v2)]","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/lcd.rs#L224-L260","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Lower the requested fps (or widen the fps range) in the LcdConfig so a valid PS/div exists.","Change the RTC/LCD clock source or frequency so the target fps is reachable within PS<=0xF and div<=3.","Keep the RTC clock near 32.768 kHz, the frequency the LCD timing math is designed around."],"exampleFix":"// before\nlet config = LcdConfig::default().fps(120); // unreachable with 32.768 kHz LSE\n// after\nlet config = LcdConfig::default().fps(30); // reachable PS/div combination","handlingStrategy":"validation","validationCode":"// sanity-check the target fps against a 32.768 kHz LCD clock before Lcd::new\nfn fps_reachable(rtc_hz: u32, fps: u32, duty_div: u32) -> bool {\n    // max division is ps(0xF -> 2^16) * div(3) * duty; fps * divs must stay under rtc_hz\n    fps * duty_div * (1 << 16) * 3 >= rtc_hz / 4 && fps <= rtc_hz / (duty_div * 2)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the LCD clock near 32.768 kHz; use LSE for the RTC/LCD domain.","Choose fps values in the range typical for segment LCDs (30-60 Hz).","Verify the duty setting matches the panel; changing duty shifts the divider math."],"tags":["rust","embedded","stm32","lcd","clock-config"],"backgroundTag":"invalid-config-value","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}