embassy-rs/embassy · error
psc division overflow
Error message
psc division overflow: {} What it means
The TIM-based time driver computes psc = timer_freq/TICK_HZ - 1 and stores it in the 16-bit PSC register. If the computed value doesn't fit in u16 (timer clock too fast relative to TICK_HZ, or TICK_HZ = 0 causing underflow/overflow), init_timer panics.
Solutions
- Increase TICK_HZ so timer_freq/TICK_HZ - 1 fits in a u16 (≤ 65536 division).
- Lower the timer input clock via RCC prescalers if you need a very coarse tick.
- Fix TICK_HZ so it is nonzero and sensible (typically 1000).
Example fix
// before (timer_freq = 500 MHz, TICK_HZ = 1000 -> psc = 499999, > u16::MAX) tick_hz = 1000 // after (enable APB prescaler so timer_freq = 64 MHz, psc = 63999 fits u16) // or choose tick_hz such that timer_freq/tick_hz <= 65536
Defensive patterns
Strategy: validation
Validate before calling
fn psc_fits(timer_freq: u32, tick_hz: u32) -> bool {
tick_hz > 0 && (timer_freq / tick_hz).saturating_sub(1) <= u16::MAX as u32
} Prevention
- Keep timer_freq / TICK_HZ - 1 within 0..=65535.
- Never set TICK_HZ to 0; define it via a checked constant.
- If you need coarse ticks, slow the timer clock with RCC prescalers instead of huge PSC values.
When it happens
Trigger: timer_freq / TICK_HZ - 1 > 65535 (e.g. very high timer clock with very low TICK_HZ), or TICK_HZ of 0 making the subtraction underflow on u32.
Common situations: Setting an extremely low TICK_HZ with a high-speed timer clock; typo making TICK_HZ 0; running a 480 MHz timer clock with 1 Hz ticks.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- LSE is not configured, but selected for time_driver!!!
- Invalid prescaler: for timer frequency: Hz
- Enabling OsTimer clock should not fail
- Passphrase is too short or too long
- Boot prepare error
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/5c5a4978af97c70d.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/time_driver/tim.rs:159
queue: Mutex::new(RefCell::new(Queue::new()))
});
impl RtcDriver {
/// initialize the timer, but don't start it. Used for chips like stm32wle5
/// for low power where the timer config is lost in STOP2.
pub(crate) fn init_timer(&'static self, cs: critical_section::CriticalSection) {
let r = regs_gp16();
rcc::enable_and_reset_with_cs_no_refcount::<T>(cs);
let timer_freq = T::frequency();
r.cr1().modify(|w| w.set_cen(false));
write_cnt(0);
let psc = timer_freq.0 / TICK_HZ as u32 - 1;
let psc: u16 = match psc.try_into() {
Err(_) => panic!("psc division overflow: {}", psc),
Ok(n) => n,
};
r.psc().write_value(psc);
write_arr(Counter::MAX);
// Set URS, generate update and clear URS
r.cr1().modify(|w| w.set_urs(vals::Urs::CounterOnly));
r.egr().write(|w| w.set_ug(true));
r.cr1().modify(|w| w.set_urs(vals::Urs::AnyEvent));
// Mid-way point
write_ccr(0, HALF_COUNTER);
// Enable overflow and half-overflow interrupts
r.dier().write(|w| {
w.set_uie(true);
w.set_ccie(0, true);View on GitHub (pinned to 463a07b963)