diff options
| author | Dániel Buga <[email protected]> | 2024-11-26 23:54:21 +0100 |
|---|---|---|
| committer | Dániel Buga <[email protected]> | 2024-12-10 21:31:42 +0100 |
| commit | 5a5495aac43d75610735f2ca80fb6c8e8f31ed71 (patch) | |
| tree | 7a4336917894730692589359e9d1a285ec5a0a05 /embassy-nrf | |
| parent | 406d377b7564d16e12b7fae4f42c0c709bf4f243 (diff) | |
Refactor integrated-timers
Diffstat (limited to 'embassy-nrf')
| -rw-r--r-- | embassy-nrf/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/time_driver.rs | 117 |
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] |
| 137 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } | 137 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } |
| 138 | embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } | ||
| 138 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } | 139 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } |
| 139 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } | 140 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } |
| 140 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } | 141 | embassy-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 @@ | |||
| 1 | use core::cell::Cell; | 1 | use core::cell::Cell; |
| 2 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; | 2 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 3 | use core::{mem, ptr}; | ||
| 4 | 3 | ||
| 5 | use critical_section::CriticalSection; | 4 | use critical_section::CriticalSection; |
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; | 6 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; |
| 8 | use embassy_time_driver::{AlarmHandle, Driver}; | 7 | use embassy_time_driver::Driver; |
| 8 | use embassy_time_queue_driver::GlobalTimerQueue; | ||
| 9 | 9 | ||
| 10 | use crate::interrupt::InterruptExt; | 10 | use crate::interrupt::InterruptExt; |
| 11 | use crate::{interrupt, pac}; | 11 | use crate::{interrupt, pac}; |
| @@ -94,11 +94,6 @@ mod test { | |||
| 94 | 94 | ||
| 95 | struct AlarmState { | 95 | struct 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 | ||
| 104 | unsafe impl Send for AlarmState {} | 99 | unsafe 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 | ||
| 116 | const ALARM_COUNT: usize = 3; | ||
| 117 | |||
| 118 | struct RtcDriver { | 109 | struct 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 | ||
| 126 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 116 | embassy_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 | ||
| 132 | impl RtcDriver { | 121 | impl 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 | |||
| 224 | impl 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 | ||
| 253 | impl 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() { | |||
| 321 | pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | 277 | pub(crate) fn init(irq_prio: crate::interrupt::Priority) { |
| 322 | DRIVER.init(irq_prio) | 278 | DRIVER.init(irq_prio) |
| 323 | } | 279 | } |
| 280 | |||
| 281 | embassy_time_queue_driver::timer_queue_impl!( | ||
| 282 | static TIMER_QUEUE_DRIVER: GlobalTimerQueue | ||
| 283 | = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) | ||
| 284 | ); | ||
