aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf/src
diff options
context:
space:
mode:
authorAlessandro Gasbarroni <[email protected]>2024-12-17 13:25:58 +0100
committerMatthew Tran <[email protected]>2025-05-10 17:08:52 -0500
commit967a98fd4448a8e00c8cbfb509c1cc32e2bdcd29 (patch)
tree7b718eec9ad0d6208dc249ff581925e67bebcf6a /embassy-nrf/src
parentf9f20ae2174cb26d0f8926207d179041cfec2d2e (diff)
nrf: Add IPC peripheral for nRF5340
Diffstat (limited to 'embassy-nrf/src')
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/ipc.rs360
-rw-r--r--embassy-nrf/src/lib.rs2
4 files changed, 372 insertions, 0 deletions
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 0103fa7ae..99cf29487 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
262 PPI_GROUP4, 262 PPI_GROUP4,
263 PPI_GROUP5, 263 PPI_GROUP5,
264 264
265 // IPC
266 IPC,
267
265 // GPIO port 0 268 // GPIO port 0
266 #[cfg(feature = "lfxo-pins-as-gpio")] 269 #[cfg(feature = "lfxo-pins-as-gpio")]
267 P0_00, 270 P0_00,
@@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
327 EGU5, 330 EGU5,
328} 331}
329 332
333impl_ipc!(IPC, IPC, IPC);
334
330impl_usb!(USBD, USBD, USBD); 335impl_usb!(USBD, USBD, USBD);
331 336
332impl_uarte!(SERIAL0, UARTE0, SERIAL0); 337impl_uarte!(SERIAL0, UARTE0, SERIAL0);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 22d33d080..c2932be31 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
141 PPI_GROUP4, 141 PPI_GROUP4,
142 PPI_GROUP5, 142 PPI_GROUP5,
143 143
144 // IPC
145 IPC,
146
144 // GPIO port 0 147 // GPIO port 0
145 P0_00, 148 P0_00,
146 P0_01, 149 P0_01,
@@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
200 EGU0, 203 EGU0,
201} 204}
202 205
206impl_ipc!(IPC, IPC, IPC);
207
203impl_uarte!(SERIAL0, UARTE0, SERIAL0); 208impl_uarte!(SERIAL0, UARTE0, SERIAL0);
204impl_spim!(SERIAL0, SPIM0, SERIAL0); 209impl_spim!(SERIAL0, SPIM0, SERIAL0);
205impl_spis!(SERIAL0, SPIS0, SERIAL0); 210impl_spis!(SERIAL0, SPIS0, SERIAL0);
diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs
new file mode 100644
index 000000000..410783ef4
--- /dev/null
+++ b/embassy-nrf/src/ipc.rs
@@ -0,0 +1,360 @@
1//! InterProcessor Communication (IPC)
2
3#![macro_use]
4
5use core::future::poll_fn;
6use core::sync::atomic::{compiler_fence, Ordering};
7use core::task::Poll;
8
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::peripherals::IPC;
13use crate::{interrupt, pac};
14
15/// IPC Event
16#[derive(Debug, Clone, Copy)]
17pub enum IpcEvent {
18 /// IPC Event 0
19 Event0 = 0,
20 /// IPC Event 1
21 Event1 = 1,
22 /// IPC Event 2
23 Event2 = 2,
24 /// IPC Event 3
25 Event3 = 3,
26 /// IPC Event 4
27 Event4 = 4,
28 /// IPC Event 5
29 Event5 = 5,
30 /// IPC Event 6
31 Event6 = 6,
32 /// IPC Event 7
33 Event7 = 7,
34 /// IPC Event 8
35 Event8 = 8,
36 /// IPC Event 9
37 Event9 = 9,
38 /// IPC Event 10
39 Event10 = 10,
40 /// IPC Event 11
41 Event11 = 11,
42 /// IPC Event 12
43 Event12 = 12,
44 /// IPC Event 13
45 Event13 = 13,
46 /// IPC Event 14
47 Event14 = 14,
48 /// IPC Event 15
49 Event15 = 15,
50}
51
52const EVENTS: [IpcEvent; 16] = [
53 IpcEvent::Event0,
54 IpcEvent::Event1,
55 IpcEvent::Event2,
56 IpcEvent::Event3,
57 IpcEvent::Event4,
58 IpcEvent::Event5,
59 IpcEvent::Event6,
60 IpcEvent::Event7,
61 IpcEvent::Event8,
62 IpcEvent::Event9,
63 IpcEvent::Event10,
64 IpcEvent::Event11,
65 IpcEvent::Event12,
66 IpcEvent::Event13,
67 IpcEvent::Event14,
68 IpcEvent::Event15,
69];
70
71/// IPC Channel
72#[derive(Debug, Clone, Copy)]
73pub enum IpcChannel {
74 /// IPC Channel 0
75 Channel0,
76 /// IPC Channel 1
77 Channel1,
78 /// IPC Channel 2
79 Channel2,
80 /// IPC Channel 3
81 Channel3,
82 /// IPC Channel 4
83 Channel4,
84 /// IPC Channel 5
85 Channel5,
86 /// IPC Channel 6
87 Channel6,
88 /// IPC Channel 7
89 Channel7,
90 /// IPC Channel 8
91 Channel8,
92 /// IPC Channel 9
93 Channel9,
94 /// IPC Channel 10
95 Channel10,
96 /// IPC Channel 11
97 Channel11,
98 /// IPC Channel 12
99 Channel12,
100 /// IPC Channel 13
101 Channel13,
102 /// IPC Channel 14
103 Channel14,
104 /// IPC Channel 15
105 Channel15,
106}
107
108/// Interrupt Handler
109pub struct InterruptHandler {}
110
111impl interrupt::typelevel::Handler<interrupt::typelevel::IPC> for InterruptHandler {
112 unsafe fn on_interrupt() {
113 let regs = IPC::regs();
114
115 // Check if an event was generated, and if it was, trigger the corresponding waker
116 for event in EVENTS {
117 if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
118 // Event is set. Reset and wake waker
119 regs.events_receive(event as usize).write_value(0);
120 IPC::state().waker_for(event);
121 }
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 }
128 }
129}
130
131/// IPC driver
132pub struct Ipc<'d, T: Instance> {
133 _peri: PeripheralRef<'d, T>,
134}
135
136impl<'d, T: Instance> From<PeripheralRef<'d, T>> for Ipc<'d, T> {
137 fn from(value: PeripheralRef<'d, T>) -> Self {
138 Self { _peri: value }
139 }
140}
141
142impl<'d, T: Instance> Ipc<'d, T> {
143 /// Create IPC driver
144 pub fn new(ipc: impl Peripheral<P = T> + 'd) -> Self {
145 into_ref!(ipc);
146
147 Self { _peri: ipc }
148 }
149
150 /// Duplicates the peripheral singleton
151 ///
152 /// # Safety
153 ///
154 /// Ensure manually that only one peripheral is in use at one time
155 pub unsafe fn clone_unchecked(&self) -> Self {
156 Self {
157 _peri: self._peri.clone_unchecked(),
158 }
159 }
160
161 /// Configures the sending of events
162 ///
163 /// Events can be configured to broadcast on one or multiple IPC channels.
164 pub fn configure_send_event<I: IntoIterator<Item = IpcChannel>>(&self, ev: IpcEvent, channels: I) {
165 let regs = T::regs();
166
167 regs.send_cnf(ev as usize).write(|w| {
168 for channel in channels {
169 match channel {
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 }
188 })
189 }
190
191 /// Configures the receiving of events
192 ///
193 /// Events can be configured to be received by one or multiple IPC channels.
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 {
199 match channel {
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 }
218 });
219 }
220
221 /// Triggers an event
222 pub fn trigger_event(&self, ev: IpcEvent) {
223 let regs = T::regs();
224
225 regs.tasks_send(ev as usize).write_value(0x01);
226 }
227
228 /// Wait for event to be triggered
229 pub async fn wait_for_event(&self, ev: IpcEvent) {
230 let regs = T::regs();
231
232 // Enable interrupt
233 match ev {
234 IpcEvent::Event0 => {
235 regs.inten().modify(|m| m.set_receive0(true));
236 }
237 IpcEvent::Event1 => {
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
284 poll_fn(|cx| {
285 IPC::state().waker_for(ev).register(cx.waker());
286
287 if regs.events_receive(ev as usize).read() & 0x01 == 0x01 {
288 regs.events_receive(ev as usize).write_value(0x00);
289
290 Poll::Ready(())
291 } else {
292 Poll::Pending
293 }
294 })
295 .await;
296 }
297}
298
299pub(crate) struct State {
300 wakers: [AtomicWaker; 16],
301}
302
303impl State {
304 pub(crate) const fn new() -> Self {
305 const WAKER: AtomicWaker = AtomicWaker::new();
306
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 }
329 }
330}
331
332pub(crate) trait SealedInstance {
333 fn regs() -> pac::ipc::Ipc;
334 fn state() -> &'static State;
335}
336
337/// IPC peripheral instance.
338#[allow(private_bounds)]
339pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
340 /// Interrupt for this peripheral.
341 type Interrupt: interrupt::typelevel::Interrupt;
342}
343
344macro_rules! impl_ipc {
345 ($type:ident, $pac_type:ident, $irq:ident) => {
346 impl crate::ipc::SealedInstance for peripherals::$type {
347 fn regs() -> pac::ipc::Ipc {
348 pac::$pac_type
349 }
350
351 fn state() -> &'static crate::ipc::State {
352 static STATE: crate::ipc::State = crate::ipc::State::new();
353 &STATE
354 }
355 }
356 impl crate::ipc::Instance for peripherals::$type {
357 type Interrupt = crate::interrupt::typelevel::$irq;
358 }
359 };
360}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 07ba2f6d4..5bce65a98 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -88,6 +88,8 @@ pub mod gpiote;
88#[cfg(not(feature = "_nrf54l"))] // TODO 88#[cfg(not(feature = "_nrf54l"))] // TODO
89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] 89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
90pub mod i2s; 90pub mod i2s;
91#[cfg(feature = "_nrf5340")]
92pub mod ipc;
91#[cfg(not(feature = "_nrf54l"))] // TODO 93#[cfg(not(feature = "_nrf54l"))] // TODO
92#[cfg(any( 94#[cfg(any(
93 feature = "nrf52832", 95 feature = "nrf52832",