aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src
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-rp/src
parent406d377b7564d16e12b7fae4f42c0c709bf4f243 (diff)
Refactor integrated-timers
Diffstat (limited to 'embassy-rp/src')
-rw-r--r--embassy-rp/src/time_driver.rs130
1 files changed, 25 insertions, 105 deletions
diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs
index 40fc71bb1..17ae5fff3 100644
--- a/embassy-rp/src/time_driver.rs
+++ b/embassy-rp/src/time_driver.rs
@@ -1,11 +1,10 @@
1//! Timer driver. 1//! Timer driver.
2use core::cell::Cell; 2use core::cell::Cell;
3 3
4use atomic_polyfill::{AtomicU8, Ordering};
5use critical_section::CriticalSection;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 4use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::Mutex; 5use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::{AlarmHandle, Driver}; 6use embassy_time_driver::Driver;
7use embassy_time_queue_driver::GlobalTimerQueue;
9#[cfg(feature = "rp2040")] 8#[cfg(feature = "rp2040")]
10use pac::TIMER; 9use pac::TIMER;
11#[cfg(feature = "_rp235x")] 10#[cfg(feature = "_rp235x")]
@@ -16,23 +15,17 @@ use crate::{interrupt, pac};
16 15
17struct AlarmState { 16struct AlarmState {
18 timestamp: Cell<u64>, 17 timestamp: Cell<u64>,
19 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
20} 18}
21unsafe impl Send for AlarmState {} 19unsafe impl Send for AlarmState {}
22 20
23const ALARM_COUNT: usize = 4;
24
25struct TimerDriver { 21struct TimerDriver {
26 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, 22 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
27 next_alarm: AtomicU8,
28} 23}
29 24
30embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ 25embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
31 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState { 26 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState {
32 timestamp: Cell::new(0), 27 timestamp: Cell::new(0),
33 callback: Cell::new(None), 28 }),
34 }}; ALARM_COUNT]),
35 next_alarm: AtomicU8::new(0),
36}); 29});
37 30
38impl Driver for TimerDriver { 31impl Driver for TimerDriver {
@@ -46,34 +39,13 @@ impl Driver for TimerDriver {
46 } 39 }
47 } 40 }
48 } 41 }
42}
49 43
50 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 44impl TimerDriver {
51 let id = self.next_alarm.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 45 fn set_alarm(&self, timestamp: u64) -> bool {
52 if x < ALARM_COUNT as u8 { 46 let n = 0;
53 Some(x + 1)
54 } else {
55 None
56 }
57 });
58
59 match id {
60 Ok(id) => Some(AlarmHandle::new(id)),
61 Err(_) => None,
62 }
63 }
64
65 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
66 let n = alarm.id() as usize;
67 critical_section::with(|cs| {
68 let alarm = &self.alarms.borrow(cs)[n];
69 alarm.callback.set(Some((callback, ctx)));
70 })
71 }
72
73 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
74 let n = alarm.id() as usize;
75 critical_section::with(|cs| { 47 critical_section::with(|cs| {
76 let alarm = &self.alarms.borrow(cs)[n]; 48 let alarm = &self.alarms.borrow(cs);
77 alarm.timestamp.set(timestamp); 49 alarm.timestamp.set(timestamp);
78 50
79 // Arm it. 51 // Arm it.
@@ -96,15 +68,14 @@ impl Driver for TimerDriver {
96 } 68 }
97 }) 69 })
98 } 70 }
99}
100 71
101impl TimerDriver { 72 fn check_alarm(&self) {
102 fn check_alarm(&self, n: usize) { 73 let n = 0;
103 critical_section::with(|cs| { 74 critical_section::with(|cs| {
104 let alarm = &self.alarms.borrow(cs)[n]; 75 let alarm = &self.alarms.borrow(cs);
105 let timestamp = alarm.timestamp.get(); 76 let timestamp = alarm.timestamp.get();
106 if timestamp <= self.now() { 77 if timestamp <= self.now() {
107 self.trigger_alarm(n, cs) 78 self.trigger_alarm()
108 } else { 79 } else {
109 // Not elapsed, arm it again. 80 // Not elapsed, arm it again.
110 // This can happen if it was set more than 2^32 us in the future. 81 // This can happen if it was set more than 2^32 us in the future.
@@ -116,17 +87,8 @@ impl TimerDriver {
116 TIMER.intr().write(|w| w.set_alarm(n, true)); 87 TIMER.intr().write(|w| w.set_alarm(n, true));
117 } 88 }
118 89
119 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 90 fn trigger_alarm(&self) {
120 // disarm 91 TIMER_QUEUE_DRIVER.dispatch();
121 TIMER.armed().write(|w| w.set_armed(1 << n));
122
123 let alarm = &self.alarms.borrow(cs)[n];
124 alarm.timestamp.set(u64::MAX);
125
126 // Call after clearing alarm, so the callback can set another alarm.
127 if let Some((f, ctx)) = alarm.callback.get() {
128 f(ctx);
129 }
130 } 92 }
131} 93}
132 94
@@ -134,79 +96,37 @@ impl TimerDriver {
134pub unsafe fn init() { 96pub unsafe fn init() {
135 // init alarms 97 // init alarms
136 critical_section::with(|cs| { 98 critical_section::with(|cs| {
137 let alarms = DRIVER.alarms.borrow(cs); 99 let alarm = DRIVER.alarms.borrow(cs);
138 for a in alarms { 100 alarm.timestamp.set(u64::MAX);
139 a.timestamp.set(u64::MAX);
140 }
141 }); 101 });
142 102
143 // enable all irqs 103 // enable irq
144 TIMER.inte().write(|w| { 104 TIMER.inte().write(|w| {
145 w.set_alarm(0, true); 105 w.set_alarm(0, true);
146 w.set_alarm(1, true);
147 w.set_alarm(2, true);
148 w.set_alarm(3, true);
149 }); 106 });
150 #[cfg(feature = "rp2040")] 107 #[cfg(feature = "rp2040")]
151 { 108 {
152 interrupt::TIMER_IRQ_0.enable(); 109 interrupt::TIMER_IRQ_0.enable();
153 interrupt::TIMER_IRQ_1.enable();
154 interrupt::TIMER_IRQ_2.enable();
155 interrupt::TIMER_IRQ_3.enable();
156 } 110 }
157 #[cfg(feature = "_rp235x")] 111 #[cfg(feature = "_rp235x")]
158 { 112 {
159 interrupt::TIMER0_IRQ_0.enable(); 113 interrupt::TIMER0_IRQ_0.enable();
160 interrupt::TIMER0_IRQ_1.enable();
161 interrupt::TIMER0_IRQ_2.enable();
162 interrupt::TIMER0_IRQ_3.enable();
163 } 114 }
164} 115}
165 116
166#[cfg(all(feature = "rt", feature = "rp2040"))] 117#[cfg(all(feature = "rt", feature = "rp2040"))]
167#[interrupt] 118#[interrupt]
168fn TIMER_IRQ_0() { 119fn TIMER_IRQ_0() {
169 DRIVER.check_alarm(0) 120 DRIVER.check_alarm()
170}
171
172#[cfg(all(feature = "rt", feature = "rp2040"))]
173#[interrupt]
174fn TIMER_IRQ_1() {
175 DRIVER.check_alarm(1)
176}
177
178#[cfg(all(feature = "rt", feature = "rp2040"))]
179#[interrupt]
180fn TIMER_IRQ_2() {
181 DRIVER.check_alarm(2)
182}
183
184#[cfg(all(feature = "rt", feature = "rp2040"))]
185#[interrupt]
186fn TIMER_IRQ_3() {
187 DRIVER.check_alarm(3)
188} 121}
189 122
190#[cfg(all(feature = "rt", feature = "_rp235x"))] 123#[cfg(all(feature = "rt", feature = "_rp235x"))]
191#[interrupt] 124#[interrupt]
192fn TIMER0_IRQ_0() { 125fn TIMER0_IRQ_0() {
193 DRIVER.check_alarm(0) 126 DRIVER.check_alarm()
194} 127}
195 128
196#[cfg(all(feature = "rt", feature = "_rp235x"))] 129embassy_time_queue_driver::timer_queue_impl!(
197#[interrupt] 130 static TIMER_QUEUE_DRIVER: GlobalTimerQueue
198fn TIMER0_IRQ_1() { 131 = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration))
199 DRIVER.check_alarm(1) 132);
200}
201
202#[cfg(all(feature = "rt", feature = "_rp235x"))]
203#[interrupt]
204fn TIMER0_IRQ_2() {
205 DRIVER.check_alarm(2)
206}
207
208#[cfg(all(feature = "rt", feature = "_rp235x"))]
209#[interrupt]
210fn TIMER0_IRQ_3() {
211 DRIVER.check_alarm(3)
212}