Skip to content

Commit ac8a8ea

Browse files
committed
timer Instance, rtic monotonic
1 parent fa6eb8a commit ac8a8ea

File tree

10 files changed

+176
-25
lines changed

10 files changed

+176
-25
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
99

1010
### Added
1111

12+
- `Instance` for Timer's, rtic-monotonic fugit impl
1213
- Serial can now be reconfigured, allowing to change e.g. the baud rate after initialisation.
1314

1415
## [v0.8.0] - 2021-12-29

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ bxcan = "0.6"
2525
cast = { default-features = false, version = "0.3.0" }
2626
void = { default-features = false, version = "1.0.2" }
2727
embedded-hal = { features = ["unproven"], version = "0.2.6" }
28+
fugit = "0.3.0"
29+
rtic-monotonic = { version = "1.0", optional = true }
2830

2931
[dependencies.stm32-usbd]
3032
version = "0.6.0"
@@ -62,6 +64,8 @@ connectivity = ["medium", "has-can"]
6264
# Devices with CAN interface
6365
has-can = []
6466

67+
rtic = ["rt", "rtic-monotonic"]
68+
6569
[profile.dev]
6670
incremental = false
6771
codegen-units = 1

examples/blinky_timer_irq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn main() -> ! {
8686
cortex_m::interrupt::free(|cs| *G_LED.borrow(cs).borrow_mut() = Some(led));
8787

8888
// Set up a timer expiring after 1s
89-
let mut timer = Timer::tim2(dp.TIM2, &clocks).start_count_down(1.hz());
89+
let mut timer = Timer::new(dp.TIM2, &clocks).start_count_down(1.hz());
9090

9191
// Generate an interrupt when the timer expires
9292
timer.listen(Event::Update);

examples/pwm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn main() -> ! {
5252
// let c4 = gpiob.pb9.into_alternate_push_pull(&mut gpiob.crh);
5353

5454
let mut pwm =
55-
Timer::tim2(p.TIM2, &clocks).pwm::<Tim2NoRemap, _, _, _>(pins, &mut afio.mapr, 1.khz());
55+
Timer::new(p.TIM2, &clocks).pwm::<Tim2NoRemap, _, _, _>(pins, &mut afio.mapr, 1.khz());
5656

5757
// Enable clock on each of the channels
5858
pwm.enable(Channel::C1);

examples/pwm_custom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn main() -> ! {
3030
let p0 = pb4.into_alternate_push_pull(&mut gpiob.crl);
3131
let p1 = gpiob.pb5.into_alternate_push_pull(&mut gpiob.crl);
3232

33-
let pwm = Timer::tim3(p.TIM3, &clocks).pwm((p0, p1), &mut afio.mapr, 1.khz());
33+
let pwm = Timer::new(p.TIM3, &clocks).pwm((p0, p1), &mut afio.mapr, 1.khz());
3434

3535
let max = pwm.get_max_duty();
3636

examples/pwm_input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn main() -> ! {
2727
let (_pa15, _pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4);
2828
let pb5 = gpiob.pb5;
2929

30-
let pwm_input = Timer::tim3(p.TIM3, &clocks).pwm_input(
30+
let pwm_input = Timer::new(p.TIM3, &clocks).pwm_input(
3131
(pb4, pb5),
3232
&mut afio.mapr,
3333
&mut dbg,

examples/qei.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn main() -> ! {
3838
let c1 = gpiob.pb6;
3939
let c2 = gpiob.pb7;
4040

41-
let qei = Timer::tim4(dp.TIM4, &clocks).qei((c1, c2), &mut afio.mapr, QeiOptions::default());
41+
let qei = Timer::new(dp.TIM4, &clocks).qei((c1, c2), &mut afio.mapr, QeiOptions::default());
4242
let mut delay = Delay::new(cp.SYST, clocks);
4343

4444
loop {

examples/timer-interrupt-rtic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ mod app {
4949
.pc13
5050
.into_push_pull_output_with_state(&mut gpioc.crh, PinState::High);
5151
// Configure the syst timer to trigger an update every second and enables interrupt
52-
let mut timer = Timer::tim1(cx.device.TIM1, &clocks).start_count_down(1.hz());
52+
let mut timer = Timer::new(cx.device.TIM1, &clocks).start_count_down(1.hz());
5353
timer.listen(Event::Update);
5454

5555
// Init the static resources to use them later through RTIC

src/timer.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,17 @@ use crate::pac::{DBGMCU as DBG, TIM2, TIM3};
6868
#[cfg(feature = "stm32f100")]
6969
use crate::pac::{TIM15, TIM16, TIM17};
7070

71-
use crate::rcc::{Clocks, Enable, GetBusFreq, RccBus, Reset};
71+
use crate::rcc::{self, Clocks};
7272
use cast::{u16, u32, u64};
7373
use cortex_m::peripheral::syst::SystClkSource;
7474
use cortex_m::peripheral::SYST;
7575
use void::Void;
7676

7777
use crate::time::Hertz;
7878

79+
#[cfg(feature = "rtic")]
80+
mod monotonic;
81+
7982
/// Interrupt events
8083
pub enum Event {
8184
/// Timer timed out / count down ended
@@ -275,18 +278,50 @@ impl Cancel for CountDownTimer<SYST> {
275278

276279
impl Periodic for CountDownTimer<SYST> {}
277280

281+
pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + rcc::GetBusFreq {}
282+
283+
impl<TIM> Timer<TIM>
284+
where
285+
TIM: Instance,
286+
{
287+
/// Initialize timer
288+
pub fn new(tim: TIM, clocks: &Clocks) -> Self {
289+
unsafe {
290+
//NOTE(unsafe) this reference will only be used for atomic writes with no side effects
291+
let rcc = &(*RCC::ptr());
292+
// Enable and reset the timer peripheral
293+
TIM::enable(rcc);
294+
TIM::reset(rcc);
295+
}
296+
297+
Self {
298+
clk: TIM::get_timer_frequency(&clocks),
299+
tim,
300+
}
301+
}
302+
303+
/// Resets timer peripheral
304+
#[inline(always)]
305+
pub fn clocking_reset(&mut self) {
306+
let rcc = unsafe { &(*RCC::ptr()) };
307+
TIM::reset(rcc);
308+
}
309+
310+
/// Releases the TIM Peripheral
311+
pub fn release(self) -> TIM {
312+
self.tim
313+
}
314+
}
315+
278316
macro_rules! hal {
279317
($($TIMX:ident: ($timX:ident, $APBx:ident, $dbg_timX_stop:ident$(,$master_timbase:ident)*),)+) => {
280318
$(
319+
impl Instance for $TIMX { }
320+
281321
impl Timer<$TIMX> {
282322
/// Initialize timer
283323
pub fn $timX(tim: $TIMX, clocks: &Clocks) -> Self {
284-
// enable and reset peripheral to a clean slate state
285-
let rcc = unsafe { &(*RCC::ptr()) };
286-
$TIMX::enable(rcc);
287-
$TIMX::reset(rcc);
288-
289-
Self { tim, clk: <$TIMX as RccBus>::Bus::get_timer_frequency(&clocks) }
324+
Self::new(tim, clocks)
290325
}
291326

292327
/// Starts timer in count down mode at a given frequency
@@ -323,23 +358,11 @@ macro_rules! hal {
323358
timer
324359
}
325360

326-
/// Resets timer peripheral
327-
#[inline(always)]
328-
pub fn clocking_reset(&mut self) {
329-
let rcc = unsafe { &(*RCC::ptr()) };
330-
$TIMX::reset(rcc);
331-
}
332-
333361
/// Stopping timer in debug mode can cause troubles when sampling the signal
334362
#[inline(always)]
335363
pub fn stop_in_debug(&mut self, dbg: &mut DBG, state: bool) {
336364
dbg.cr.modify(|_, w| w.$dbg_timX_stop().bit(state));
337365
}
338-
339-
/// Releases the TIM Peripheral
340-
pub fn release(self) -> $TIMX {
341-
self.tim
342-
}
343366
}
344367

345368
impl CountDownTimer<$TIMX> {

src/timer/monotonic.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//! RTIC Monotonic implementation
2+
3+
use core::convert::TryInto;
4+
5+
use crate::{rcc::Clocks, timer::Timer};
6+
pub use fugit::{self, ExtU32};
7+
use rtic_monotonic::Monotonic;
8+
9+
pub struct MonoTimer<T, const FREQ: u32> {
10+
tim: T,
11+
ovf: u32,
12+
}
13+
14+
macro_rules! mono {
15+
($($TIM:ty,)+) => {
16+
$(
17+
impl Timer<$TIM> {
18+
pub fn monotonic<const FREQ: u32>(self) -> MonoTimer<$TIM, FREQ> {
19+
MonoTimer::<$TIM, FREQ>::_new(self)
20+
}
21+
}
22+
23+
impl<const FREQ: u32> MonoTimer<$TIM, FREQ> {
24+
pub fn new(timer: $TIM, clocks: &Clocks) -> Self {
25+
Timer::<$TIM>::new(timer, clocks).monotonic()
26+
}
27+
28+
fn _new(timer: Timer<$TIM>) -> Self {
29+
let Timer { tim, clk } = timer;
30+
// Configure timer. If the u16 conversion panics, try increasing FREQ.
31+
let psc: u16 = (clk.0 / FREQ - 1).try_into().unwrap();
32+
tim.psc.write(|w| w.psc().bits(psc)); // Set prescaler.
33+
tim.arr.write(|w| w.arr().bits(u16::MAX)); // Set auto-reload value.
34+
tim.egr.write(|w| w.ug().set_bit()); // Generate interrupt on overflow.
35+
36+
// Start timer.
37+
tim.sr.modify(|_, w| w.uif().clear_bit()); // Clear interrupt flag.
38+
tim.cr1.modify(|_, w| {
39+
w.cen()
40+
.set_bit() // Enable counter.
41+
.udis()
42+
.clear_bit() // Overflow should trigger update event.
43+
.urs()
44+
.set_bit() // Only overflow triggers interrupt.
45+
});
46+
47+
Self { tim, ovf: 0 }
48+
}
49+
}
50+
51+
impl<const FREQ: u32> Monotonic for MonoTimer<$TIM, FREQ> {
52+
type Instant = fugit::TimerInstantU32<FREQ>;
53+
type Duration = fugit::TimerDurationU32<FREQ>;
54+
55+
unsafe fn reset(&mut self) {
56+
self.tim.dier.modify(|_, w| w.cc1ie().set_bit());
57+
}
58+
59+
#[inline(always)]
60+
fn now(&mut self) -> Self::Instant {
61+
let cnt = self.tim.cnt.read().cnt().bits() as u32;
62+
63+
// If the overflow bit is set, we add this to the timer value. It means the `on_interrupt`
64+
// has not yet happened, and we need to compensate here.
65+
let ovf = if self.tim.sr.read().uif().bit_is_set() {
66+
0x10000
67+
} else {
68+
0
69+
};
70+
71+
Self::Instant::from_ticks(cnt.wrapping_add(ovf).wrapping_add(self.ovf))
72+
}
73+
74+
fn set_compare(&mut self, instant: Self::Instant) {
75+
let now = self.now();
76+
let cnt = self.tim.cnt.read().cnt().bits();
77+
78+
// Since the timer may or may not overflow based on the requested compare val, we check
79+
// how many ticks are left.
80+
let val = match instant.checked_duration_since(now) {
81+
None => cnt.wrapping_add(0xffff), // In the past, RTIC will handle this
82+
Some(x) if x.ticks() <= 0xffff => instant.duration_since_epoch().ticks() as u16, // Will not overflow
83+
Some(_) => cnt.wrapping_add(0xffff), // Will overflow, run for as long as possible
84+
};
85+
86+
self.tim.ccr1.write(|w| w.ccr().bits(val));
87+
}
88+
89+
fn clear_compare_flag(&mut self) {
90+
self.tim.sr.modify(|_, w| w.cc1if().clear_bit());
91+
}
92+
93+
fn on_interrupt(&mut self) {
94+
// If there was an overflow, increment the overflow counter.
95+
if self.tim.sr.read().uif().bit_is_set() {
96+
self.tim.sr.modify(|_, w| w.uif().clear_bit());
97+
98+
self.ovf += 0x10000;
99+
}
100+
}
101+
102+
#[inline(always)]
103+
fn zero() -> Self::Instant {
104+
Self::Instant::from_ticks(0)
105+
}
106+
}
107+
)+
108+
}
109+
}
110+
111+
mono!(crate::pac::TIM2, crate::pac::TIM3,);
112+
113+
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
114+
mono!(crate::pac::TIM1,);
115+
116+
#[cfg(feature = "medium")]
117+
mono!(crate::pac::TIM4,);
118+
119+
#[cfg(any(feature = "high", feature = "connectivity"))]
120+
mono!(crate::pac::TIM5,);
121+
122+
#[cfg(all(feature = "stm32f103", feature = "high",))]
123+
mono!(crate::pac::TIM8,);

0 commit comments

Comments
 (0)