-
Notifications
You must be signed in to change notification settings - Fork 69
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
Timers with period > 1s #190
Comments
I'm not sure, if it is really possible, but it should. Some pointers / ideas:
|
Some naive approaches: Keep PSC and ARR equal. Calculate it with sqrt of period. (Has resolution issues). Fix one and set the other. (Has resolution and range issues). I think the existing code is pretty good about setting the right values, if they're faster than 1hz, and you leave it in edge mode. Related: The latest version of my fork has a working interface to set RTC wakeup timer, where you pass period in seconds as f32. This works in practice in a similar way to a timer, with an easy API. But the reg write process is different, and doesn't help here. |
Definitely. This has to be reworked. I wouldn't worry about a breaking change too much.
Seems like a valid approach. I'm not sure though, if this does cause any issues. I wonder why the |
Just to chime in, this is similar to the discussion around clocks for PWM. Ultimately, the only way to get full control over these things is to basically give the same interface as the registers. They use the divider -1 approach because all states are valid and you can get ever valid combo. However, it’s just terribly unfriendly to use. It seems like there just needs to be multiple ways to configure these things, via trait or otherwise. Possibly structs that can produce the register values given a clock frequency. That way most users can get more conceptually useful inputs (like setting an approximate resulting period) or drill down to get exactly what they need. |
I've added the method (as to be non-breaking) to my fork. Here's the code. The comments provide some details, including how this approach is quick+dirty: Ie there are ways to get better precision, perhaps at the expense of some computation. /// Set the timer period, in seconds. Overrides the period or frequency set
/// in the constructor.
/// This allows you to set periods greater than 1hz.
pub fn set_period(&mut self, period: f32, clocks: &clocks::Clocks) {
// PSC and ARR range: 0 to 65535
// (PSC+1)*(ARR+1) = TIMclk/Updatefrequency = TIMclk * period
// APB1 (pclk1) is used by Tim2, 3, 4, 6, 7.
// APB2 (pclk2) is used by Tim8, 15-20 etc.
// todo: It appears there's a (fixed?) 2x multiplier on APB1
// timers; it's twice `pclk1`. See clocks diagram in RM, or `Clock Configuration`
// tool in STM32CubeIDE.
let tim_clk = clocks.calc_speeds().pclk1 * 2.;
// We need to factor the right-hand-side of the above equation (`rhs` variable)
// into integers. There are likely clever algorithms available to do this.
// Some examples: https://cp-algorithms.com/algebra/factorization.html
// We've chosen something quick to write, and with sloppy precision;
// should be good enough for most cases.
let rhs = tim_clk * period;
// todo: Round instead of cast?
let arr = (rhs.sqrt() - 1.) as u16;
let psc = arr;
self.tim.arr.write(|w| unsafe { w.bits(u32::from(arr)) });
self.tim.psc.write(|w| unsafe { w.bits(u32::from(psc)) });
} We set I've tested this with a few values; seems to work, at least for the clock config and periods I used. Here's the code from the current impl, using let frequency = timeout.into().0;
let timer_clock = $TIMX::get_clk(&self.clocks);
let ticks = timer_clock.0 * if self.clocks.ppre1() == 1 { 1 } else { 2 }
/ frequency;
let psc = crate::unwrap!(u16::try_from((ticks - 1) / (1 << 16)).ok());
// NOTE(write): uses all bits in this register.
self.tim.psc.write(|w| w.psc().bits(psc));
let arr = crate::unwrap!(u16::try_from(ticks / u32::from(psc + 1)).ok());
// TODO (sh3rm4n)
// self.tim.arr.write(|w| { w.arr().bits(arr) });
self.tim.arr.write(|w| unsafe { w.bits(u32::from(arr)) }); |
Probably should return a let max_val = 65_535;
if arr > max_val || psc > max_val {
return Err(ValueError {})
} A little more info on the subjective part:
|
Closed by #267 |
Hi. Is it possible to implement timers with period > 1s? It seems that the
.hz()
api only takes integers.If not, are you open to a PR?
The text was updated successfully, but these errors were encountered: