rtic_monotonics/nrf/
rtc.rs1pub mod prelude {
32 pub use crate::nrf_rtc0_monotonic;
33 pub use crate::nrf_rtc1_monotonic;
34 #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
35 pub use crate::nrf_rtc2_monotonic;
36
37 pub use crate::Monotonic;
38 pub use fugit::{self, ExtU64, ExtU64Ceil};
39}
40
41#[cfg(feature = "nrf52805")]
42#[doc(hidden)]
43pub use nrf52805_pac::{self as pac, RTC0, RTC1};
44#[cfg(feature = "nrf52810")]
45#[doc(hidden)]
46pub use nrf52810_pac::{self as pac, RTC0, RTC1};
47#[cfg(feature = "nrf52811")]
48#[doc(hidden)]
49pub use nrf52811_pac::{self as pac, RTC0, RTC1};
50#[cfg(feature = "nrf52832")]
51#[doc(hidden)]
52pub use nrf52832_pac::{self as pac, RTC0, RTC1, RTC2};
53#[cfg(feature = "nrf52833")]
54#[doc(hidden)]
55pub use nrf52833_pac::{self as pac, RTC0, RTC1, RTC2};
56#[cfg(feature = "nrf52840")]
57#[doc(hidden)]
58pub use nrf52840_pac::{self as pac, RTC0, RTC1, RTC2};
59#[cfg(feature = "nrf5340-app")]
60#[doc(hidden)]
61pub use nrf5340_app_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
62#[cfg(feature = "nrf5340-net")]
63#[doc(hidden)]
64pub use nrf5340_net_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
65#[cfg(feature = "nrf9160")]
66#[doc(hidden)]
67pub use nrf9160_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
68
69use portable_atomic::{AtomicU32, Ordering};
70use rtic_time::{
71 half_period_counter::calculate_now,
72 timer_queue::{TimerQueue, TimerQueueBackend},
73};
74
75#[doc(hidden)]
76#[macro_export]
77macro_rules! __internal_create_nrf_rtc_interrupt {
78 ($mono_backend:ident, $rtc:ident) => {
79 #[no_mangle]
80 #[allow(non_snake_case)]
81 unsafe extern "C" fn $rtc() {
82 use $crate::TimerQueueBackend;
83 $crate::nrf::rtc::$mono_backend::timer_queue().on_monotonic_interrupt();
84 }
85 };
86}
87
88#[doc(hidden)]
89#[macro_export]
90macro_rules! __internal_create_nrf_rtc_struct {
91 ($name:ident, $mono_backend:ident, $timer:ident) => {
92 pub struct $name;
94
95 impl $name {
96 pub fn start(rtc: $crate::nrf::rtc::$timer) {
100 $crate::__internal_create_nrf_rtc_interrupt!($mono_backend, $timer);
101
102 $crate::nrf::rtc::$mono_backend::_start(rtc);
103 }
104 }
105
106 impl $crate::TimerQueueBasedMonotonic for $name {
107 type Backend = $crate::nrf::rtc::$mono_backend;
108 type Instant = $crate::fugit::Instant<
109 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
110 1,
111 32_768,
112 >;
113 type Duration = $crate::fugit::Duration<
114 <Self::Backend as $crate::TimerQueueBackend>::Ticks,
115 1,
116 32_768,
117 >;
118 }
119
120 $crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
121 $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
122 };
123}
124
125#[macro_export]
129macro_rules! nrf_rtc0_monotonic {
130 ($name:ident) => {
131 $crate::__internal_create_nrf_rtc_struct!($name, Rtc0Backend, RTC0);
132 };
133}
134
135#[macro_export]
139macro_rules! nrf_rtc1_monotonic {
140 ($name:ident) => {
141 $crate::__internal_create_nrf_rtc_struct!($name, Rtc1Backend, RTC1);
142 };
143}
144
145#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
149#[cfg_attr(
150 docsrs,
151 doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
152)]
153#[macro_export]
154macro_rules! nrf_rtc2_monotonic {
155 ($name:ident) => {
156 $crate::__internal_create_nrf_rtc_struct!($name, Rtc2Backend, RTC2);
157 };
158}
159
160struct TimerValueU24(u32);
161impl rtic_time::half_period_counter::TimerValue for TimerValueU24 {
162 const BITS: u32 = 24;
163}
164impl From<TimerValueU24> for u64 {
165 fn from(value: TimerValueU24) -> Self {
166 Self::from(value.0)
167 }
168}
169
170macro_rules! make_rtc {
171 ($backend_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
172 $(
174 #[cfg_attr(docsrs, doc(cfg($($doc)*)))]
175 )?
176 pub struct $backend_name;
177
178 static $overflow: AtomicU32 = AtomicU32::new(0);
179 static $tq: TimerQueue<$backend_name> = TimerQueue::new();
180
181 impl $backend_name {
182 pub fn _start(rtc: $rtc) {
188 unsafe { rtc.prescaler.write(|w| w.bits(0)) };
189
190 rtc.intenclr.write(|w| w
192 .compare0().clear()
193 .compare1().clear()
194 .ovrflw().clear()
195 );
196
197 rtc.cc[0].write(|w| unsafe { w.bits(0) }); rtc.cc[1].write(|w| unsafe { w.bits(0x80_0000) }); critical_section::with(|_|{
203 rtc.tasks_clear.write(|w| unsafe { w.bits(1) });
205 rtc.tasks_start.write(|w| unsafe { w.bits(1) });
206
207 rtc.events_ovrflw.write(|w| w);
210 rtc.events_compare[0].write(|w| w);
211 rtc.events_compare[1].write(|w| w);
212
213 $overflow.store(0, Ordering::SeqCst);
215
216 $tq.initialize(Self {});
218
219 rtc.intenset.write(|w| w
222 .compare0().set()
223 .compare1().set()
224 .ovrflw().set()
225 );
226 rtc.evtenset.write(|w| w
227 .compare0().set()
228 .compare1().set()
229 .ovrflw().set()
230 );
231 });
232
233 unsafe {
237 crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, pac::Interrupt::$rtc);
238 pac::NVIC::unmask(pac::Interrupt::$rtc);
239 }
240 }
241 }
242
243 impl TimerQueueBackend for $backend_name {
244 type Ticks = u64;
245
246 fn now() -> Self::Ticks {
247 let rtc = unsafe { &*$rtc::PTR };
248 calculate_now(
249 || $overflow.load(Ordering::Relaxed),
250 || TimerValueU24(rtc.counter.read().bits())
251 )
252 }
253
254 fn on_interrupt() {
255 let rtc = unsafe { &*$rtc::PTR };
256 if rtc.events_ovrflw.read().bits() == 1 {
257 rtc.events_ovrflw.write(|w| unsafe { w.bits(0) });
258 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
259 assert!(prev % 2 == 1, "Monotonic must have skipped an interrupt!");
260 }
261 if rtc.events_compare[1].read().bits() == 1 {
262 rtc.events_compare[1].write(|w| unsafe { w.bits(0) });
263 let prev = $overflow.fetch_add(1, Ordering::Relaxed);
264 assert!(prev % 2 == 0, "Monotonic must have skipped an interrupt!");
265 }
266 }
267
268 fn set_compare(mut instant: Self::Ticks) {
269 let rtc = unsafe { &*$rtc::PTR };
270
271 const MAX: u64 = 0xff_ffff;
272
273 critical_section::with(|_|{
278 let now = Self::now();
279 let diff = instant.wrapping_sub(now);
281 let val = if diff <= MAX {
282 if diff < 3 {
288 instant = now.wrapping_add(3);
289 }
290
291 (instant & MAX) as u32
292 } else {
293 0
294 };
295
296 unsafe { rtc.cc[0].write(|w| w.bits(val)) };
297 });
298 }
299
300 fn clear_compare_flag() {
301 let rtc = unsafe { &*$rtc::PTR };
302 unsafe { rtc.events_compare[0].write(|w| w.bits(0)) };
303 }
304
305 fn pend_interrupt() {
306 pac::NVIC::pend(pac::Interrupt::$rtc);
307 }
308
309 fn timer_queue() -> &'static TimerQueue<Self> {
310 &$tq
311 }
312 }
313 };
314}
315
316make_rtc!(Rtc0Backend, RTC0, RTC0_OVERFLOWS, RTC0_TQ);
317make_rtc!(Rtc1Backend, RTC1, RTC1_OVERFLOWS, RTC1_TQ);
318#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
319make_rtc!(Rtc2Backend, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));