Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timer::start panics #227

Open
knoellle opened this issue Mar 26, 2023 · 0 comments
Open

Timer::start panics #227

knoellle opened this issue Mar 26, 2023 · 0 comments

Comments

@knoellle
Copy link
Contributor

knoellle commented Mar 26, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant