embassy-rs/embassy · error
The LCD driver needs the RTC/LCD clock to be running
Error message
The LCD driver needs the RTC/LCD clock to be running
What it means
The LCD controller is clocked from the RTC/LCD clock domain. During driver construction the code reads the currently configured RTC frequency via rcc::get_freqs(); if it is None the driver cannot compute the prescaler/divider, so it panics instead of producing garbage timing.
Solutions
- Enable and configure the RTC/LCD clock source (LSE, LSI or HSE/32) in the RCC config before constructing the LCD driver.
- Verify rcc::get_freqs().rtc is Some(hz) after your clock setup, then create the Lcd driver.
- If LSE is used, account for its startup delay before initializing the LCD.
Example fix
// before let mut lcd = Lcd::new(p.LCD, p.RTC, config); // rtc clock not configured // after let rtc = Rtc::new(p.RTC, RtcConfig::default()); // starts LSE/RTC clock let mut lcd = Lcd::new(p.LCD, p.RTC, config);
Defensive patterns
Strategy: validation
Validate before calling
// assert RTC clock is configured before LCD init let freqs = embassy_stm32::rcc::get_freqs(); assert!(freqs.rtc.to_hertz().is_some(), "RTC/LCD clock must run before Lcd::new");
Try / catch
// Not catchable in idiomatic embedded Rust; ensure init order: let rtc = Rtc::new(p.RTC, RtcConfig::default()); let lcd = Lcd::new(p.LCD, p.RTC, config);
Prevention
- Always bring up the RTC/LCD clock source before peripheral drivers that consume it.
- Add a board-init checklist covering clock domains (RCC -> RTC -> LCD).
- Debug-print rcc::get_freqs().rtc during bring-up to confirm it is Some.
When it happens
Trigger: Instantiating Lcd::new() before the RTC peripheral (and its LCD clock source, e.g. LSE/LSI) has been enabled and configured in the RCC setup.
Common situations: Forgetting to call the rtc enable/config step in the board init; RCC config that selects no RTC clock source; running LCD init code before clock configuration on boards where LSE startup is deferred.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- Lcd clock error
- LSE frequency more than 5% off from 32.768 kHz, cannot use…
- MSIx auto-calibration is enabled for a source that has not…
- LSE frequency more than 5% off from 32.768 kHz, cannot use…
- cannot select OTG_HS reference clock with source frequency…
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/e608b26164368b2b.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/lcd.rs:201
);
// Set the pins
for pin in pins.iter_mut() {
pin.pin.pin.set_as_af(
pin.af_num,
AfType::output(crate::gpio::OutputType::PushPull, crate::gpio::Speed::VeryHigh),
);
}
// Initialize the display ram to 0
for i in 0..8 {
T::regs().ram_com(i).low().write_value(0);
T::regs().ram_com(i).high().write_value(0);
}
// Calculate the clock dividers
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 {
Duty::Static => 1,
Duty::Half => 2,
Duty::Third => 3,
Duty::Quarter => 4,
Duty::Eigth => 8,
};
let target_clock = config.target_fps.0 * duty_divider;
let target_division = lcd_clk.0 / target_clock;
let mut ps = 0;
let mut div = 0;
let mut best_fps_match = u32::MAX;
for trial_div in 0..0xF {
let trial_ps = (target_division / (trial_div + 16))
.next_power_of_two()View on GitHub (pinned to 463a07b963)