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 Ok(psc) = u16::try_from(tim_clock_hz / timer_hz - 1) else {
242 panic!("Clock prescaler overflowed!");
243 };
244 $timer.psc().write(|r| r.set_psc(psc));
245
246 $timer.dier().modify(|r| r.set_uie(true));
248
249 $timer.ccr(0).write(|r| r.set_ccr(($bits::MAX - ($bits::MAX >> 1)).into()));
251 $timer.dier().modify(|r| r.set_ccie(0, true));
252
253 $timer.egr().write(|r| r.set_ug(true));
255
256 $timer.cnt().write(|r| r.set_cnt(1));
258
259 $timer.sr().write(|r| {
262 r.0 = !0;
263 r.set_uif(false);
264 r.set_ccif(0, false);
265 r.set_ccif(1, false);
266 });
267
268 $tq.initialize(Self {});
269 $overflow.store(0, Ordering::SeqCst);
270
271 $timer.cr1().modify(|r| {
273 r.set_cen(true);
274 });
275
276 unsafe {
280 crate::set_monotonic_prio(_generated::NVIC_PRIO_BITS, pac::Interrupt::$timer);
281 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::$timer);
282 }
283 }
284 }
285
286 impl TimerQueueBackend for $backend_name {
287 type Ticks = u64;
288
289 fn now() -> Self::Ticks {
290 calculate_now(
291 || $overflow.load(Ordering::Relaxed),
292 || $timer.cnt().read().cnt()
293 )
294 }
295
296 fn set_compare(instant: Self::Ticks) {
297 let now = Self::now();
298
299 let val = if instant.wrapping_sub(now) <= ($bits::MAX as u64) {
302 instant as $bits
303 } else {
304 0
306 };
307
308 $timer.ccr(1).write(|r| r.set_ccr(val.into()));
309 }
310
311 fn clear_compare_flag() {
312 $timer.sr().write(|r| {
313 r.0 = !0;
314 r.set_ccif(1, false);
315 });
316 }
317
318 fn pend_interrupt() {
319 cortex_m::peripheral::NVIC::pend(pac::Interrupt::$timer);
320 }
321
322 fn enable_timer() {
323 $timer.dier().modify(|r| r.set_ccie(1, true));
324 }
325
326 fn disable_timer() {
327 $timer.dier().modify(|r| r.set_ccie(1, false));
328 }
329
330 fn on_interrupt() {
331 if $timer.sr().read().uif() {
333 $timer.sr().write(|r| {
334 r.0 = !0;
335 r.set_uif(false);
336 });
337 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
338 assert!(prev % 2 == 1, "Monotonic must have missed an interrupt!");
339 }
340 if $timer.sr().read().ccif(0) {
342 $timer.sr().write(|r| {
343 r.0 = !0;
344 r.set_ccif(0, false);
345 });
346 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
347 assert!(prev % 2 == 0, "Monotonic must have missed an interrupt!");
348 }
349 }
350
351 fn timer_queue() -> &'static TimerQueue<$backend_name> {
352 &$tq
353 }
354 }
355 };
356}
357
358#[cfg(feature = "stm32_tim2")]
359make_timer!(Tim2Backend, TIM2, u32, TIMER2_OVERFLOWS, TIMER2_TQ);
360
361#[cfg(feature = "stm32_tim3")]
362make_timer!(Tim3Backend, TIM3, u16, TIMER3_OVERFLOWS, TIMER3_TQ);
363
364#[cfg(feature = "stm32_tim4")]
365make_timer!(Tim4Backend, TIM4, u16, TIMER4_OVERFLOWS, TIMER4_TQ);
366
367#[cfg(feature = "stm32_tim5")]
368make_timer!(Tim5Backend, TIM5, u16, TIMER5_OVERFLOWS, TIMER5_TQ);
369
370#[cfg(feature = "stm32_tim15")]
371make_timer!(Tim15Backend, TIM15, u16, TIMER15_OVERFLOWS, TIMER15_TQ);