aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorDániel Buga <[email protected]>2024-11-26 23:54:21 +0100
committerDániel Buga <[email protected]>2024-12-10 21:31:42 +0100
commit5a5495aac43d75610735f2ca80fb6c8e8f31ed71 (patch)
tree7a4336917894730692589359e9d1a285ec5a0a05 /embassy-nrf
parent406d377b7564d16e12b7fae4f42c0c709bf4f243 (diff)
Refactor integrated-timers
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/Cargo.toml3
-rw-r--r--embassy-nrf/src/time_driver.rs117
2 files changed, 41 insertions, 79 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 9da050a22..48f80bb5e 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -119,7 +119,7 @@ _nrf52 = ["_ppi"]
119_nrf51 = ["_ppi"] 119_nrf51 = ["_ppi"]
120_nrf91 = [] 120_nrf91 = []
121 121
122_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] 122_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-driver"]
123 123
124# trustzone state. 124# trustzone state.
125_s = [] 125_s = []
@@ -135,6 +135,7 @@ _nrf52832_anomaly_109 = []
135 135
136[dependencies] 136[dependencies]
137embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 137embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
138embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true }
138embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } 139embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
139embassy-sync = { version = "0.6.1", path = "../embassy-sync" } 140embassy-sync = { version = "0.6.1", path = "../embassy-sync" }
140embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } 141embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 9ba38ec1b..f8b3c4bbc 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;
2use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
3use core::{mem, ptr};
4 3
5use critical_section::CriticalSection; 4use critical_section::CriticalSection;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
8use embassy_time_driver::{AlarmHandle, Driver}; 7use embassy_time_driver::Driver;
8use embassy_time_queue_driver::GlobalTimerQueue;
9 9
10use crate::interrupt::InterruptExt; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
@@ -94,11 +94,6 @@ mod test {
94 94
95struct AlarmState { 95struct AlarmState {
96 timestamp: Cell<u64>, 96 timestamp: Cell<u64>,
97
98 // This is really a Option<(fn(*mut ()), *mut ())>
99 // but fn pointers aren't allowed in const yet
100 callback: Cell<*const ()>,
101 ctx: Cell<*mut ()>,
102} 97}
103 98
104unsafe impl Send for AlarmState {} 99unsafe impl Send for AlarmState {}
@@ -107,26 +102,20 @@ impl AlarmState {
107 const fn new() -> Self { 102 const fn new() -> Self {
108 Self { 103 Self {
109 timestamp: Cell::new(u64::MAX), 104 timestamp: Cell::new(u64::MAX),
110 callback: Cell::new(ptr::null()),
111 ctx: Cell::new(ptr::null_mut()),
112 } 105 }
113 } 106 }
114} 107}
115 108
116const ALARM_COUNT: usize = 3;
117
118struct RtcDriver { 109struct RtcDriver {
119 /// Number of 2^23 periods elapsed since boot. 110 /// Number of 2^23 periods elapsed since boot.
120 period: AtomicU32, 111 period: AtomicU32,
121 alarm_count: AtomicU8,
122 /// 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.
123 alarms: Mutex<[AlarmState; ALARM_COUNT]>, 113 alarms: Mutex<AlarmState>,
124} 114}
125 115
126embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 116embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
127 period: AtomicU32::new(0), 117 period: AtomicU32::new(0),
128 alarm_count: AtomicU8::new(0), 118 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
129 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const {AlarmState::new()}; ALARM_COUNT]),
130}); 119});
131 120
132impl RtcDriver { 121impl RtcDriver {
@@ -169,13 +158,12 @@ impl RtcDriver {
169 self.next_period(); 158 self.next_period();
170 } 159 }
171 160
172 for n in 0..ALARM_COUNT { 161 let n = 0;
173 if r.events_compare(n).read() == 1 { 162 if r.events_compare(n).read() == 1 {
174 r.events_compare(n).write_value(0); 163 r.events_compare(n).write_value(0);
175 critical_section::with(|cs| { 164 critical_section::with(|cs| {
176 self.trigger_alarm(n, cs); 165 self.trigger_alarm(cs);
177 }) 166 });
178 }
179 } 167 }
180 } 168 }
181 169
@@ -186,75 +174,33 @@ impl RtcDriver {
186 self.period.store(period, Ordering::Relaxed); 174 self.period.store(period, Ordering::Relaxed);
187 let t = (period as u64) << 23; 175 let t = (period as u64) << 23;
188 176
189 for n in 0..ALARM_COUNT { 177 let n = 0;
190 let alarm = &self.alarms.borrow(cs)[n]; 178 let alarm = &self.alarms.borrow(cs);
191 let at = alarm.timestamp.get(); 179 let at = alarm.timestamp.get();
192 180
193 if at < t + 0xc00000 { 181 if at < t + 0xc00000 {
194 // just enable it. `set_alarm` has already set the correct CC val. 182 // just enable it. `set_alarm` has already set the correct CC val.
195 r.intenset().write(|w| w.0 = compare_n(n)); 183 r.intenset().write(|w| w.0 = compare_n(n));
196 }
197 } 184 }
198 }) 185 })
199 } 186 }
200 187
201 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 188 fn trigger_alarm(&self, cs: CriticalSection) {
202 // safety: we're allowed to assume the AlarmState is created by us, and 189 let n = 0;
203 // we never create one that's out of bounds.
204 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
205 }
206
207 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
208 let r = rtc(); 190 let r = rtc();
209 r.intenclr().write(|w| w.0 = compare_n(n)); 191 r.intenclr().write(|w| w.0 = compare_n(n));
210 192
211 let alarm = &self.alarms.borrow(cs)[n]; 193 let alarm = &self.alarms.borrow(cs);
212 alarm.timestamp.set(u64::MAX); 194 alarm.timestamp.set(u64::MAX);
213 195
214 // Call after clearing alarm, so the callback can set another alarm. 196 // Call after clearing alarm, so the callback can set another alarm.
215 197 TIMER_QUEUE_DRIVER.dispatch();
216 // safety:
217 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
218 // - other than that we only store valid function pointers into alarm.callback
219 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
220 f(alarm.ctx.get());
221 }
222}
223
224impl Driver for RtcDriver {
225 fn now(&self) -> u64 {
226 // `period` MUST be read before `counter`, see comment at the top for details.
227 let period = self.period.load(Ordering::Relaxed);
228 compiler_fence(Ordering::Acquire);
229 let counter = rtc().counter().read().0;
230 calc_now(period, counter)
231 }
232
233 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
234 critical_section::with(|_| {
235 let id = self.alarm_count.load(Ordering::Relaxed);
236 if id < ALARM_COUNT as u8 {
237 self.alarm_count.store(id + 1, Ordering::Relaxed);
238 Some(AlarmHandle::new(id))
239 } else {
240 None
241 }
242 })
243 }
244
245 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
246 critical_section::with(|cs| {
247 let alarm = self.get_alarm(cs, alarm);
248
249 alarm.callback.set(callback as *const ());
250 alarm.ctx.set(ctx);
251 })
252 } 198 }
253 199
254 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 200 fn set_alarm(&self, timestamp: u64) -> bool {
255 critical_section::with(|cs| { 201 critical_section::with(|cs| {
256 let n = alarm.id() as _; 202 let n = 0;
257 let alarm = self.get_alarm(cs, alarm); 203 let alarm = &self.alarms.borrow(cs);
258 alarm.timestamp.set(timestamp); 204 alarm.timestamp.set(timestamp);
259 205
260 let r = rtc(); 206 let r = rtc();
@@ -304,6 +250,16 @@ impl Driver for RtcDriver {
304 } 250 }
305} 251}
306 252
253impl Driver for RtcDriver {
254 fn now(&self) -> u64 {
255 // `period` MUST be read before `counter`, see comment at the top for details.
256 let period = self.period.load(Ordering::Relaxed);
257 compiler_fence(Ordering::Acquire);
258 let counter = rtc().counter().read().0;
259 calc_now(period, counter)
260 }
261}
262
307#[cfg(feature = "_nrf54l")] 263#[cfg(feature = "_nrf54l")]
308#[cfg(feature = "rt")] 264#[cfg(feature = "rt")]
309#[interrupt] 265#[interrupt]
@@ -321,3 +277,8 @@ fn RTC1() {
321pub(crate) fn init(irq_prio: crate::interrupt::Priority) { 277pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
322 DRIVER.init(irq_prio) 278 DRIVER.init(irq_prio)
323} 279}
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);