aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerhard de Clercq <[email protected]>2025-05-13 14:59:03 +0200
committerGitHub <[email protected]>2025-05-13 14:59:03 +0200
commitf7c796e3ccdbd559eee26fddf39413782530f977 (patch)
tree83bcae20ffd755a7cac4a5b184d5a2dfd7133fdb
parent3c73b497909ce5bacd16d23e54928a7f66544e09 (diff)
parent575eab3c60c0d2098f9e9d2a22429aa174b6b968 (diff)
Merge branch 'embassy-rs:main' into dfu-msos
-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.rs363
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--embassy-rp/Cargo.toml5
5 files changed, 379 insertions, 1 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..a8a08c911
--- /dev/null
+++ b/embassy-nrf/src/ipc.rs
@@ -0,0 +1,363 @@
1//! InterProcessor Communication (IPC)
2
3#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::task::Poll;
8
9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac, ppi};
14
15const EVENT_COUNT: usize = 16;
16
17/// IPC Event
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub enum EventNumber {
20 /// IPC Event 0
21 Event0 = 0,
22 /// IPC Event 1
23 Event1 = 1,
24 /// IPC Event 2
25 Event2 = 2,
26 /// IPC Event 3
27 Event3 = 3,
28 /// IPC Event 4
29 Event4 = 4,
30 /// IPC Event 5
31 Event5 = 5,
32 /// IPC Event 6
33 Event6 = 6,
34 /// IPC Event 7
35 Event7 = 7,
36 /// IPC Event 8
37 Event8 = 8,
38 /// IPC Event 9
39 Event9 = 9,
40 /// IPC Event 10
41 Event10 = 10,
42 /// IPC Event 11
43 Event11 = 11,
44 /// IPC Event 12
45 Event12 = 12,
46 /// IPC Event 13
47 Event13 = 13,
48 /// IPC Event 14
49 Event14 = 14,
50 /// IPC Event 15
51 Event15 = 15,
52}
53
54const EVENTS: [EventNumber; EVENT_COUNT] = [
55 EventNumber::Event0,
56 EventNumber::Event1,
57 EventNumber::Event2,
58 EventNumber::Event3,
59 EventNumber::Event4,
60 EventNumber::Event5,
61 EventNumber::Event6,
62 EventNumber::Event7,
63 EventNumber::Event8,
64 EventNumber::Event9,
65 EventNumber::Event10,
66 EventNumber::Event11,
67 EventNumber::Event12,
68 EventNumber::Event13,
69 EventNumber::Event14,
70 EventNumber::Event15,
71];
72
73/// IPC Channel
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub enum IpcChannel {
76 /// IPC Channel 0
77 Channel0,
78 /// IPC Channel 1
79 Channel1,
80 /// IPC Channel 2
81 Channel2,
82 /// IPC Channel 3
83 Channel3,
84 /// IPC Channel 4
85 Channel4,
86 /// IPC Channel 5
87 Channel5,
88 /// IPC Channel 6
89 Channel6,
90 /// IPC Channel 7
91 Channel7,
92 /// IPC Channel 8
93 Channel8,
94 /// IPC Channel 9
95 Channel9,
96 /// IPC Channel 10
97 Channel10,
98 /// IPC Channel 11
99 Channel11,
100 /// IPC Channel 12
101 Channel12,
102 /// IPC Channel 13
103 Channel13,
104 /// IPC Channel 14
105 Channel14,
106 /// IPC Channel 15
107 Channel15,
108}
109
110impl IpcChannel {
111 fn mask(self) -> u32 {
112 1 << (self as u32)
113 }
114}
115
116/// Interrupt Handler
117pub struct InterruptHandler<T: Instance> {
118 _phantom: PhantomData<T>,
119}
120
121impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
122 unsafe fn on_interrupt() {
123 let regs = T::regs();
124
125 // Check if an event was generated, and if it was, trigger the corresponding waker
126 for event in EVENTS {
127 if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
128 regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
129 T::state().wakers[event as usize].wake();
130 }
131 }
132 }
133}
134
135/// IPC driver
136#[non_exhaustive]
137pub struct Ipc<'d, T: Instance> {
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>,
170}
171
172impl<'d, T: Instance> Ipc<'d, T> {
173 /// Create a new IPC driver.
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
202 }
203}
204
205/// IPC event
206pub struct Event<'d, T: Instance> {
207 number: EventNumber,
208 _phantom: PhantomData<&'d T>,
209}
210
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);
216 }
217
218 /// Wait for the event to be triggered.
219 pub async fn wait(&mut self) {
220 let regs = T::regs();
221 let nr = self.number as usize;
222 regs.intenset().write(|w| w.0 = 1 << nr);
223 poll_fn(|cx| {
224 T::state().wakers[nr].register(cx.waker());
225
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;
234 }
235
236 /// Returns the [`EventNumber`] of the event.
237 pub fn number(&self) -> EventNumber {
238 self.number
239 }
240
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| {
252 for channel in channels {
253 w.0 |= channel.mask();
254 }
255 })
256 }
257
258 /// Configure the channels the event will listen on
259 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
260 T::regs().receive_cnf(self.number as usize).write(|w| {
261 for channel in channels {
262 w.0 |= channel.mask();
263 }
264 });
265 }
266
267 /// Get the task for the IPC event to use with PPI.
268 pub fn task(&self) -> ppi::Task<'d> {
269 let nr = self.number as usize;
270 let regs = T::regs();
271 ppi::Task::from_reg(regs.tasks_send(nr))
272 }
273
274 /// Get the event for the IPC event to use with PPI.
275 pub fn event(&self) -> ppi::Event<'d> {
276 let nr = self.number as usize;
277 let regs = T::regs();
278 ppi::Event::from_reg(regs.events_receive(nr))
279 }
280
281 /// Reborrow into a "child" Event.
282 ///
283 /// `self` will stay borrowed until the child Event is dropped.
284 pub fn reborrow(&mut self) -> Event<'_, T> {
285 Self { ..*self }
286 }
287
288 /// Steal an IPC event by number.
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}
300
301/// A handle that can trigger an IPC event.
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}
309
310impl<T: Instance> EventTrigger<'_, T> {
311 /// Trigger the event.
312 pub fn trigger(&self) {
313 let nr = self.number;
314 T::regs().tasks_send(nr as usize).write_value(1);
315 }
316
317 /// Returns the [`EventNumber`] of the event.
318 pub fn number(&self) -> EventNumber {
319 self.number
320 }
321}
322
323pub(crate) struct State {
324 wakers: [AtomicWaker; EVENT_COUNT],
325}
326
327impl State {
328 pub(crate) const fn new() -> Self {
329 Self {
330 wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
331 }
332 }
333}
334
335pub(crate) trait SealedInstance {
336 fn regs() -> pac::ipc::Ipc;
337 fn state() -> &'static State;
338}
339
340/// IPC peripheral instance.
341#[allow(private_bounds)]
342pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
343 /// Interrupt for this peripheral.
344 type Interrupt: interrupt::typelevel::Interrupt;
345}
346
347macro_rules! impl_ipc {
348 ($type:ident, $pac_type:ident, $irq:ident) => {
349 impl crate::ipc::SealedInstance for peripherals::$type {
350 fn regs() -> pac::ipc::Ipc {
351 pac::$pac_type
352 }
353
354 fn state() -> &'static crate::ipc::State {
355 static STATE: crate::ipc::State = crate::ipc::State::new();
356 &STATE
357 }
358 }
359 impl crate::ipc::Instance for peripherals::$type {
360 type Interrupt = crate::interrupt::typelevel::$irq;
361 }
362 };
363}
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",
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b440591cf..8fb8a50fd 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
26 26
27[features] 27[features]
28default = [ "rt" ] 28default = [ "rt" ]
29## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. 29
30## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac).
31## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that.
32## See <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> for more info.
30rt = [ "rp-pac/rt" ] 33rt = [ "rp-pac/rt" ]
31 34
32## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 35## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.