Skip to content

Timer::start panics #227

@knoellle

Description

@knoellle

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions