1pub mod prelude {
40 #[cfg(feature = "stm32_tim2")]
41 pub use crate::stm32_tim2_monotonic;
42
43 #[cfg(feature = "stm32_tim3")]
44 pub use crate::stm32_tim3_monotonic;
45
46 #[cfg(feature = "stm32_tim4")]
47 pub use crate::stm32_tim4_monotonic;
48
49 #[cfg(feature = "stm32_tim5")]
50 pub use crate::stm32_tim5_monotonic;
51
52 #[cfg(feature = "stm32_tim15")]
53 pub use crate::stm32_tim15_monotonic;
54
55 pub use crate::Monotonic;
56 pub use fugit::{self, ExtU64, ExtU64Ceil};
57}
58
59use portable_atomic::{AtomicU64, Ordering};
60use rtic_time::{
61 half_period_counter::calculate_now,
62 timer_queue::{TimerQueue, TimerQueueBackend},
63};
64use stm32_metapac as pac;
65
66mod _generated {
67 #![allow(dead_code)]
68 #![allow(unused_imports)]
69 #![allow(non_snake_case)]
70
71 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
72}
73
74#[doc(hidden)]
75#[macro_export]
76macro_rules! __internal_create_stm32_timer_interrupt {
77 ($mono_backend:ident, $interrupt_name:ident) => {
78 #[no_mangle]
79 #[allow(non_snake_case)]
80 unsafe extern "C" fn $interrupt_name() {
81 use $crate::TimerQueueBackend;
82 $crate::stm32::$mono_backend::timer_queue().on_monotonic_interrupt();
83 }
84 };
85}
86
87#[doc(hidden)]
88#[macro_export]
89macro_rules! __internal_create_stm32_timer_struct {
90 ($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
91 pub struct $name;
93
94 impl $name {
95 pub fn start(tim_clock_hz: u32) {
104 $crate::__internal_create_stm32_timer_interrupt!($mono_backend, $timer);
105
106 $crate::stm32::$mono_backend::_start(tim_clock_hz, $tick_rate_hz);
107 }
108 }
109
110 impl $crate::TimerQueueBasedMonotonic for $name {
111 type Backend = $crate::stm32::$mono_backend;
112 type Instant = $crate::fugit::Instant<
113 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
114 1,
115 { $tick_rate_hz },
116 >;
117 type Duration = $crate::fugit::Duration<
118 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
119 1,
120 { $tick_rate_hz },
121 >;
122 }
123
124 $crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
125 $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
126 };
127}
128
129#[cfg(feature = "stm32_tim2")]
139#[macro_export]
140macro_rules! stm32_tim2_monotonic {
141 ($name:ident, $tick_rate_hz:expr) => {
142 $crate::__internal_create_stm32_timer_struct!($name, Tim2Backend, TIM2, $tick_rate_hz);
143 };
144}
145
146#[cfg(feature = "stm32_tim3")]
156#[macro_export]
157macro_rules! stm32_tim3_monotonic {
158 ($name:ident, $tick_rate_hz:expr) => {
159 $crate::__internal_create_stm32_timer_struct!($name, Tim3Backend, TIM3, $tick_rate_hz);
160 };
161}
162
163#[cfg(feature = "stm32_tim4")]
173#[macro_export]
174macro_rules! stm32_tim4_monotonic {
175 ($name:ident, $tick_rate_hz:expr) => {
176 $crate::__internal_create_stm32_timer_struct!($name, Tim4Backend, TIM4, $tick_rate_hz);
177 };
178}
179
180#[cfg(feature = "stm32_tim5")]
190#[macro_export]
191macro_rules! stm32_tim5_monotonic {
192 ($name:ident, $tick_rate_hz:expr) => {
193 $crate::__internal_create_stm32_timer_struct!($name, Tim5Backend, TIM5, $tick_rate_hz);
194 };
195}
196
197#[cfg(feature = "stm32_tim15")]
207#[macro_export]
208macro_rules! stm32_tim15_monotonic {
209 ($name:ident, $tick_rate_hz:expr) => {
210 $crate::__internal_create_stm32_timer_struct!($name, Tim15Backend, TIM15, $tick_rate_hz);
211 };
212}
213
214macro_rules! make_timer {
215 ($backend_name:ident, $timer:ident, $bits:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
216 $(
218 #[cfg_attr(docsrs, doc(cfg($($doc)*)))]
219 )?
220
221 pub struct $backend_name;
222
223 use pac::$timer;
224
225 static $overflow: AtomicU64 = AtomicU64::new(0);
226 static $tq: TimerQueue<$backend_name> = TimerQueue::new();
227
228 impl $backend_name {
229 pub fn _start(tim_clock_hz: u32, timer_hz: u32) {
235 _generated::$timer::enable();
236 _generated::$timer::reset();
237
238 $timer.cr1().modify(|r| r.set_cen(false));
239
240 assert!((tim_clock_hz % timer_hz) == 0, "Unable to find suitable timer prescaler value!");
241 let psc = tim_clock_hz / timer_hz - 1;
242 $timer.psc().write(|r| r.set_psc(psc as u16));
243
244 $timer.dier().modify(|r| r.set_uie(true));
246
247 $timer.ccr(0).write(|r| r.set_ccr(($bits::MAX - ($bits::MAX >> 1)).into()));
249 $timer.dier().modify(|r| r.set_ccie(0, true));
250
251 $timer.egr().write(|r| r.set_ug(true));
253
254 $timer.cnt().write(|r| r.set_cnt(1));
256
257 $timer.sr().write(|r| {
260 r.0 = !0;
261 r.set_uif(false);
262 r.set_ccif(0, false);
263 r.set_ccif(1, false);
264 });
265
266 $tq.initialize(Self {});
267 $overflow.store(0, Ordering::SeqCst);
268
269 $timer.cr1().modify(|r| {
271 r.set_cen(true);
272 });
273
274 unsafe {
278 crate::set_monotonic_prio(_generated::NVIC_PRIO_BITS, pac::Interrupt::$timer);
279 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::$timer);
280 }
281 }
282 }
283
284 impl TimerQueueBackend for $backend_name {
285 type Ticks = u64;
286
287 fn now() -> Self::Ticks {
288 calculate_now(
289 || $overflow.load(Ordering::Relaxed),
290 || $timer.cnt().read().cnt()
291 )
292 }
293
294 fn set_compare(instant: Self::Ticks) {
295 let now = Self::now();
296
297 let val = if instant.wrapping_sub(now) <= ($bits::MAX as u64) {
300 instant as $bits
301 } else {
302 0
304 };
305
306 $timer.ccr(1).write(|r| r.set_ccr(val.into()));
307 }
308
309 fn clear_compare_flag() {
310 $timer.sr().write(|r| {
311 r.0 = !0;
312 r.set_ccif(1, false);
313 });
314 }
315
316 fn pend_interrupt() {
317 cortex_m::peripheral::NVIC::pend(pac::Interrupt::$timer);
318 }
319
320 fn enable_timer() {
321 $timer.dier().modify(|r| r.set_ccie(1, true));
322 }
323
324 fn disable_timer() {
325 $timer.dier().modify(|r| r.set_ccie(1, false));
326 }
327
328 fn on_interrupt() {
329 if $timer.sr().read().uif() {
331 $timer.sr().write(|r| {
332 r.0 = !0;
333 r.set_uif(false);
334 });
335 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
336 assert!(prev % 2 == 1, "Monotonic must have missed an interrupt!");
337 }
338 if $timer.sr().read().ccif(0) {
340 $timer.sr().write(|r| {
341 r.0 = !0;
342 r.set_ccif(0, false);
343 });
344 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
345 assert!(prev % 2 == 0, "Monotonic must have missed an interrupt!");
346 }
347 }
348
349 fn timer_queue() -> &'static TimerQueue<$backend_name> {
350 &$tq
351 }
352 }
353 };
354}
355
356#[cfg(feature = "stm32_tim2")]
357make_timer!(Tim2Backend, TIM2, u32, TIMER2_OVERFLOWS, TIMER2_TQ);
358
359#[cfg(feature = "stm32_tim3")]
360make_timer!(Tim3Backend, TIM3, u16, TIMER3_OVERFLOWS, TIMER3_TQ);
361
362#[cfg(feature = "stm32_tim4")]
363make_timer!(Tim4Backend, TIM4, u16, TIMER4_OVERFLOWS, TIMER4_TQ);
364
365#[cfg(feature = "stm32_tim5")]
366make_timer!(Tim5Backend, TIM5, u16, TIMER5_OVERFLOWS, TIMER5_TQ);
367
368#[cfg(feature = "stm32_tim15")]
369make_timer!(Tim15Backend, TIM15, u16, TIMER15_OVERFLOWS, TIMER15_TQ);