embassy-rs/embassy · error
DSI TX escape clock
Error message
DSI TX escape clock
What it means
Same pattern as the lane byte clock: set_video_config reads tx_escape_clock.to_hertz().expect("DSI TX escape clock"). The TX escape clock (used for the DSI low-power data lane, typically lane_byte_clock/8) must have been computed and stored when the DsiHost was configured; if it is None the display setup panics.
Solutions
- Use the standard DsiHost::new/init path which computes tx_escape_clock from the lane byte clock (LSCLKDIV / /8).
- Ensure dsi_phy/lane byte clock is present in the RCC config so the escape clock can be derived.
- Update to the latest embassy-stm32 and follow the matching DSI example for clock setup.
- If using a custom panel setup, set the escape divider registers before set_video_config runs.
Example fix
// before let mut dsi = DsiHost::new(...); dsi.enable(); // after let mut dsi = DsiHost::new(...); dsi.init(&rcc_cfg_dsiderived_clocks); // sets lane_byte_clock & tx_escape_clock dsi.start_panel::<Panel>(&lcd_hse_freq, ...);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure init path computed tx_escape_clock before set_video_config: // use DsiHost::new + init (which derives escape clock) instead of constructing state manually.
Prevention
- Use the documented DsiHost constructor/init path rather than manual setup.
- Keep lane byte clock configured so the /8 escape clock can be derived.
- Update embassy-stm32 and re-check the DSI example when upgrading.
When it happens
Trigger: Calling set_video_config (via start_panel) when the DsiHost was constructed without setting tx_escape_clock — normally derived from the lane byte clock during init — e.g. when clocks were not programmed or a custom constructor path skipped the derivation.
Common situations: Hand-constructing DsiHost state instead of using the documented new/init path; RCC config missing the DSI kernel clock so escape clock derivation fails; driver version changes moving escape-clock computation into init while old app code skipped that call.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- DSI lane byte clock
- DSI PHY clock must be enabled before init
- AHB frequency is too low
- cannot select OTG_HS reference clock with source frequency…
- DTS PCLK frequency must be less than 127 MHz.
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/1ed727cda06efbce.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/dsihost/mode.rs:300
fn set_color<Panel: DsiPanel>(&mut self, color: DsiColor) {
T::regs().lcolcr().modify(|w| {
w.set_colc(color as u8);
w.set_lpe(match color {
DsiColor::Rgb666Config1 | DsiColor::Rgb666Config2 => Panel::LOOSELY_PACKED,
_ => false,
});
});
// Set color coding in DSI wrapper COLMUX
T::regs().wcfgr().modify(|w| {
w.set_colmux(color as u8);
});
}
/// Set video mode registers from a [`DsiVideoConfig`]
fn set_video_config<Panel: DsiPanel>(&mut self, config: &DsiVideoConfig) {
let lane_byte_clock = self.lane_byte_clock.to_hertz().expect("DSI lane byte clock");
let tx_escape_clock = self.tx_escape_clock.to_hertz().expect("DSI TX escape clock");
let ltdc_clock = LTDC::frequency();
T::regs().mcr().modify(|w| w.set_cmdm(false));
T::regs().wcfgr().modify(|w| w.set_dsim(false));
T::regs().vmcr().modify(|w| {
w.set_vmt(config.mode as u8);
w.set_lpvsae(config.lpvsa);
w.set_lpvbpe(config.lpvbp);
w.set_lpvfpe(config.lpvfp);
w.set_lpvae(config.lpva);
w.set_lphbpe(config.lphbp);
w.set_lphfpe(config.lphfp);
w.set_fbtaae(config.bta);
w.set_lpce(config.lpcmd);
});
match config.mode {View on GitHub (pinned to 463a07b963)