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