embassy-rs/embassy · error
Invalid prescaler: for timer frequency: Hz
Error message
Invalid prescaler: {} for timer frequency: {}Hz What it means
The LPTIM-based time driver computes the prescaler needed so timer ticks match TICK_HZ; it only supports division factors 1,2,4,8,16 (mapped to LPTIM Presc values). If the required division for the given timer frequency isn't one of these, init_timer panics with the prescaler and timer frequency.
Solutions
- Choose a TICK_HZ that divides timer_freq by exactly 1/2/4/8/16 (e.g. with 32 kHz LSE use TICK_HZ 1024 or 2048).
- Change the LPTIM clock source/frequency so the ratio becomes a supported power of two.
- Adjust the TICK_HZ feature/configuration at build time to match your timer clock.
Example fix
// before (LSE 32768 Hz) tick_hz = 1000 // after tick_hz = 1024 // 32768 / 32 is not supported; 32768/32 no — use power-of-two ratio ≤16: // e.g. tick_hz = 2048 (32768/16) or raise LPTIM clock to 16 MHz and keep 1000 only if ratio fits
Defensive patterns
Strategy: validation
Validate before calling
const TICK_HZ: u32 = 1024; // ensure timer_freq / TICK_HZ is exactly 1, 2, 4, 8, or 16
fn prescaler_valid(timer_freq: u32, tick_hz: u32) -> bool {
matches!(timer_freq / tick_hz, 1 | 2 | 4 | 8 | 16)
} Prevention
- Pick TICK_HZ as timer_freq divided by a supported power of two (≤16).
- For 32 kHz LSE clocks, use TICK_HZ like 2048 or 4096, not 1000.
- Set TICK_HZ at build time consistently with the LPTIM clock source.
When it happens
Trigger: Setting TICK_HZ such that timer_freq / TICK_HZ is not exactly 1, 2, 4, 8, or 16 (e.g. timer clock 32768 Hz with TICK_HZ=1000 → ratio not a supported power of two).
Common situations: Custom TICK_HZ in a build.rs/feature config that doesn't divide the LPTIM clock; boards using an unusual LPTIM clock source (e.g. LSE 32768 Hz) with a millisecond tick.
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
- LSE is not configured, but selected for time_driver!!!
- psc division overflow
- 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/d861779b231482cf.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/time_driver/lptim.rs:147
rcc::enable_and_reset_with_cs::<T>(cs);
let timer_freq = T::frequency();
r.cnt().write(|w| w.set_cnt(0));
// let psc = timer_freq.0 / TICK_HZ as u32 - 1;
let psc = timer_freq.0 / TICK_HZ as u32;
let psc = match psc {
128 => vals::Presc::Div128,
64 => vals::Presc::Div64,
32 => vals::Presc::Div32,
16 => vals::Presc::Div16,
8 => vals::Presc::Div8,
4 => vals::Presc::Div4,
2 => vals::Presc::Div2,
1 => vals::Presc::Div1,
// TODO: we could compute the valid TICK_HZ for the valid prescalers to include in the panic message
_ => panic!("Invalid prescaler: {} for timer frequency: {}Hz", psc, timer_freq.0),
};
trace!(
"init: setting presc: {} timer_freq: {}Hz TICK_HZ: {}",
psc, timer_freq, TICK_HZ
);
r.cfgr().modify(|w| w.set_presc(psc));
// RM says timer must be enabled before setting arr or cmp
r.cr().modify(|w| w.set_enable(true));
trace!("init: arr: {:?}", r.arr().read());
// TRM says this is updated immediately if the timer is not started so no need to check for arrok! (stm32wl5 & stm32wle)
r.arr().write(|w| w.set_arr(u16::MAX));
// Enable overflow interrupts
ier_set_ueie(T::regs(), true);
<T as crate::lptim::SealedBasicInstance>::GlobalInterrupt::unpend();View on GitHub (pinned to 463a07b963)