aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/rtc.rs93
-rw-r--r--embassy/src/executor.rs3
-rw-r--r--embassy/src/time.rs6
-rw-r--r--examples/src/bin/rtc_raw.rs3
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;
3use core::sync::atomic::{AtomicU32, Ordering}; 3use core::sync::atomic::{AtomicU32, Ordering};
4 4
5use crate::interrupt; 5use crate::interrupt;
6use crate::interrupt::Mutex; 6use crate::interrupt::{CriticalSection, Mutex};
7use crate::pac::{rtc0, Interrupt, RTC0, RTC1}; 7use 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
37struct AlarmState {
38 timestamp: Cell<u64>,
39 callback: Cell<Option<fn()>>,
40}
41
42impl AlarmState {
43 fn new() -> Self {
44 Self {
45 timestamp: Cell::new(u64::MAX),
46 callback: Cell::new(None),
47 }
48 }
49}
50
51const ALARM_COUNT: usize = 3;
52
37pub struct RTC<T> { 53pub 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
56unsafe impl<T> Send for RTC<T> {} 72unsafe 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
172pub struct Alarm<T: Instance> { 206pub struct Alarm<T: Instance> {
207 n: usize,
173 rtc: &'static RTC<T>, 208 rtc: &'static RTC<T>,
174} 209}
175 210
176impl<T: Instance> embassy::time::Alarm for Alarm<T> { 211impl<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
28impl<M: Model, A: Alarm> Executor<M, A> { 28impl<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.
275pub trait Alarm { 275pub 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