aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-12-08 23:27:32 +0100
committerDániel Buga <[email protected]>2024-12-13 21:20:59 +0100
commitb268b1795fed58544c166c41842ce0d66328aa3e (patch)
tree55b6fb09f6694b5e3355d344770b36bfe1550415 /embassy-nrf
parentec96395d084d5edc8be25ddaea8547e2ebd447a6 (diff)
Merge time-driver and time-queue-driver traits, make HALs own and handle the queue.
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/time_driver.rs115
1 files changed, 63 insertions, 52 deletions
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index f8b3c4bbc..a27fae9a8 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -1,11 +1,11 @@
1use core::cell::Cell; 1use core::cell::{Cell, RefCell};
2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
3 3
4use critical_section::CriticalSection; 4use critical_section::CriticalSection;
5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 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_time_driver::Driver; 7use embassy_time_driver::Driver;
8use embassy_time_queue_driver::GlobalTimerQueue; 8use embassy_time_queue_driver::Queue;
9 9
10use crate::interrupt::InterruptExt; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
@@ -111,11 +111,13 @@ struct RtcDriver {
111 period: AtomicU32, 111 period: AtomicU32,
112 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 112 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
113 alarms: Mutex<AlarmState>, 113 alarms: Mutex<AlarmState>,
114 queue: Mutex<RefCell<Queue>>,
114} 115}
115 116
116embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 117embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
117 period: AtomicU32::new(0), 118 period: AtomicU32::new(0),
118 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), 119 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
120 queue: Mutex::new(RefCell::new(Queue::new())),
119}); 121});
120 122
121impl RtcDriver { 123impl RtcDriver {
@@ -194,59 +196,60 @@ impl RtcDriver {
194 alarm.timestamp.set(u64::MAX); 196 alarm.timestamp.set(u64::MAX);
195 197
196 // Call after clearing alarm, so the callback can set another alarm. 198 // Call after clearing alarm, so the callback can set another alarm.
197 TIMER_QUEUE_DRIVER.dispatch(); 199 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
200 while !self.set_alarm(cs, next) {
201 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
202 }
198 } 203 }
199 204
200 fn set_alarm(&self, timestamp: u64) -> bool { 205 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
201 critical_section::with(|cs| { 206 let n = 0;
202 let n = 0; 207 let alarm = &self.alarms.borrow(cs);
203 let alarm = &self.alarms.borrow(cs); 208 alarm.timestamp.set(timestamp);
204 alarm.timestamp.set(timestamp);
205 209
206 let r = rtc(); 210 let r = rtc();
207 211
208 let t = self.now(); 212 let t = self.now();
209 if timestamp <= t { 213 if timestamp <= t {
210 // If alarm timestamp has passed the alarm will not fire. 214 // If alarm timestamp has passed the alarm will not fire.
211 // Disarm the alarm and return `false` to indicate that. 215 // Disarm the alarm and return `false` to indicate that.
212 r.intenclr().write(|w| w.0 = compare_n(n)); 216 r.intenclr().write(|w| w.0 = compare_n(n));
213 217
214 alarm.timestamp.set(u64::MAX); 218 alarm.timestamp.set(u64::MAX);
215 219
216 return false; 220 return false;
217 } 221 }
218 222
219 // If it hasn't triggered yet, setup it in the compare channel. 223 // If it hasn't triggered yet, setup it in the compare channel.
220 224
221 // Write the CC value regardless of whether we're going to enable it now or not. 225 // Write the CC value regardless of whether we're going to enable it now or not.
222 // This way, when we enable it later, the right value is already set. 226 // This way, when we enable it later, the right value is already set.
223 227
224 // nrf52 docs say: 228 // nrf52 docs say:
225 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. 229 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
226 // To workaround this, we never write a timestamp smaller than N+3. 230 // To workaround this, we never write a timestamp smaller than N+3.
227 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. 231 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
228 // 232 //
229 // It is impossible for rtc to tick more than once because 233 // It is impossible for rtc to tick more than once because
230 // - this code takes less time than 1 tick 234 // - this code takes less time than 1 tick
231 // - it runs with interrupts disabled so nothing else can preempt it. 235 // - it runs with interrupts disabled so nothing else can preempt it.
232 // 236 //
233 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed 237 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
234 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, 238 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
235 // and we don't do that here. 239 // and we don't do that here.
236 let safe_timestamp = timestamp.max(t + 3); 240 let safe_timestamp = timestamp.max(t + 3);
237 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); 241 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
238 242
239 let diff = timestamp - t; 243 let diff = timestamp - t;
240 if diff < 0xc00000 { 244 if diff < 0xc00000 {
241 r.intenset().write(|w| w.0 = compare_n(n)); 245 r.intenset().write(|w| w.0 = compare_n(n));
242 } else { 246 } else {
243 // If it's too far in the future, don't setup the compare channel yet. 247 // If it's too far in the future, don't setup the compare channel yet.
244 // It will be setup later by `next_period`. 248 // It will be setup later by `next_period`.
245 r.intenclr().write(|w| w.0 = compare_n(n)); 249 r.intenclr().write(|w| w.0 = compare_n(n));
246 } 250 }
247 251
248 true 252 true
249 })
250 } 253 }
251} 254}
252 255
@@ -258,6 +261,19 @@ impl Driver for RtcDriver {
258 let counter = rtc().counter().read().0; 261 let counter = rtc().counter().read().0;
259 calc_now(period, counter) 262 calc_now(period, counter)
260 } 263 }
264
265 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
266 critical_section::with(|cs| {
267 let mut queue = self.queue.borrow(cs).borrow_mut();
268
269 if queue.schedule_wake(at, waker) {
270 let mut next = queue.next_expiration(self.now());
271 while !self.set_alarm(cs, next) {
272 next = queue.next_expiration(self.now());
273 }
274 }
275 })
276 }
261} 277}
262 278
263#[cfg(feature = "_nrf54l")] 279#[cfg(feature = "_nrf54l")]
@@ -277,8 +293,3 @@ fn RTC1() {
277pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 293pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
278 DRIVER.init(irq_prio) 294 DRIVER.init(irq_prio)
279} 295}
280
281embassy_time_queue_driver::timer_queue_impl!(
282 static TIMER_QUEUE_DRIVER: GlobalTimerQueue
283 = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
284);