aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/ipc.rs391
1 files changed, 197 insertions, 194 deletions
diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs
index 410783ef4..a8a08c911 100644
--- a/embassy-nrf/src/ipc.rs
+++ b/embassy-nrf/src/ipc.rs
@@ -3,18 +3,20 @@
3#![macro_use] 3#![macro_use]
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::sync::atomic::{compiler_fence, Ordering}; 6use core::marker::PhantomData;
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12use crate::peripherals::IPC; 12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac}; 13use crate::{interrupt, pac, ppi};
14
15const EVENT_COUNT: usize = 16;
14 16
15/// IPC Event 17/// IPC Event
16#[derive(Debug, Clone, Copy)] 18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum IpcEvent { 19pub enum EventNumber {
18 /// IPC Event 0 20 /// IPC Event 0
19 Event0 = 0, 21 Event0 = 0,
20 /// IPC Event 1 22 /// IPC Event 1
@@ -49,27 +51,27 @@ pub enum IpcEvent {
49 Event15 = 15, 51 Event15 = 15,
50} 52}
51 53
52const EVENTS: [IpcEvent; 16] = [ 54const EVENTS: [EventNumber; EVENT_COUNT] = [
53 IpcEvent::Event0, 55 EventNumber::Event0,
54 IpcEvent::Event1, 56 EventNumber::Event1,
55 IpcEvent::Event2, 57 EventNumber::Event2,
56 IpcEvent::Event3, 58 EventNumber::Event3,
57 IpcEvent::Event4, 59 EventNumber::Event4,
58 IpcEvent::Event5, 60 EventNumber::Event5,
59 IpcEvent::Event6, 61 EventNumber::Event6,
60 IpcEvent::Event7, 62 EventNumber::Event7,
61 IpcEvent::Event8, 63 EventNumber::Event8,
62 IpcEvent::Event9, 64 EventNumber::Event9,
63 IpcEvent::Event10, 65 EventNumber::Event10,
64 IpcEvent::Event11, 66 EventNumber::Event11,
65 IpcEvent::Event12, 67 EventNumber::Event12,
66 IpcEvent::Event13, 68 EventNumber::Event13,
67 IpcEvent::Event14, 69 EventNumber::Event14,
68 IpcEvent::Event15, 70 EventNumber::Event15,
69]; 71];
70 72
71/// IPC Channel 73/// IPC Channel
72#[derive(Debug, Clone, Copy)] 74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub enum IpcChannel { 75pub enum IpcChannel {
74 /// IPC Channel 0 76 /// IPC Channel 0
75 Channel0, 77 Channel0,
@@ -105,226 +107,227 @@ pub enum IpcChannel {
105 Channel15, 107 Channel15,
106} 108}
107 109
110impl IpcChannel {
111 fn mask(self) -> u32 {
112 1 << (self as u32)
113 }
114}
115
108/// Interrupt Handler 116/// Interrupt Handler
109pub struct InterruptHandler {} 117pub struct InterruptHandler<T: Instance> {
118 _phantom: PhantomData<T>,
119}
110 120
111impl interrupt::typelevel::Handler<interrupt::typelevel::IPC> for InterruptHandler { 121impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
112 unsafe fn on_interrupt() { 122 unsafe fn on_interrupt() {
113 let regs = IPC::regs(); 123 let regs = T::regs();
114 124
115 // Check if an event was generated, and if it was, trigger the corresponding waker 125 // Check if an event was generated, and if it was, trigger the corresponding waker
116 for event in EVENTS { 126 for event in EVENTS {
117 if regs.events_receive(event as usize).read() & 0x01 == 0x01 { 127 if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
118 // Event is set. Reset and wake waker 128 regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
119 regs.events_receive(event as usize).write_value(0); 129 T::state().wakers[event as usize].wake();
120 IPC::state().waker_for(event);
121 } 130 }
122
123 // Ensure the state is actually cleared
124 // Ref: nRF5340 PS v1.5 7.1.9.1 p.153
125 compiler_fence(Ordering::SeqCst);
126 while regs.events_receive(event as usize).read() & 0x01 != 0x00 {}
127 } 131 }
128 } 132 }
129} 133}
130 134
131/// IPC driver 135/// IPC driver
136#[non_exhaustive]
132pub struct Ipc<'d, T: Instance> { 137pub struct Ipc<'d, T: Instance> {
133 _peri: PeripheralRef<'d, T>, 138 /// Event 0
139 pub event0: Event<'d, T>,
140 /// Event 1
141 pub event1: Event<'d, T>,
142 /// Event 2
143 pub event2: Event<'d, T>,
144 /// Event 3
145 pub event3: Event<'d, T>,
146 /// Event 4
147 pub event4: Event<'d, T>,
148 /// Event 5
149 pub event5: Event<'d, T>,
150 /// Event 6
151 pub event6: Event<'d, T>,
152 /// Event 7
153 pub event7: Event<'d, T>,
154 /// Event 8
155 pub event8: Event<'d, T>,
156 /// Event 9
157 pub event9: Event<'d, T>,
158 /// Event 10
159 pub event10: Event<'d, T>,
160 /// Event 11
161 pub event11: Event<'d, T>,
162 /// Event 12
163 pub event12: Event<'d, T>,
164 /// Event 13
165 pub event13: Event<'d, T>,
166 /// Event 14
167 pub event14: Event<'d, T>,
168 /// Event 15
169 pub event15: Event<'d, T>,
134} 170}
135 171
136impl<'d, T: Instance> From<PeripheralRef<'d, T>> for Ipc<'d, T> { 172impl<'d, T: Instance> Ipc<'d, T> {
137 fn from(value: PeripheralRef<'d, T>) -> Self { 173 /// Create a new IPC driver.
138 Self { _peri: value } 174 pub fn new(
175 _p: Peri<'d, T>,
176 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
177 ) -> Self {
178 T::Interrupt::unpend();
179 unsafe { T::Interrupt::enable() };
180
181 let _phantom = PhantomData;
182 #[rustfmt::skip]
183 let r = Self { // attributes on expressions are experimental
184 event0: Event { number: EventNumber::Event0, _phantom },
185 event1: Event { number: EventNumber::Event1, _phantom },
186 event2: Event { number: EventNumber::Event2, _phantom },
187 event3: Event { number: EventNumber::Event3, _phantom },
188 event4: Event { number: EventNumber::Event4, _phantom },
189 event5: Event { number: EventNumber::Event5, _phantom },
190 event6: Event { number: EventNumber::Event6, _phantom },
191 event7: Event { number: EventNumber::Event7, _phantom },
192 event8: Event { number: EventNumber::Event8, _phantom },
193 event9: Event { number: EventNumber::Event9, _phantom },
194 event10: Event { number: EventNumber::Event10, _phantom },
195 event11: Event { number: EventNumber::Event11, _phantom },
196 event12: Event { number: EventNumber::Event12, _phantom },
197 event13: Event { number: EventNumber::Event13, _phantom },
198 event14: Event { number: EventNumber::Event14, _phantom },
199 event15: Event { number: EventNumber::Event15, _phantom },
200 };
201 r
139 } 202 }
140} 203}
141 204
142impl<'d, T: Instance> Ipc<'d, T> { 205/// IPC event
143 /// Create IPC driver 206pub struct Event<'d, T: Instance> {
144 pub fn new(ipc: impl Peripheral<P = T> + 'd) -> Self { 207 number: EventNumber,
145 into_ref!(ipc); 208 _phantom: PhantomData<&'d T>,
209}
146 210
147 Self { _peri: ipc } 211impl<'d, T: Instance> Event<'d, T> {
212 /// Trigger the event.
213 pub fn trigger(&self) {
214 let nr = self.number;
215 T::regs().tasks_send(nr as usize).write_value(1);
148 } 216 }
149 217
150 /// Duplicates the peripheral singleton 218 /// Wait for the event to be triggered.
151 /// 219 pub async fn wait(&mut self) {
152 /// # Safety 220 let regs = T::regs();
153 /// 221 let nr = self.number as usize;
154 /// Ensure manually that only one peripheral is in use at one time 222 regs.intenset().write(|w| w.0 = 1 << nr);
155 pub unsafe fn clone_unchecked(&self) -> Self { 223 poll_fn(|cx| {
156 Self { 224 T::state().wakers[nr].register(cx.waker());
157 _peri: self._peri.clone_unchecked(), 225
158 } 226 if regs.events_receive(nr).read() == 1 {
227 regs.events_receive(nr).write_value(0x00);
228 Poll::Ready(())
229 } else {
230 Poll::Pending
231 }
232 })
233 .await;
159 } 234 }
160 235
161 /// Configures the sending of events 236 /// Returns the [`EventNumber`] of the event.
162 /// 237 pub fn number(&self) -> EventNumber {
163 /// Events can be configured to broadcast on one or multiple IPC channels. 238 self.number
164 pub fn configure_send_event<I: IntoIterator<Item = IpcChannel>>(&self, ev: IpcEvent, channels: I) { 239 }
165 let regs = T::regs();
166 240
167 regs.send_cnf(ev as usize).write(|w| { 241 /// Create a handle that can trigger the event.
242 pub fn trigger_handle(&self) -> EventTrigger<'d, T> {
243 EventTrigger {
244 number: self.number,
245 _phantom: PhantomData,
246 }
247 }
248
249 /// Configure the channels the event will broadcast to
250 pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
251 T::regs().send_cnf(self.number as usize).write(|w| {
168 for channel in channels { 252 for channel in channels {
169 match channel { 253 w.0 |= channel.mask();
170 IpcChannel::Channel0 => w.set_chen0(true),
171 IpcChannel::Channel1 => w.set_chen1(true),
172 IpcChannel::Channel2 => w.set_chen2(true),
173 IpcChannel::Channel3 => w.set_chen3(true),
174 IpcChannel::Channel4 => w.set_chen4(true),
175 IpcChannel::Channel5 => w.set_chen5(true),
176 IpcChannel::Channel6 => w.set_chen6(true),
177 IpcChannel::Channel7 => w.set_chen7(true),
178 IpcChannel::Channel8 => w.set_chen8(true),
179 IpcChannel::Channel9 => w.set_chen9(true),
180 IpcChannel::Channel10 => w.set_chen10(true),
181 IpcChannel::Channel11 => w.set_chen11(true),
182 IpcChannel::Channel12 => w.set_chen12(true),
183 IpcChannel::Channel13 => w.set_chen13(true),
184 IpcChannel::Channel14 => w.set_chen14(true),
185 IpcChannel::Channel15 => w.set_chen15(true),
186 }
187 } 254 }
188 }) 255 })
189 } 256 }
190 257
191 /// Configures the receiving of events 258 /// Configure the channels the event will listen on
192 /// 259 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
193 /// Events can be configured to be received by one or multiple IPC channels. 260 T::regs().receive_cnf(self.number as usize).write(|w| {
194 pub fn configure_receive_event<I: IntoIterator<Item = IpcChannel>>(&self, ev: IpcEvent, channels: I) {
195 let regs = T::regs();
196
197 regs.receive_cnf(ev as usize).write(|w| {
198 for channel in channels { 261 for channel in channels {
199 match channel { 262 w.0 |= channel.mask();
200 IpcChannel::Channel0 => w.set_chen0(true),
201 IpcChannel::Channel1 => w.set_chen1(true),
202 IpcChannel::Channel2 => w.set_chen2(true),
203 IpcChannel::Channel3 => w.set_chen3(true),
204 IpcChannel::Channel4 => w.set_chen4(true),
205 IpcChannel::Channel5 => w.set_chen5(true),
206 IpcChannel::Channel6 => w.set_chen6(true),
207 IpcChannel::Channel7 => w.set_chen7(true),
208 IpcChannel::Channel8 => w.set_chen8(true),
209 IpcChannel::Channel9 => w.set_chen9(true),
210 IpcChannel::Channel10 => w.set_chen10(true),
211 IpcChannel::Channel11 => w.set_chen11(true),
212 IpcChannel::Channel12 => w.set_chen12(true),
213 IpcChannel::Channel13 => w.set_chen13(true),
214 IpcChannel::Channel14 => w.set_chen14(true),
215 IpcChannel::Channel15 => w.set_chen15(true),
216 }
217 } 263 }
218 }); 264 });
219 } 265 }
220 266
221 /// Triggers an event 267 /// Get the task for the IPC event to use with PPI.
222 pub fn trigger_event(&self, ev: IpcEvent) { 268 pub fn task(&self) -> ppi::Task<'d> {
269 let nr = self.number as usize;
223 let regs = T::regs(); 270 let regs = T::regs();
224 271 ppi::Task::from_reg(regs.tasks_send(nr))
225 regs.tasks_send(ev as usize).write_value(0x01);
226 } 272 }
227 273
228 /// Wait for event to be triggered 274 /// Get the event for the IPC event to use with PPI.
229 pub async fn wait_for_event(&self, ev: IpcEvent) { 275 pub fn event(&self) -> ppi::Event<'d> {
276 let nr = self.number as usize;
230 let regs = T::regs(); 277 let regs = T::regs();
278 ppi::Event::from_reg(regs.events_receive(nr))
279 }
231 280
232 // Enable interrupt 281 /// Reborrow into a "child" Event.
233 match ev { 282 ///
234 IpcEvent::Event0 => { 283 /// `self` will stay borrowed until the child Event is dropped.
235 regs.inten().modify(|m| m.set_receive0(true)); 284 pub fn reborrow(&mut self) -> Event<'_, T> {
236 } 285 Self { ..*self }
237 IpcEvent::Event1 => { 286 }
238 regs.inten().modify(|m| m.set_receive1(true));
239 }
240 IpcEvent::Event2 => {
241 regs.inten().modify(|m| m.set_receive2(true));
242 }
243 IpcEvent::Event3 => {
244 regs.inten().modify(|m| m.set_receive3(true));
245 }
246 IpcEvent::Event4 => {
247 regs.inten().modify(|m| m.set_receive4(true));
248 }
249 IpcEvent::Event5 => {
250 regs.inten().modify(|m| m.set_receive5(true));
251 }
252 IpcEvent::Event6 => {
253 regs.inten().modify(|m| m.set_receive6(true));
254 }
255 IpcEvent::Event7 => {
256 regs.inten().modify(|m| m.set_receive7(true));
257 }
258 IpcEvent::Event8 => {
259 regs.inten().modify(|m| m.set_receive8(true));
260 }
261 IpcEvent::Event9 => {
262 regs.inten().modify(|m| m.set_receive9(true));
263 }
264 IpcEvent::Event10 => {
265 regs.inten().modify(|m| m.set_receive10(true));
266 }
267 IpcEvent::Event11 => {
268 regs.inten().modify(|m| m.set_receive11(true));
269 }
270 IpcEvent::Event12 => {
271 regs.inten().modify(|m| m.set_receive12(true));
272 }
273 IpcEvent::Event13 => {
274 regs.inten().modify(|m| m.set_receive13(true));
275 }
276 IpcEvent::Event14 => {
277 regs.inten().modify(|m| m.set_receive14(true));
278 }
279 IpcEvent::Event15 => {
280 regs.inten().modify(|m| m.set_receive15(true));
281 }
282 };
283 287
284 poll_fn(|cx| { 288 /// Steal an IPC event by number.
285 IPC::state().waker_for(ev).register(cx.waker()); 289 ///
290 /// # Safety
291 ///
292 /// The event number must not be in use by another [`Event`].
293 pub unsafe fn steal(number: EventNumber) -> Self {
294 Self {
295 number,
296 _phantom: PhantomData,
297 }
298 }
299}
286 300
287 if regs.events_receive(ev as usize).read() & 0x01 == 0x01 { 301/// A handle that can trigger an IPC event.
288 regs.events_receive(ev as usize).write_value(0x00); 302///
303/// This `struct` is returned by [`Event::trigger_handle`].
304#[derive(Debug, Copy, Clone)]
305pub struct EventTrigger<'d, T: Instance> {
306 number: EventNumber,
307 _phantom: PhantomData<&'d T>,
308}
289 309
290 Poll::Ready(()) 310impl<T: Instance> EventTrigger<'_, T> {
291 } else { 311 /// Trigger the event.
292 Poll::Pending 312 pub fn trigger(&self) {
293 } 313 let nr = self.number;
294 }) 314 T::regs().tasks_send(nr as usize).write_value(1);
295 .await; 315 }
316
317 /// Returns the [`EventNumber`] of the event.
318 pub fn number(&self) -> EventNumber {
319 self.number
296 } 320 }
297} 321}
298 322
299pub(crate) struct State { 323pub(crate) struct State {
300 wakers: [AtomicWaker; 16], 324 wakers: [AtomicWaker; EVENT_COUNT],
301} 325}
302 326
303impl State { 327impl State {
304 pub(crate) const fn new() -> Self { 328 pub(crate) const fn new() -> Self {
305 const WAKER: AtomicWaker = AtomicWaker::new(); 329 Self {
306 330 wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
307 Self { wakers: [WAKER; 16] }
308 }
309
310 const fn waker_for(&self, ev: IpcEvent) -> &AtomicWaker {
311 match ev {
312 IpcEvent::Event0 => &self.wakers[0],
313 IpcEvent::Event1 => &self.wakers[1],
314 IpcEvent::Event2 => &self.wakers[2],
315 IpcEvent::Event3 => &self.wakers[3],
316 IpcEvent::Event4 => &self.wakers[4],
317 IpcEvent::Event5 => &self.wakers[5],
318 IpcEvent::Event6 => &self.wakers[6],
319 IpcEvent::Event7 => &self.wakers[7],
320 IpcEvent::Event8 => &self.wakers[8],
321 IpcEvent::Event9 => &self.wakers[9],
322 IpcEvent::Event10 => &self.wakers[10],
323 IpcEvent::Event11 => &self.wakers[11],
324 IpcEvent::Event12 => &self.wakers[12],
325 IpcEvent::Event13 => &self.wakers[13],
326 IpcEvent::Event14 => &self.wakers[14],
327 IpcEvent::Event15 => &self.wakers[15],
328 } 331 }
329 } 332 }
330} 333}
@@ -336,7 +339,7 @@ pub(crate) trait SealedInstance {
336 339
337/// IPC peripheral instance. 340/// IPC peripheral instance.
338#[allow(private_bounds)] 341#[allow(private_bounds)]
339pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send { 342pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
340 /// Interrupt for this peripheral. 343 /// Interrupt for this peripheral.
341 type Interrupt: interrupt::typelevel::Interrupt; 344 type Interrupt: interrupt::typelevel::Interrupt;
342} 345}