aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src/time_driver.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-nrf/src/time_driver.rs')
-rw-r--r--embassy-nrf/src/time_driver.rs156
1 files changed, 120 insertions, 36 deletions
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 03f4c2e2b..35f65bd64 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -1,28 +1,35 @@
1use core::cell::{Cell, RefCell}; 1use core::cell::{Cell, RefCell};
2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 2#[cfg(not(feature = "_grtc"))]
3use core::sync::atomic::{AtomicU32, Ordering, compiler_fence};
3 4
4use critical_section::CriticalSection; 5use critical_section::CriticalSection;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_time_driver::Driver; 8use embassy_time_driver::Driver;
8use embassy_time_queue_utils::Queue; 9use embassy_time_queue_utils::Queue;
9 10
10use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
12#[cfg(feature = "_grtc")]
13use crate::pac::grtc::vals::Busy;
11use crate::{interrupt, pac}; 14use crate::{interrupt, pac};
12 15
13#[cfg(feature = "_nrf54l")] 16#[cfg(feature = "_grtc")]
14fn rtc() -> pac::rtc::Rtc { 17fn rtc() -> pac::grtc::Grtc {
15 pac::RTC30 18 pac::GRTC
16} 19}
17#[cfg(not(feature = "_nrf54l"))] 20
21#[cfg(not(feature = "_grtc"))]
18fn rtc() -> pac::rtc::Rtc { 22fn rtc() -> pac::rtc::Rtc {
19 pac::RTC1 23 pac::RTC1
20} 24}
21 25
22/// Calculate the timestamp from the period count and the tick count. 26/// Calculate the timestamp from the period count and the tick count.
23/// 27///
24/// The RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes. This is 28/// For nRF54 devices and newer, the GRTC counter is 52 bits, so the time driver uses the
25/// too short. We must make it "never" overflow. 29/// syscounter and ignores the periods handling, since it overflows every 142 years.
30///
31/// For most other devices, the RTC counter is 24 bit. Ticking at 32768hz, it overflows every ~8 minutes.
32/// This is too short. We must make it "never" overflow.
26/// 33///
27/// The obvious way would be to count overflow periods. Every time the counter overflows, 34/// The obvious way would be to count overflow periods. Every time the counter overflows,
28/// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic 35/// increase a `periods` variable. `now()` simply does `periods << 24 + counter`. So, the logic
@@ -64,14 +71,39 @@ fn rtc() -> pac::rtc::Rtc {
64/// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865 71/// `period` is a 32bit integer, so It overflows on 2^32 * 2^23 / 32768 seconds of uptime, which is 34865
65/// years. For comparison, flash memory like the one containing your firmware is usually rated to retain 72/// years. For comparison, flash memory like the one containing your firmware is usually rated to retain
66/// data for only 10-20 years. 34865 years is long enough! 73/// data for only 10-20 years. 34865 years is long enough!
74#[cfg(not(feature = "_grtc"))]
67fn calc_now(period: u32, counter: u32) -> u64 { 75fn calc_now(period: u32, counter: u32) -> u64 {
68 ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64) 76 ((period as u64) << 23) + ((counter ^ ((period & 1) << 23)) as u64)
69} 77}
70 78
79#[cfg(feature = "_grtc")]
80fn syscounter() -> u64 {
81 let r = rtc();
82 r.syscounter(0).active().write(|w| w.set_active(true));
83 loop {
84 let countl: u32 = r.syscounter(0).syscounterl().read();
85 let counth = r.syscounter(0).syscounterh().read();
86
87 if counth.busy() == Busy::READY && !counth.overflow() {
88 let counth: u32 = counth.value();
89 let count = countl as u64 | ((counth as u64) << 32);
90 r.syscounter(0).active().write(|w| w.set_active(false));
91 return count;
92 }
93 // If overflow or not ready, loop will re-read both registers
94 }
95}
96
97#[cfg(not(feature = "_grtc"))]
71fn compare_n(n: usize) -> u32 { 98fn compare_n(n: usize) -> u32 {
72 1 << (n + 16) 99 1 << (n + 16)
73} 100}
74 101
102#[cfg(feature = "_grtc")]
103fn compare_n(n: usize) -> u32 {
104 1 << n // GRTC uses bits 0-11 for COMPARE[0-11]
105}
106
75#[cfg(test)] 107#[cfg(test)]
76mod test { 108mod test {
77 use super::*; 109 use super::*;
@@ -108,6 +140,7 @@ impl AlarmState {
108 140
109struct RtcDriver { 141struct RtcDriver {
110 /// Number of 2^23 periods elapsed since boot. 142 /// Number of 2^23 periods elapsed since boot.
143 #[cfg(not(feature = "_grtc"))]
111 period: AtomicU32, 144 period: AtomicU32,
112 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 145 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
113 alarms: Mutex<AlarmState>, 146 alarms: Mutex<AlarmState>,
@@ -115,6 +148,7 @@ struct RtcDriver {
115} 148}
116 149
117embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 150embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
151 #[cfg(not(feature = "_grtc"))]
118 period: AtomicU32::new(0), 152 period: AtomicU32::new(0),
119 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 153 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
120 queue: Mutex::new(RefCell::new(Queue::new())), 154 queue: Mutex::new(RefCell::new(Queue::new())),
@@ -123,25 +157,43 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
123impl RtcDriver { 157impl RtcDriver {
124 fn init(&'static self, irq_prio: crate::interrupt::Priority) { 158 fn init(&'static self, irq_prio: crate::interrupt::Priority) {
125 let r = rtc(); 159 let r = rtc();
126 r.cc(3).write(|w| w.set_compare(0x800000)); 160 // Chips without GRTC needs to deal with overflow
161 #[cfg(not(feature = "_grtc"))]
162 {
163 r.cc(3).write(|w| w.set_compare(0x800000));
127 164
128 r.intenset().write(|w| { 165 r.intenset().write(|w| {
129 w.set_ovrflw(true); 166 w.set_ovrflw(true);
130 w.set_compare(3, true); 167 w.set_compare(3, true);
131 }); 168 });
169 }
132 170
171 #[cfg(feature = "_grtc")]
172 {
173 r.mode().write(|w| {
174 w.set_syscounteren(true);
175 });
176 }
133 r.tasks_clear().write_value(1); 177 r.tasks_clear().write_value(1);
134 r.tasks_start().write_value(1); 178 r.tasks_start().write_value(1);
135 179
136 // Wait for clear 180 // Wait for clear
181 #[cfg(not(feature = "_grtc"))]
137 while r.counter().read().0 != 0 {} 182 while r.counter().read().0 != 0 {}
138 183
139 #[cfg(feature = "_nrf54l")] 184 #[cfg(feature = "_grtc")]
185 loop {
186 if r.status().lftimer().read().ready() {
187 break;
188 }
189 }
190
191 #[cfg(feature = "_grtc")]
140 { 192 {
141 interrupt::RTC30.set_priority(irq_prio); 193 interrupt::GRTC_1.set_priority(irq_prio);
142 unsafe { interrupt::RTC30.enable() }; 194 unsafe { interrupt::GRTC_1.enable() };
143 } 195 }
144 #[cfg(not(feature = "_nrf54l"))] 196 #[cfg(not(feature = "_grtc"))]
145 { 197 {
146 interrupt::RTC1.set_priority(irq_prio); 198 interrupt::RTC1.set_priority(irq_prio);
147 unsafe { interrupt::RTC1.enable() }; 199 unsafe { interrupt::RTC1.enable() };
@@ -150,11 +202,14 @@ impl RtcDriver {
150 202
151 fn on_interrupt(&self) { 203 fn on_interrupt(&self) {
152 let r = rtc(); 204 let r = rtc();
205
206 #[cfg(not(feature = "_grtc"))]
153 if r.events_ovrflw().read() == 1 { 207 if r.events_ovrflw().read() == 1 {
154 r.events_ovrflw().write_value(0); 208 r.events_ovrflw().write_value(0);
155 self.next_period(); 209 self.next_period();
156 } 210 }
157 211
212 #[cfg(not(feature = "_grtc"))]
158 if r.events_compare(3).read() == 1 { 213 if r.events_compare(3).read() == 1 {
159 r.events_compare(3).write_value(0); 214 r.events_compare(3).write_value(0);
160 self.next_period(); 215 self.next_period();
@@ -169,6 +224,7 @@ impl RtcDriver {
169 } 224 }
170 } 225 }
171 226
227 #[cfg(not(feature = "_grtc"))]
172 fn next_period(&self) { 228 fn next_period(&self) {
173 critical_section::with(|cs| { 229 critical_section::with(|cs| {
174 let r = rtc(); 230 let r = rtc();
@@ -190,7 +246,10 @@ impl RtcDriver {
190 fn trigger_alarm(&self, cs: CriticalSection) { 246 fn trigger_alarm(&self, cs: CriticalSection) {
191 let n = 0; 247 let n = 0;
192 let r = rtc(); 248 let r = rtc();
249 #[cfg(not(feature = "_grtc"))]
193 r.intenclr().write(|w| w.0 = compare_n(n)); 250 r.intenclr().write(|w| w.0 = compare_n(n));
251 #[cfg(feature = "_grtc")]
252 r.intenclr(1).write(|w| w.0 = compare_n(n));
194 253
195 let alarm = &self.alarms.borrow(cs); 254 let alarm = &self.alarms.borrow(cs);
196 alarm.timestamp.set(u64::MAX); 255 alarm.timestamp.set(u64::MAX);
@@ -214,7 +273,10 @@ impl RtcDriver {
214 if timestamp <= t { 273 if timestamp <= t {
215 // If alarm timestamp has passed the alarm will not fire. 274 // If alarm timestamp has passed the alarm will not fire.
216 // Disarm the alarm and return `false` to indicate that. 275 // Disarm the alarm and return `false` to indicate that.
276 #[cfg(not(feature = "_grtc"))]
217 r.intenclr().write(|w| w.0 = compare_n(n)); 277 r.intenclr().write(|w| w.0 = compare_n(n));
278 #[cfg(feature = "_grtc")]
279 r.intenclr(1).write(|w| w.0 = compare_n(n));
218 280
219 alarm.timestamp.set(u64::MAX); 281 alarm.timestamp.set(u64::MAX);
220 282
@@ -226,7 +288,7 @@ impl RtcDriver {
226 // Write the CC value regardless of whether we're going to enable it now or not. 288 // Write the CC value regardless of whether we're going to enable it now or not.
227 // This way, when we enable it later, the right value is already set. 289 // This way, when we enable it later, the right value is already set.
228 290
229 // nrf52 docs say: 291 // nrf52 docs say :
230 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. 292 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
231 // To workaround this, we never write a timestamp smaller than N+3. 293 // To workaround this, we never write a timestamp smaller than N+3.
232 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. 294 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
@@ -238,22 +300,39 @@ impl RtcDriver {
238 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed 300 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
239 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, 301 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
240 // and we don't do that here. 302 // and we don't do that here.
241 let safe_timestamp = timestamp.max(t + 3); 303 #[cfg(not(feature = "_grtc"))]
242 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); 304 {
243 305 let safe_timestamp = timestamp.max(t + 3);
244 let diff = timestamp - t; 306 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
245 if diff < 0xc00000 { 307 let diff = timestamp - t;
246 r.intenset().write(|w| w.0 = compare_n(n)); 308 if diff < 0xc00000 {
247 309 r.intenset().write(|w| w.0 = compare_n(n));
248 // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, 310
249 // we need to retry setting the alarm. 311 // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise,
250 if self.now() + 2 <= timestamp { 312 // we need to retry setting the alarm.
313 if self.now() + 2 <= timestamp {
314 return true;
315 }
316 } else {
317 // If it's too far in the future, don't setup the compare channel yet.
318 // It will be setup later by `next_period`.
319 r.intenclr().write(|w| w.0 = compare_n(n));
251 return true; 320 return true;
252 } 321 }
253 } else { 322 }
254 // If it's too far in the future, don't setup the compare channel yet. 323
255 // It will be setup later by `next_period`. 324 // The nRF54 datasheet states that 'The EVENTS_COMPARE[n] event is generated immediately if the
256 r.intenclr().write(|w| w.0 = compare_n(n)); 325 // configured compare value at CC[n] is less than the current SYSCOUNTER value.'. This means we
326 // can write the expected timestamp and be sure the alarm is triggered.
327 #[cfg(feature = "_grtc")]
328 {
329 let ccl = timestamp as u32;
330 let cch = (timestamp >> 32) as u32 & 0xFFFFF; // 20 bits for CCH
331
332 r.cc(n).ccl().write_value(ccl);
333 r.cc(n).cch().write(|w| w.set_cch(cch));
334 r.intenset(1).write(|w| w.0 = compare_n(n));
335
257 return true; 336 return true;
258 } 337 }
259 } 338 }
@@ -261,6 +340,7 @@ impl RtcDriver {
261} 340}
262 341
263impl Driver for RtcDriver { 342impl Driver for RtcDriver {
343 #[cfg(not(feature = "_grtc"))]
264 fn now(&self) -> u64 { 344 fn now(&self) -> u64 {
265 // `period` MUST be read before `counter`, see comment at the top for details. 345 // `period` MUST be read before `counter`, see comment at the top for details.
266 let period = self.period.load(Ordering::Relaxed); 346 let period = self.period.load(Ordering::Relaxed);
@@ -269,10 +349,14 @@ impl Driver for RtcDriver {
269 calc_now(period, counter) 349 calc_now(period, counter)
270 } 350 }
271 351
352 #[cfg(feature = "_grtc")]
353 fn now(&self) -> u64 {
354 syscounter()
355 }
356
272 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { 357 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
273 critical_section::with(|cs| { 358 critical_section::with(|cs| {
274 let mut queue = self.queue.borrow(cs).borrow_mut(); 359 let mut queue = self.queue.borrow(cs).borrow_mut();
275
276 if queue.schedule_wake(at, waker) { 360 if queue.schedule_wake(at, waker) {
277 let mut next = queue.next_expiration(self.now()); 361 let mut next = queue.next_expiration(self.now());
278 while !self.set_alarm(cs, next) { 362 while !self.set_alarm(cs, next) {
@@ -283,14 +367,14 @@ impl Driver for RtcDriver {
283 } 367 }
284} 368}
285 369
286#[cfg(feature = "_nrf54l")] 370#[cfg(feature = "_grtc")]
287#[cfg(feature = "rt")] 371#[cfg(feature = "rt")]
288#[interrupt] 372#[interrupt]
289fn RTC30() { 373fn GRTC_1() {
290 DRIVER.on_interrupt() 374 DRIVER.on_interrupt()
291} 375}
292 376
293#[cfg(not(feature = "_nrf54l"))] 377#[cfg(not(feature = "_grtc"))]
294#[cfg(feature = "rt")] 378#[cfg(feature = "rt")]
295#[interrupt] 379#[interrupt]
296fn RTC1() { 380fn RTC1() {