1use portable_atomic::{AtomicU32, Ordering};
30use rtic_time::{
31 half_period_counter::calculate_now,
32 timer_queue::{TimerQueue, TimerQueueBackend},
33};
34
35pub use imxrt_ral as ral;
36
37pub mod prelude {
39 #[cfg(feature = "imxrt_gpt1")]
40 pub use crate::imxrt_gpt1_monotonic;
41 #[cfg(feature = "imxrt_gpt2")]
42 pub use crate::imxrt_gpt2_monotonic;
43
44 pub use crate::Monotonic;
45 pub use fugit::{self, ExtU64, ExtU64Ceil};
46}
47
48#[doc(hidden)]
49#[macro_export]
50macro_rules! __internal_create_imxrt_timer_interrupt {
51 ($mono_backend:ident, $timer:ident) => {
52 #[no_mangle]
53 #[allow(non_snake_case)]
54 unsafe extern "C" fn $timer() {
55 use $crate::TimerQueueBackend;
56 $crate::imxrt::$mono_backend::timer_queue().on_monotonic_interrupt();
57 }
58 };
59}
60
61#[doc(hidden)]
62#[macro_export]
63macro_rules! __internal_create_imxrt_timer_struct {
64 ($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
65 pub struct $name;
67
68 impl $name {
69 pub fn start(gpt: $crate::imxrt::ral::gpt::$timer) {
73 $crate::__internal_create_imxrt_timer_interrupt!($mono_backend, $timer);
74
75 $crate::imxrt::$mono_backend::_start(gpt);
76 }
77 }
78
79 impl $crate::TimerQueueBasedMonotonic for $name {
80 type Backend = $crate::imxrt::$mono_backend;
81 type Instant = $crate::fugit::Instant<
82 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
83 1,
84 { $tick_rate_hz },
85 >;
86 type Duration = $crate::fugit::Duration<
87 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
88 1,
89 { $tick_rate_hz },
90 >;
91 }
92
93 $crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
94 $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
95 };
96}
97
98#[cfg(feature = "imxrt_gpt1")]
109#[macro_export]
110macro_rules! imxrt_gpt1_monotonic {
111 ($name:ident, $tick_rate_hz:expr) => {
112 $crate::__internal_create_imxrt_timer_struct!($name, Gpt1Backend, GPT1, $tick_rate_hz);
113 };
114}
115
116#[cfg(feature = "imxrt_gpt2")]
127#[macro_export]
128macro_rules! imxrt_gpt2_monotonic {
129 ($name:ident, $tick_rate_hz:expr) => {
130 $crate::__internal_create_imxrt_timer_struct!($name, Gpt2Backend, GPT2, $tick_rate_hz);
131 };
132}
133
134macro_rules! make_timer {
135 ($mono_name:ident, $backend_name:ident, $timer:ident, $period:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
136 $(
138 #[cfg_attr(docsrs, doc(cfg($($doc)*)))]
139 )?
140
141 pub struct $backend_name;
142
143 use ral::gpt::$timer;
144
145 static $period: AtomicU32 = AtomicU32::new(0);
147 static $tq: TimerQueue<$backend_name> = TimerQueue::new();
148
149 impl $backend_name {
150 pub fn _start(gpt: $timer) {
156
157 ral::modify_reg!(ral::gpt, gpt, CR, EN: 0);
159 ral::write_reg!(ral::gpt, gpt, SR, 0b11_1111);
161
162 ral::modify_reg!(ral::gpt, gpt, CR,
164 ENMOD: 1, FRR: 1, );
167
168 $period.store(0, Ordering::SeqCst);
170
171 ral::write_reg!(ral::gpt, gpt, IR,
173 ROVIE: 1, OF1IE: 1, OF2IE: 1, );
177
178 ral::write_reg!(ral::gpt, gpt, OCR[0], 0x8000_0000);
180
181 ral::write_reg!(ral::gpt, gpt, OCR[1], 0x0000_0000);
184
185 $tq.initialize(Self {});
187
188 ral::modify_reg!(ral::gpt, gpt, CR, EN: 1);
190 ral::modify_reg!(ral::gpt, gpt, CR,
191 ENMOD: 0, );
193
194 unsafe {
198 crate::set_monotonic_prio(ral::NVIC_PRIO_BITS, ral::Interrupt::$timer);
199 cortex_m::peripheral::NVIC::unmask(ral::Interrupt::$timer);
200 }
201 }
202 }
203
204 impl TimerQueueBackend for $backend_name {
205 type Ticks = u64;
206
207 fn now() -> Self::Ticks {
208 let gpt = unsafe{ $timer::instance() };
209
210 calculate_now(
211 || $period.load(Ordering::Relaxed),
212 || ral::read_reg!(ral::gpt, gpt, CNT)
213 )
214 }
215
216 fn set_compare(instant: Self::Ticks) {
217 let gpt = unsafe{ $timer::instance() };
218
219 let ticks_wrapped = instant as u32;
225
226 ral::write_reg!(ral::gpt, gpt, OCR[1], ticks_wrapped);
227 }
228
229 fn clear_compare_flag() {
230 let gpt = unsafe{ $timer::instance() };
231 ral::write_reg!(ral::gpt, gpt, SR, OF2: 1);
232 }
233
234 fn pend_interrupt() {
235 cortex_m::peripheral::NVIC::pend(ral::Interrupt::$timer);
236 }
237
238 fn on_interrupt() {
239 let gpt = unsafe{ $timer::instance() };
240
241 let (rollover, half_rollover) = ral::read_reg!(ral::gpt, gpt, SR, ROV, OF1);
242
243 if rollover != 0 {
244 let prev = $period.fetch_add(1, Ordering::Relaxed);
245 ral::write_reg!(ral::gpt, gpt, SR, ROV: 1);
246 assert!(prev % 2 == 1, "Monotonic must have skipped an interrupt!");
247 }
248
249 if half_rollover != 0 {
250 let prev = $period.fetch_add(1, Ordering::Relaxed);
251 ral::write_reg!(ral::gpt, gpt, SR, OF1: 1);
252 assert!(prev % 2 == 0, "Monotonic must have skipped an interrupt!");
253 }
254 }
255
256 fn timer_queue() -> &'static TimerQueue<Self> {
257 &$tq
258 }
259 }
260 };
261}
262
263#[cfg(feature = "imxrt_gpt1")]
264make_timer!(Gpt1, Gpt1Backend, GPT1, GPT1_HALFPERIODS, GPT1_TQ);
265
266#[cfg(feature = "imxrt_gpt2")]
267make_timer!(Gpt2, Gpt2Backend, GPT2, GPT2_HALFPERIODS, GPT2_TQ);