Skip to content

Commit bea4cea

Browse files
committed
Fix timer panic on high frequencies
Make the calculation more robust against overflows and wrong settings
1 parent e474119 commit bea4cea

File tree

3 files changed

+26
-11
lines changed

3 files changed

+26
-11
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ No changes.
2020

2121
- Add missing ADC channels ([#337])
2222

23+
### Fixed
24+
25+
- Fix wrong timer frequency calculation and unexpected panics ([#338])
26+
2327
## [v0.9.1] - 2022-09-07
2428

2529
### Added
@@ -570,6 +574,7 @@ let clocks = rcc
570574
[defmt]: https://github.com/knurling-rs/defmt
571575
[filter]: https://defmt.ferrous-systems.com/filtering.html
572576

577+
[#338]: https://github.com/stm32-rs/stm32f3xx-hal/pull/338
573578
[#337]: https://github.com/stm32-rs/stm32f3xx-hal/pull/337
574579
[#335]: https://github.com/stm32-rs/stm32f3xx-hal/pull/335
575580
[#334]: https://github.com/stm32-rs/stm32f3xx-hal/pull/334

src/timer.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//!
1111
//! [examples/adc.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.9.1/examples/adc.rs
1212
13-
use core::convert::{From, TryFrom};
13+
use core::convert::TryFrom;
1414

1515
use crate::pac::{DCB, DWT};
1616
#[cfg(feature = "enumset")]
@@ -279,13 +279,19 @@ where
279279
let timeout: Self::Time = timeout.into();
280280
let clock = TIM::clock(&self.clocks);
281281

282-
let ticks = clock.integer() * *timeout.scaling_factor() * timeout.integer();
282+
let ticks = clock.integer().saturating_mul(timeout.integer()) * *timeout.scaling_factor();
283283

284-
let psc = crate::unwrap!(u16::try_from((ticks - 1) / (1 << 16)).ok());
285-
self.tim.set_psc(psc);
284+
let psc: u32 = (ticks.saturating_sub(1)) / (1 << 16);
285+
self.tim.set_psc(crate::unwrap!(u16::try_from(psc).ok()));
286286

287-
let arr = crate::unwrap!(u16::try_from(ticks / u32::from(psc + 1)).ok());
288-
self.tim.set_arr(arr);
287+
let mut arr = ticks / psc.saturating_add(1);
288+
// If the set frequency is to high to get a meaningful timer resolution,
289+
// set arr to one, so the timer can at least do something and code waiting
290+
// on it is not stuck.
291+
if psc == 0 && arr == 0 {
292+
arr = 1;
293+
}
294+
self.tim.set_arr(crate::unwrap!(u16::try_from(arr).ok()));
289295

290296
// Ensure that the below procedure does not create an unexpected interrupt.
291297
let is_update_interrupt_active = self.is_interrupt_configured(Event::Update);

testsuite/tests/timer.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ mod tests {
7777
defmt::trace!("{}", state.mono_timer);
7878
let freqcyc = state.mono_timer.frequency().integer();
7979

80-
let durations: [duration::Generic<u32>; 5] = [
80+
let durations: [duration::Generic<u32>; 6] = [
81+
100.nanoseconds().into(),
8182
100.microseconds().into(),
8283
1.milliseconds().into(),
8384
100.milliseconds().into(),
@@ -86,11 +87,12 @@ mod tests {
8687
// 100.seconds().into(),
8788
];
8889

89-
for dur in durations {
90+
for (i, dur) in durations.into_iter().enumerate() {
9091
defmt::trace!("Duration: {}", defmt::Debug2Format(&dur));
9192

9293
timer.start(dur);
93-
assert!(!timer.is_event_triggered(Event::Update));
94+
// Wait one cycle, so the start function overhead is not that big.
95+
unwrap!(nb::block!(timer.wait()).ok());
9496
// call instant after start, because starting the timer is the last thing done in the
9597
// start function, and therefor no overhead is added to the timing.
9698
let instant = state.mono_timer.now();
@@ -106,8 +108,10 @@ mod tests {
106108
let deviation = (ratio - 1.).abs();
107109

108110
// Deviation is high for smaller timer duration. Higher duration are pretty accurate.
109-
// TODO: Maybe the allowed deviation should changed depending on the duration?
110-
defmt::assert!(deviation < 11e-02);
111+
defmt::trace!("deviation: {}", deviation);
112+
if i > 0 {
113+
defmt::assert!(deviation < 1e-02);
114+
}
111115
}
112116
state.timer = Some(timer);
113117
}

0 commit comments

Comments
 (0)