The Timer::start()implementation breaks if the ticks value calculated inside the start function is an exact multiple of (1 << 16).
Numerical example
If ticks is 1 << 16 == 65536 then psc, which is (ticks - 1) / (1 << 16) becomes 0 because the division result is ever so slightly less than one and thus trucated.
Now we calculate u16(ticks / u32(psc + 1)). But since psc is 0,psc + 1 is 1, so ticks / u32(psc + 1) is still 65536, which is then cast to a u16.
But since 65536 is 1 << 16, it doesn't fit in the u16 range from 0 to 1 << 16 - 1 and we unwrapp an Err(Overflow) value.
Clock configuration example
Pretty simple actually, the MSI clock source outputs frequencies that (except for MSI range 0) are all multiple of 1 << 16.
For example, MSI clock source of range 1 produces a 65536 Hz clock.
When attempting to start a timer with frequency 1 with this clock, the error occurs.
Code example
use cast::{u16, u32, Error};
// simplified version of calculations inside Timer::start()
fn timer_settings(sysclk: u32, frequency: u32) -> Result<(u16, u16), Error> {
let ticks = sysclk / frequency;
println!("{}", ticks % (1 << 16));
let psc = u16((ticks - 1) / (1 << 16))?;
let arr = u16(ticks / u32(psc + 1))?;
Ok((psc, arr))
}
fn main() {
// all of these return Err()
for n in 1..100 {
println!("{n} {:?}", timer_settings((2 << 16) * n, n).unwrap_err());
}
// all of these return Ok()
for n in 1..100 {
println!("{n} {:?}", timer_settings((2 << 16) * n - 1, n).unwrap());
}
}
Possible solution
I'm not 100% sure on this, but I think u16(ticks / u32(psc + 1)) can be changed to u16((ticks - 1) / u32(psc + 1)), such that both divisions have the same numerator.
The
Timer::start()
implementation breaks if theticks
value calculated inside the start function is an exact multiple of(1 << 16)
.Numerical example
If
ticks
is1 << 16 == 65536
thenpsc
, which is(ticks - 1) / (1 << 16)
becomes0
because the division result is ever so slightly less than one and thus trucated. Now we calculateu16(ticks / u32(psc + 1))
. But sincepsc
is0
,psc + 1
is1
, soticks / u32(psc + 1)
is still65536
, which is then cast to au16
. But since65536
is1 << 16
, it doesn't fit in theu16
range from0
to1 << 16 - 1
and we unwrapp anErr(Overflow)
value.Clock configuration example
Pretty simple actually, the
MSI
clock source outputs frequencies that (except for MSI range 0) are all multiple of1 << 16
. For example, MSI clock source of range 1 produces a 65536 Hz clock. When attempting to start a timer with frequency 1 with this clock, the error occurs.Code example
Possible solution
I'm not 100% sure on this, but I think
u16(ticks / u32(psc + 1))
can be changed tou16((ticks - 1) / u32(psc + 1))
, such that both divisions have the same numerator.