diff options
| -rw-r--r-- | embassy-nrf/src/rtc.rs | 93 | ||||
| -rw-r--r-- | embassy/src/executor.rs | 3 | ||||
| -rw-r--r-- | embassy/src/time.rs | 6 | ||||
| -rw-r--r-- | examples/src/bin/rtc_raw.rs | 3 |
4 files changed, 75 insertions, 30 deletions
diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs index ddb4fd367..f28ad1dad 100644 --- a/embassy-nrf/src/rtc.rs +++ b/embassy-nrf/src/rtc.rs | |||
| @@ -3,7 +3,7 @@ use core::ops::Deref; | |||
| 3 | use core::sync::atomic::{AtomicU32, Ordering}; | 3 | use core::sync::atomic::{AtomicU32, Ordering}; |
| 4 | 4 | ||
| 5 | use crate::interrupt; | 5 | use crate::interrupt; |
| 6 | use crate::interrupt::Mutex; | 6 | use crate::interrupt::{CriticalSection, Mutex}; |
| 7 | use crate::pac::{rtc0, Interrupt, RTC0, RTC1}; | 7 | use crate::pac::{rtc0, Interrupt, RTC0, RTC1}; |
| 8 | 8 | ||
| 9 | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] | 9 | #[cfg(any(feature = "52832", feature = "52833", feature = "52840"))] |
| @@ -34,6 +34,22 @@ mod test { | |||
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | struct AlarmState { | ||
| 38 | timestamp: Cell<u64>, | ||
| 39 | callback: Cell<Option<fn()>>, | ||
| 40 | } | ||
| 41 | |||
| 42 | impl AlarmState { | ||
| 43 | fn new() -> Self { | ||
| 44 | Self { | ||
| 45 | timestamp: Cell::new(u64::MAX), | ||
| 46 | callback: Cell::new(None), | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | const ALARM_COUNT: usize = 3; | ||
| 52 | |||
| 37 | pub struct RTC<T> { | 53 | pub struct RTC<T> { |
| 38 | rtc: T, | 54 | rtc: T, |
| 39 | 55 | ||
| @@ -50,7 +66,7 @@ pub struct RTC<T> { | |||
| 50 | period: AtomicU32, | 66 | period: AtomicU32, |
| 51 | 67 | ||
| 52 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | 68 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. |
| 53 | alarm: Mutex<Cell<(u64, Option<fn()>)>>, | 69 | alarms: Mutex<[AlarmState; ALARM_COUNT]>, |
| 54 | } | 70 | } |
| 55 | 71 | ||
| 56 | unsafe impl<T> Send for RTC<T> {} | 72 | unsafe impl<T> Send for RTC<T> {} |
| @@ -61,7 +77,7 @@ impl<T: Instance> RTC<T> { | |||
| 61 | Self { | 77 | Self { |
| 62 | rtc, | 78 | rtc, |
| 63 | period: AtomicU32::new(0), | 79 | period: AtomicU32::new(0), |
| 64 | alarm: Mutex::new(Cell::new((u64::MAX, None))), | 80 | alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]), |
| 65 | } | 81 | } |
| 66 | } | 82 | } |
| 67 | 83 | ||
| @@ -101,9 +117,13 @@ impl<T: Instance> RTC<T> { | |||
| 101 | self.next_period(); | 117 | self.next_period(); |
| 102 | } | 118 | } |
| 103 | 119 | ||
| 104 | if self.rtc.events_compare[1].read().bits() == 1 { | 120 | for n in 0..ALARM_COUNT { |
| 105 | self.rtc.events_compare[1].write(|w| w); | 121 | if self.rtc.events_compare[n + 1].read().bits() == 1 { |
| 106 | self.trigger_alarm(); | 122 | self.rtc.events_compare[n + 1].write(|w| w); |
| 123 | interrupt::free(|cs| { | ||
| 124 | self.trigger_alarm(n, cs); | ||
| 125 | }) | ||
| 126 | } | ||
| 107 | } | 127 | } |
| 108 | } | 128 | } |
| 109 | 129 | ||
| @@ -112,35 +132,43 @@ impl<T: Instance> RTC<T> { | |||
| 112 | let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; | 132 | let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; |
| 113 | let t = (period as u64) << 23; | 133 | let t = (period as u64) << 23; |
| 114 | 134 | ||
| 115 | let (at, _) = self.alarm.borrow(cs).get(); | 135 | for alarm in self.alarms.borrow(cs) { |
| 136 | let at = alarm.timestamp.get(); | ||
| 116 | 137 | ||
| 117 | let diff = at - t; | 138 | let diff = at - t; |
| 118 | if diff < 0xc00000 { | 139 | if diff < 0xc00000 { |
| 119 | self.rtc.cc[1].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) }); | 140 | self.rtc.cc[1].write(|w| unsafe { w.bits(at as u32 & 0xFFFFFF) }); |
| 120 | self.rtc.intenset.write(|w| w.compare1().set()); | 141 | self.rtc.intenset.write(|w| w.compare1().set()); |
| 142 | } | ||
| 121 | } | 143 | } |
| 122 | }) | 144 | }) |
| 123 | } | 145 | } |
| 124 | 146 | ||
| 125 | fn trigger_alarm(&self) { | 147 | fn trigger_alarm(&self, n: usize, cs: &CriticalSection) { |
| 126 | self.rtc.intenclr.write(|w| w.compare1().clear()); | 148 | self.rtc.intenclr.write(|w| w.compare1().clear()); |
| 127 | interrupt::free(|cs| { | ||
| 128 | let alarm = self.alarm.borrow(cs); | ||
| 129 | let (_, f) = alarm.get(); | ||
| 130 | alarm.set((u64::MAX, None)); | ||
| 131 | 149 | ||
| 132 | // Call after clearing alarm, so the callback can set another alarm. | 150 | let alarm = &self.alarms.borrow(cs)[n]; |
| 133 | f.map(|f| f()) | 151 | alarm.timestamp.set(u64::MAX); |
| 134 | }); | 152 | |
| 153 | // Call after clearing alarm, so the callback can set another alarm. | ||
| 154 | alarm.callback.get().map(|f| f()); | ||
| 135 | } | 155 | } |
| 136 | 156 | ||
| 137 | fn do_set_alarm(&self, timestamp: u64, callback: Option<fn()>) { | 157 | fn set_alarm_callback(&self, n: usize, callback: fn()) { |
| 138 | interrupt::free(|cs| { | 158 | interrupt::free(|cs| { |
| 139 | self.alarm.borrow(cs).set((timestamp, callback)); | 159 | let alarm = &self.alarms.borrow(cs)[n]; |
| 160 | alarm.callback.set(Some(callback)); | ||
| 161 | }) | ||
| 162 | } | ||
| 163 | |||
| 164 | fn set_alarm(&self, n: usize, timestamp: u64) { | ||
| 165 | interrupt::free(|cs| { | ||
| 166 | let alarm = &self.alarms.borrow(cs)[n]; | ||
| 167 | alarm.timestamp.set(timestamp); | ||
| 140 | 168 | ||
| 141 | let t = self.now(); | 169 | let t = self.now(); |
| 142 | if timestamp <= t { | 170 | if timestamp <= t { |
| 143 | self.trigger_alarm(); | 171 | self.trigger_alarm(n, cs); |
| 144 | return; | 172 | return; |
| 145 | } | 173 | } |
| 146 | 174 | ||
| @@ -155,7 +183,7 @@ impl<T: Instance> RTC<T> { | |||
| 155 | 183 | ||
| 156 | let t = self.now(); | 184 | let t = self.now(); |
| 157 | if timestamp <= t { | 185 | if timestamp <= t { |
| 158 | self.trigger_alarm(); | 186 | self.trigger_alarm(n, cs); |
| 159 | return; | 187 | return; |
| 160 | } | 188 | } |
| 161 | } else { | 189 | } else { |
| @@ -165,21 +193,32 @@ impl<T: Instance> RTC<T> { | |||
| 165 | } | 193 | } |
| 166 | 194 | ||
| 167 | pub fn alarm0(&'static self) -> Alarm<T> { | 195 | pub fn alarm0(&'static self) -> Alarm<T> { |
| 168 | Alarm { rtc: self } | 196 | Alarm { n: 0, rtc: self } |
| 197 | } | ||
| 198 | pub fn alarm1(&'static self) -> Alarm<T> { | ||
| 199 | Alarm { n: 1, rtc: self } | ||
| 200 | } | ||
| 201 | pub fn alarm2(&'static self) -> Alarm<T> { | ||
| 202 | Alarm { n: 2, rtc: self } | ||
| 169 | } | 203 | } |
| 170 | } | 204 | } |
| 171 | 205 | ||
| 172 | pub struct Alarm<T: Instance> { | 206 | pub struct Alarm<T: Instance> { |
| 207 | n: usize, | ||
| 173 | rtc: &'static RTC<T>, | 208 | rtc: &'static RTC<T>, |
| 174 | } | 209 | } |
| 175 | 210 | ||
| 176 | impl<T: Instance> embassy::time::Alarm for Alarm<T> { | 211 | impl<T: Instance> embassy::time::Alarm for Alarm<T> { |
| 177 | fn set(&self, timestamp: u64, callback: fn()) { | 212 | fn set_callback(&self, callback: fn()) { |
| 178 | self.rtc.do_set_alarm(timestamp, Some(callback)); | 213 | self.rtc.set_alarm_callback(self.n, callback); |
| 214 | } | ||
| 215 | |||
| 216 | fn set(&self, timestamp: u64) { | ||
| 217 | self.rtc.set_alarm(self.n, timestamp); | ||
| 179 | } | 218 | } |
| 180 | 219 | ||
| 181 | fn clear(&self) { | 220 | fn clear(&self) { |
| 182 | self.rtc.do_set_alarm(u64::MAX, None); | 221 | self.rtc.set_alarm(self.n, u64::MAX); |
| 183 | } | 222 | } |
| 184 | } | 223 | } |
| 185 | 224 | ||
diff --git a/embassy/src/executor.rs b/embassy/src/executor.rs index c5d024f7b..2c7cc5786 100644 --- a/embassy/src/executor.rs +++ b/embassy/src/executor.rs | |||
| @@ -27,6 +27,7 @@ pub struct Executor<M, A: Alarm> { | |||
| 27 | 27 | ||
| 28 | impl<M: Model, A: Alarm> Executor<M, A> { | 28 | impl<M: Model, A: Alarm> Executor<M, A> { |
| 29 | pub fn new(alarm: A) -> Self { | 29 | pub fn new(alarm: A) -> Self { |
| 30 | alarm.set_callback(M::signal); | ||
| 30 | Self { | 31 | Self { |
| 31 | inner: se::Executor::new(M::signal), | 32 | inner: se::Executor::new(M::signal), |
| 32 | alarm, | 33 | alarm, |
| @@ -53,7 +54,7 @@ impl<M: Model, A: Alarm> Executor<M, A> { | |||
| 53 | match self.timer.next_expiration() { | 54 | match self.timer.next_expiration() { |
| 54 | // If this is in the past, set_alarm will immediately trigger the alarm, | 55 | // If this is in the past, set_alarm will immediately trigger the alarm, |
| 55 | // which will make the wfe immediately return so we do another loop iteration. | 56 | // which will make the wfe immediately return so we do another loop iteration. |
| 56 | Some(at) => self.alarm.set(at, M::signal), | 57 | Some(at) => self.alarm.set(at), |
| 57 | None => self.alarm.clear(), | 58 | None => self.alarm.clear(), |
| 58 | } | 59 | } |
| 59 | }) | 60 | }) |
diff --git a/embassy/src/time.rs b/embassy/src/time.rs index 30fd1b680..eba2e6eb2 100644 --- a/embassy/src/time.rs +++ b/embassy/src/time.rs | |||
| @@ -273,13 +273,17 @@ impl Future for Timer { | |||
| 273 | 273 | ||
| 274 | /// Trait to register a callback at a given timestamp. | 274 | /// Trait to register a callback at a given timestamp. |
| 275 | pub trait Alarm { | 275 | pub trait Alarm { |
| 276 | /// Sets the callback function to be called when the alarm triggers. | ||
| 277 | /// The callback may be called from any context (interrupt or thread mode). | ||
| 278 | fn set_callback(&self, callback: fn()); | ||
| 279 | |||
| 276 | /// Sets an alarm at the given timestamp. When the clock reaches that | 280 | /// Sets an alarm at the given timestamp. When the clock reaches that |
| 277 | /// timestamp, the provided callback funcion will be called. | 281 | /// timestamp, the provided callback funcion will be called. |
| 278 | /// | 282 | /// |
| 279 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. | 283 | /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. |
| 280 | /// | 284 | /// |
| 281 | /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any. | 285 | /// Only one alarm can be active at a time. This overwrites any previously-set alarm if any. |
| 282 | fn set(&self, timestamp: u64, callback: fn()); | 286 | fn set(&self, timestamp: u64); |
| 283 | 287 | ||
| 284 | /// Clears the previously-set alarm. | 288 | /// Clears the previously-set alarm. |
| 285 | /// If no alarm was set, this is a noop. | 289 | /// If no alarm was set, this is a noop. |
diff --git a/examples/src/bin/rtc_raw.rs b/examples/src/bin/rtc_raw.rs index 2e4b28653..8311c1bc0 100644 --- a/examples/src/bin/rtc_raw.rs +++ b/examples/src/bin/rtc_raw.rs | |||
| @@ -35,7 +35,8 @@ fn main() -> ! { | |||
| 35 | 35 | ||
| 36 | rtc.start(); | 36 | rtc.start(); |
| 37 | 37 | ||
| 38 | alarm.set(53719, || info!("ALARM TRIGGERED")); | 38 | alarm.set_callback(|| info!("ALARM TRIGGERED")); |
| 39 | alarm.set(53719); | ||
| 39 | 40 | ||
| 40 | info!("initialized!"); | 41 | info!("initialized!"); |
| 41 | 42 | ||
