aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-hal-common/src/peripheral.rs124
-rw-r--r--embassy-hal-common/src/usb/mod.rs49
-rw-r--r--embassy-hal-common/src/usb/usb_serial.rs10
-rw-r--r--embassy-nrf/src/buffered_uarte.rs98
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs64
-rw-r--r--examples/nrf/src/bin/buffered_uart.rs3
-rw-r--r--examples/stm32h7/src/bin/eth.rs18
7 files changed, 170 insertions, 196 deletions
diff --git a/embassy-hal-common/src/peripheral.rs b/embassy-hal-common/src/peripheral.rs
index 92512a0f6..d3df06e86 100644
--- a/embassy-hal-common/src/peripheral.rs
+++ b/embassy-hal-common/src/peripheral.rs
@@ -1,6 +1,5 @@
1use core::cell::UnsafeCell; 1use core::marker::PhantomData;
2use core::marker::{PhantomData, PhantomPinned}; 2use core::mem::MaybeUninit;
3use core::pin::Pin;
4 3
5use cortex_m::peripheral::scb::VectActive; 4use cortex_m::peripheral::scb::VectActive;
6use cortex_m::peripheral::{NVIC, SCB}; 5use cortex_m::peripheral::{NVIC, SCB};
@@ -10,23 +9,23 @@ use embassy::interrupt::{Interrupt, InterruptExt};
10/// 9///
11/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt, 10/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
12/// and `&mut T` is only `Send` where `T: Send`. 11/// and `&mut T` is only `Send` where `T: Send`.
13///
14/// It also requires `'static` to be used safely with `PeripheralMutex::register_interrupt`,
15/// because although `Pin` guarantees that the memory of the state won't be invalidated,
16/// it doesn't guarantee that the lifetime will last.
17pub trait PeripheralState: Send { 12pub trait PeripheralState: Send {
18 type Interrupt: Interrupt; 13 type Interrupt: Interrupt;
19 fn on_interrupt(&mut self); 14 fn on_interrupt(&mut self);
20} 15}
21 16
22pub struct PeripheralMutex<S: PeripheralState> { 17pub struct StateStorage<S>(MaybeUninit<S>);
23 state: UnsafeCell<S>,
24 18
25 irq_setup_done: bool, 19impl<S> StateStorage<S> {
26 irq: S::Interrupt, 20 pub fn new() -> Self {
21 Self(MaybeUninit::uninit())
22 }
23}
27 24
28 _not_send: PhantomData<*mut ()>, 25pub struct PeripheralMutex<'a, S: PeripheralState> {
29 _pinned: PhantomPinned, 26 state: *mut S,
27 _phantom: PhantomData<&'a mut S>,
28 irq: S::Interrupt,
30} 29}
31 30
32/// Whether `irq` can be preempted by the current interrupt. 31/// Whether `irq` can be preempted by the current interrupt.
@@ -50,58 +49,45 @@ pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
50 } 49 }
51} 50}
52 51
53impl<S: PeripheralState + 'static> PeripheralMutex<S> { 52impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
54 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it. 53 /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`.
55 ///
56 /// This requires this `PeripheralMutex`'s `PeripheralState` to live for `'static`,
57 /// because `Pin` only guarantees that it's memory won't be repurposed,
58 /// not that it's lifetime will last.
59 /// 54 ///
60 /// To use non-`'static` `PeripheralState`, use the unsafe `register_interrupt_unchecked`. 55 /// self requires `state` to live for `'static`, because if the `PeripheralMutex` is leaked, the
56 /// interrupt won't be disabled, which may try accessing the state at any time. To use non-`'static`
57 /// state, see [`Self::new_unchecked`].
61 /// 58 ///
62 /// Note: `'static` doesn't mean it _has_ to live for the entire program, like an `&'static T`; 59 /// Registers `on_interrupt` as the `irq`'s handler, and enables it.
63 /// it just means it _can_ live for the entire program - for example, `u8` lives for `'static`. 60 pub fn new(storage: &'a mut StateStorage<S>, state: S, irq: S::Interrupt) -> Self
64 pub fn register_interrupt(self: Pin<&mut Self>) { 61 where
65 // SAFETY: `S: 'static`, so there's no way it's lifetime can expire. 62 'a: 'static,
66 unsafe { self.register_interrupt_unchecked() } 63 {
64 // safety: safe because state is `'static`.
65 unsafe { Self::new_unchecked(storage, state, irq) }
67 } 66 }
68}
69 67
70impl<S: PeripheralState> PeripheralMutex<S> { 68 /// Create a `PeripheralMutex` without requiring the state is `'static`.
71 /// Create a new `PeripheralMutex` wrapping `irq`, with the initial state `state`. 69 ///
72 pub fn new(state: S, irq: S::Interrupt) -> Self { 70 /// See also [`Self::new`].
71 ///
72 /// # Safety
73 /// The created instance must not be leaked (its `drop` must run).
74 pub unsafe fn new_unchecked(
75 storage: &'a mut StateStorage<S>,
76 state: S,
77 irq: S::Interrupt,
78 ) -> Self {
73 if can_be_preempted(&irq) { 79 if can_be_preempted(&irq) {
74 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"); 80 panic!("`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps");
75 } 81 }
76 82
77 Self { 83 let state_ptr = storage.0.as_mut_ptr();
78 irq,
79 irq_setup_done: false,
80 84
81 state: UnsafeCell::new(state), 85 // Safety: The pointer is valid and not used by anyone else
82 _not_send: PhantomData, 86 // because we have the `&mut StateStorage`.
83 _pinned: PhantomPinned, 87 state_ptr.write(state);
84 }
85 }
86
87 /// Registers `on_interrupt` as the wrapped interrupt's interrupt handler and enables it.
88 ///
89 /// # Safety
90 /// The lifetime of any data in `PeripheralState` that is accessed by the interrupt handler
91 /// must not end without `Drop` being called on this `PeripheralMutex`.
92 ///
93 /// This can be accomplished by either not accessing any data with a lifetime in `on_interrupt`,
94 /// or making sure that nothing like `mem::forget` is used on the `PeripheralMutex`.
95
96 // TODO: this name isn't the best.
97 pub unsafe fn register_interrupt_unchecked(self: Pin<&mut Self>) {
98 let this = self.get_unchecked_mut();
99 if this.irq_setup_done {
100 return;
101 }
102 88
103 this.irq.disable(); 89 irq.disable();
104 this.irq.set_handler(|p| { 90 irq.set_handler(|p| {
105 // Safety: it's OK to get a &mut to the state, since 91 // Safety: it's OK to get a &mut to the state, since
106 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`. 92 // - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
107 // Interrupts' priorities can only be changed with raw embassy `Interrupts`, 93 // Interrupts' priorities can only be changed with raw embassy `Interrupts`,
@@ -110,23 +96,24 @@ impl<S: PeripheralState> PeripheralMutex<S> {
110 let state = unsafe { &mut *(p as *mut S) }; 96 let state = unsafe { &mut *(p as *mut S) };
111 state.on_interrupt(); 97 state.on_interrupt();
112 }); 98 });
113 this.irq 99 irq.set_handler_context(state_ptr as *mut ());
114 .set_handler_context((&mut this.state) as *mut _ as *mut ()); 100 irq.enable();
115 this.irq.enable();
116 101
117 this.irq_setup_done = true; 102 Self {
103 irq,
104 state: state_ptr,
105 _phantom: PhantomData,
106 }
118 } 107 }
119 108
120 pub fn with<R>(self: Pin<&mut Self>, f: impl FnOnce(&mut S) -> R) -> R { 109 pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
121 let this = unsafe { self.get_unchecked_mut() }; 110 self.irq.disable();
122
123 this.irq.disable();
124 111
125 // Safety: it's OK to get a &mut to the state, since the irq is disabled. 112 // Safety: it's OK to get a &mut to the state, since the irq is disabled.
126 let state = unsafe { &mut *this.state.get() }; 113 let state = unsafe { &mut *self.state };
127 let r = f(state); 114 let r = f(state);
128 115
129 this.irq.enable(); 116 self.irq.enable();
130 117
131 r 118 r
132 } 119 }
@@ -152,9 +139,14 @@ impl<S: PeripheralState> PeripheralMutex<S> {
152 } 139 }
153} 140}
154 141
155impl<S: PeripheralState> Drop for PeripheralMutex<S> { 142impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
156 fn drop(&mut self) { 143 fn drop(&mut self) {
157 self.irq.disable(); 144 self.irq.disable();
158 self.irq.remove_handler(); 145 self.irq.remove_handler();
146
147 // safety:
148 // - we initialized the state in `new`, so we know it's initialized.
149 // - the irq is disabled, so it won't preempt us while dropping.
150 unsafe { self.state.drop_in_place() }
159 } 151 }
160} 152}
diff --git a/embassy-hal-common/src/usb/mod.rs b/embassy-hal-common/src/usb/mod.rs
index 1fb501d7f..0940e6b02 100644
--- a/embassy-hal-common/src/usb/mod.rs
+++ b/embassy-hal-common/src/usb/mod.rs
@@ -9,14 +9,31 @@ use usb_device::device::UsbDevice;
9mod cdc_acm; 9mod cdc_acm;
10pub mod usb_serial; 10pub mod usb_serial;
11 11
12use crate::peripheral::{PeripheralMutex, PeripheralState}; 12use crate::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
13use embassy::interrupt::Interrupt; 13use embassy::interrupt::Interrupt;
14use usb_serial::{ReadInterface, UsbSerial, WriteInterface}; 14use usb_serial::{ReadInterface, UsbSerial, WriteInterface};
15 15
16/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction. 16/// Marker trait to mark an interrupt to be used with the [`Usb`] abstraction.
17pub unsafe trait USBInterrupt: Interrupt + Send {} 17pub unsafe trait USBInterrupt: Interrupt + Send {}
18 18
19pub(crate) struct State<'bus, B, T, I> 19pub struct State<'bus, B, T, I>(StateStorage<StateInner<'bus, B, T, I>>)
20where
21 B: UsbBus,
22 T: ClassSet<B>,
23 I: USBInterrupt;
24
25impl<'bus, B, T, I> State<'bus, B, T, I>
26where
27 B: UsbBus,
28 T: ClassSet<B>,
29 I: USBInterrupt,
30{
31 pub fn new() -> Self {
32 Self(StateStorage::new())
33 }
34}
35
36pub(crate) struct StateInner<'bus, B, T, I>
20where 37where
21 B: UsbBus, 38 B: UsbBus,
22 T: ClassSet<B>, 39 T: ClassSet<B>,
@@ -34,7 +51,7 @@ where
34 I: USBInterrupt, 51 I: USBInterrupt,
35{ 52{
36 // Don't you dare moving out `PeripheralMutex` 53 // Don't you dare moving out `PeripheralMutex`
37 inner: RefCell<PeripheralMutex<State<'bus, B, T, I>>>, 54 inner: RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, I>>>,
38} 55}
39 56
40impl<'bus, B, T, I> Usb<'bus, B, T, I> 57impl<'bus, B, T, I> Usb<'bus, B, T, I>
@@ -43,30 +60,22 @@ where
43 T: ClassSet<B>, 60 T: ClassSet<B>,
44 I: USBInterrupt, 61 I: USBInterrupt,
45{ 62{
46 pub fn new<S: IntoClassSet<B, T>>(device: UsbDevice<'bus, B>, class_set: S, irq: I) -> Self { 63 pub fn new<S: IntoClassSet<B, T>>(
47 let state = State { 64 state: &'bus mut State<'bus, B, T, I>,
65 device: UsbDevice<'bus, B>,
66 class_set: S,
67 irq: I,
68 ) -> Self {
69 let initial_state = StateInner {
48 device, 70 device,
49 classes: class_set.into_class_set(), 71 classes: class_set.into_class_set(),
50 _interrupt: PhantomData, 72 _interrupt: PhantomData,
51 }; 73 };
52 let mutex = PeripheralMutex::new(state, irq); 74 let mutex = unsafe { PeripheralMutex::new_unchecked(&mut state.0, initial_state, irq) };
53 Self { 75 Self {
54 inner: RefCell::new(mutex), 76 inner: RefCell::new(mutex),
55 } 77 }
56 } 78 }
57
58 /// # Safety
59 /// The `UsbDevice` passed to `Self::new` must not be dropped without calling `Drop` on this `Usb` first.
60 pub unsafe fn start(self: Pin<&mut Self>) {
61 let this = self.get_unchecked_mut();
62 let mut mutex = this.inner.borrow_mut();
63 let mutex = Pin::new_unchecked(&mut *mutex);
64
65 // Use inner to register the irq
66 // SAFETY: the safety contract of this function makes sure the `UsbDevice` won't be invalidated
67 // without the `PeripheralMutex` being dropped.
68 mutex.register_interrupt_unchecked();
69 }
70} 79}
71 80
72impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I> 81impl<'bus, 'c, B, T, I> Usb<'bus, B, T, I>
@@ -129,7 +138,7 @@ where
129 } 138 }
130} 139}
131 140
132impl<'bus, B, T, I> PeripheralState for State<'bus, B, T, I> 141impl<'bus, B, T, I> PeripheralState for StateInner<'bus, B, T, I>
133where 142where
134 B: UsbBus, 143 B: UsbBus,
135 T: ClassSet<B>, 144 T: ClassSet<B>,
diff --git a/embassy-hal-common/src/usb/usb_serial.rs b/embassy-hal-common/src/usb/usb_serial.rs
index a229b2000..8b27152b5 100644
--- a/embassy-hal-common/src/usb/usb_serial.rs
+++ b/embassy-hal-common/src/usb/usb_serial.rs
@@ -10,9 +10,10 @@ use usb_device::class_prelude::*;
10use usb_device::UsbError; 10use usb_device::UsbError;
11 11
12use super::cdc_acm::CdcAcmClass; 12use super::cdc_acm::CdcAcmClass;
13use super::StateInner;
13use crate::peripheral::PeripheralMutex; 14use crate::peripheral::PeripheralMutex;
14use crate::ring_buffer::RingBuffer; 15use crate::ring_buffer::RingBuffer;
15use crate::usb::{ClassSet, SerialState, State, USBInterrupt}; 16use crate::usb::{ClassSet, SerialState, USBInterrupt};
16 17
17pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT> 18pub struct ReadInterface<'a, 'bus, 'c, I, B, T, INT>
18where 19where
@@ -22,7 +23,7 @@ where
22 INT: USBInterrupt, 23 INT: USBInterrupt,
23{ 24{
24 // Don't you dare moving out `PeripheralMutex` 25 // Don't you dare moving out `PeripheralMutex`
25 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>, 26 pub(crate) inner: &'a RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, INT>>>,
26 pub(crate) _buf_lifetime: PhantomData<&'c T>, 27 pub(crate) _buf_lifetime: PhantomData<&'c T>,
27 pub(crate) _index: PhantomData<I>, 28 pub(crate) _index: PhantomData<I>,
28} 29}
@@ -39,7 +40,7 @@ where
39 INT: USBInterrupt, 40 INT: USBInterrupt,
40{ 41{
41 // Don't you dare moving out `PeripheralMutex` 42 // Don't you dare moving out `PeripheralMutex`
42 pub(crate) inner: &'a RefCell<PeripheralMutex<State<'bus, B, T, INT>>>, 43 pub(crate) inner: &'a RefCell<PeripheralMutex<'bus, StateInner<'bus, B, T, INT>>>,
43 pub(crate) _buf_lifetime: PhantomData<&'c T>, 44 pub(crate) _buf_lifetime: PhantomData<&'c T>,
44 pub(crate) _index: PhantomData<I>, 45 pub(crate) _index: PhantomData<I>,
45} 46}
@@ -54,7 +55,6 @@ where
54 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> { 55 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
55 let this = self.get_mut(); 56 let this = self.get_mut();
56 let mut mutex = this.inner.borrow_mut(); 57 let mut mutex = this.inner.borrow_mut();
57 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
58 mutex.with(|state| { 58 mutex.with(|state| {
59 let serial = state.classes.get_serial(); 59 let serial = state.classes.get_serial();
60 let serial = Pin::new(serial); 60 let serial = Pin::new(serial);
@@ -76,7 +76,6 @@ where
76 fn consume(self: Pin<&mut Self>, amt: usize) { 76 fn consume(self: Pin<&mut Self>, amt: usize) {
77 let this = self.get_mut(); 77 let this = self.get_mut();
78 let mut mutex = this.inner.borrow_mut(); 78 let mut mutex = this.inner.borrow_mut();
79 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
80 mutex.with(|state| { 79 mutex.with(|state| {
81 let serial = state.classes.get_serial(); 80 let serial = state.classes.get_serial();
82 let serial = Pin::new(serial); 81 let serial = Pin::new(serial);
@@ -100,7 +99,6 @@ where
100 ) -> Poll<io::Result<usize>> { 99 ) -> Poll<io::Result<usize>> {
101 let this = self.get_mut(); 100 let this = self.get_mut();
102 let mut mutex = this.inner.borrow_mut(); 101 let mut mutex = this.inner.borrow_mut();
103 let mutex = unsafe { Pin::new_unchecked(&mut *mutex) };
104 mutex.with(|state| { 102 mutex.with(|state| {
105 let serial = state.classes.get_serial(); 103 let serial = state.classes.get_serial();
106 let serial = Pin::new(serial); 104 let serial = Pin::new(serial);
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index d6120bd0c..642c30185 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -7,7 +7,7 @@ use core::task::{Context, Poll};
7use embassy::interrupt::InterruptExt; 7use embassy::interrupt::InterruptExt;
8use embassy::io::{AsyncBufRead, AsyncWrite, Result}; 8use embassy::io::{AsyncBufRead, AsyncWrite, Result};
9use embassy::util::{Unborrow, WakerRegistration}; 9use embassy::util::{Unborrow, WakerRegistration};
10use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState}; 10use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
11use embassy_hal_common::ring_buffer::RingBuffer; 11use embassy_hal_common::ring_buffer::RingBuffer;
12use embassy_hal_common::{low_power_wait_until, unborrow}; 12use embassy_hal_common::{low_power_wait_until, unborrow};
13 13
@@ -35,7 +35,14 @@ enum TxState {
35 Transmitting(usize), 35 Transmitting(usize),
36} 36}
37 37
38struct State<'d, U: UarteInstance, T: TimerInstance> { 38pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>);
39impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> {
40 pub fn new() -> Self {
41 Self(StateStorage::new())
42 }
43}
44
45struct StateInner<'d, U: UarteInstance, T: TimerInstance> {
39 phantom: PhantomData<&'d mut U>, 46 phantom: PhantomData<&'d mut U>,
40 timer: Timer<'d, T>, 47 timer: Timer<'d, T>,
41 _ppi_ch1: Ppi<'d, AnyConfigurableChannel>, 48 _ppi_ch1: Ppi<'d, AnyConfigurableChannel>,
@@ -51,20 +58,16 @@ struct State<'d, U: UarteInstance, T: TimerInstance> {
51} 58}
52 59
53/// Interface to a UARTE instance 60/// Interface to a UARTE instance
54///
55/// This is a very basic interface that comes with the following limitations:
56/// - The UARTE instances share the same address space with instances of UART.
57/// You need to make sure that conflicting instances
58/// are disabled before using `Uarte`. See product specification:
59/// - nrf52832: Section 15.2
60/// - nrf52840: Section 6.1.2
61pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 61pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> {
62 inner: PeripheralMutex<State<'d, U, T>>, 62 inner: PeripheralMutex<'d, StateInner<'d, U, T>>,
63} 63}
64 64
65impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
66
65impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { 67impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
66 /// unsafe: may not leak self or futures 68 /// unsafe: may not leak self or futures
67 pub unsafe fn new( 69 pub unsafe fn new(
70 state: &'d mut State<'d, U, T>,
68 _uarte: impl Unborrow<Target = U> + 'd, 71 _uarte: impl Unborrow<Target = U> + 'd,
69 timer: impl Unborrow<Target = T> + 'd, 72 timer: impl Unborrow<Target = T> + 'd,
70 ppi_ch1: impl Unborrow<Target = impl ConfigurableChannel> + 'd, 73 ppi_ch1: impl Unborrow<Target = impl ConfigurableChannel> + 'd,
@@ -152,31 +155,28 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
152 ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx)); 155 ppi_ch2.set_task(Task::from_reg(&r.tasks_stoprx));
153 ppi_ch2.enable(); 156 ppi_ch2.enable();
154 157
155 BufferedUarte { 158 let initial_state = StateInner {
156 inner: PeripheralMutex::new( 159 phantom: PhantomData,
157 State { 160 timer,
158 phantom: PhantomData, 161 _ppi_ch1: ppi_ch1,
159 timer, 162 _ppi_ch2: ppi_ch2,
160 _ppi_ch1: ppi_ch1, 163
161 _ppi_ch2: ppi_ch2, 164 rx: RingBuffer::new(rx_buffer),
162 165 rx_state: RxState::Idle,
163 rx: RingBuffer::new(rx_buffer), 166 rx_waker: WakerRegistration::new(),
164 rx_state: RxState::Idle, 167
165 rx_waker: WakerRegistration::new(), 168 tx: RingBuffer::new(tx_buffer),
166 169 tx_state: TxState::Idle,
167 tx: RingBuffer::new(tx_buffer), 170 tx_waker: WakerRegistration::new(),
168 tx_state: TxState::Idle, 171 };
169 tx_waker: WakerRegistration::new(), 172
170 }, 173 Self {
171 irq, 174 inner: PeripheralMutex::new_unchecked(&mut state.0, initial_state, irq),
172 ),
173 } 175 }
174 } 176 }
175 177
176 pub fn set_baudrate(self: Pin<&mut Self>, baudrate: Baudrate) { 178 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
177 let mut inner = self.inner(); 179 self.inner.with(|state| {
178 unsafe { inner.as_mut().register_interrupt_unchecked() }
179 inner.with(|state| {
180 let r = U::regs(); 180 let r = U::regs();
181 181
182 let timeout = 0x8000_0000 / (baudrate as u32 / 40); 182 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
@@ -186,17 +186,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
186 r.baudrate.write(|w| w.baudrate().variant(baudrate)); 186 r.baudrate.write(|w| w.baudrate().variant(baudrate));
187 }); 187 });
188 } 188 }
189
190 fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<'d, U, T>>> {
191 unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
192 }
193} 189}
194 190
195impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> { 191impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d, U, T> {
196 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { 192 fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> {
197 let mut inner = self.inner(); 193 self.inner.with(|state| {
198 unsafe { inner.as_mut().register_interrupt_unchecked() }
199 inner.with(|state| {
200 // Conservative compiler fence to prevent optimizations that do not 194 // Conservative compiler fence to prevent optimizations that do not
201 // take in to account actions by DMA. The fence has been placed here, 195 // take in to account actions by DMA. The fence has been placed here,
202 // before any DMA action has started 196 // before any DMA action has started
@@ -218,22 +212,22 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncBufRead for BufferedUarte<'d,
218 }) 212 })
219 } 213 }
220 214
221 fn consume(self: Pin<&mut Self>, amt: usize) { 215 fn consume(mut self: Pin<&mut Self>, amt: usize) {
222 let mut inner = self.inner(); 216 self.inner.with(|state| {
223 unsafe { inner.as_mut().register_interrupt_unchecked() }
224 inner.as_mut().with(|state| {
225 trace!("consume {:?}", amt); 217 trace!("consume {:?}", amt);
226 state.rx.pop(amt); 218 state.rx.pop(amt);
227 }); 219 });
228 inner.pend(); 220 self.inner.pend();
229 } 221 }
230} 222}
231 223
232impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, T> { 224impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U, T> {
233 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { 225 fn poll_write(
234 let mut inner = self.inner(); 226 mut self: Pin<&mut Self>,
235 unsafe { inner.as_mut().register_interrupt_unchecked() } 227 cx: &mut Context<'_>,
236 let poll = inner.as_mut().with(|state| { 228 buf: &[u8],
229 ) -> Poll<Result<usize>> {
230 let poll = self.inner.with(|state| {
237 trace!("poll_write: {:?}", buf.len()); 231 trace!("poll_write: {:?}", buf.len());
238 232
239 let tx_buf = state.tx.push_buf(); 233 let tx_buf = state.tx.push_buf();
@@ -257,13 +251,13 @@ impl<'d, U: UarteInstance, T: TimerInstance> AsyncWrite for BufferedUarte<'d, U,
257 Poll::Ready(Ok(n)) 251 Poll::Ready(Ok(n))
258 }); 252 });
259 253
260 inner.pend(); 254 self.inner.pend();
261 255
262 poll 256 poll
263 } 257 }
264} 258}
265 259
266impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> { 260impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
267 fn drop(&mut self) { 261 fn drop(&mut self) {
268 let r = U::regs(); 262 let r = U::regs();
269 263
@@ -285,7 +279,7 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for State<'a, U, T> {
285 } 279 }
286} 280}
287 281
288impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for State<'a, U, T> { 282impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> {
289 type Interrupt = U::Interrupt; 283 type Interrupt = U::Interrupt;
290 fn on_interrupt(&mut self) { 284 fn on_interrupt(&mut self) {
291 trace!("irq: start"); 285 trace!("irq: start");
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 3f72fb35e..2c73e0d03 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,10 +1,9 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::pin::Pin;
3use core::sync::atomic::{fence, Ordering}; 2use core::sync::atomic::{fence, Ordering};
4use core::task::Waker; 3use core::task::Waker;
5 4
6use embassy::util::{AtomicWaker, Unborrow}; 5use embassy::util::{AtomicWaker, Unborrow};
7use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState}; 6use embassy_hal_common::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
8use embassy_hal_common::unborrow; 7use embassy_hal_common::unborrow;
9use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; 8use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
10 9
@@ -19,8 +18,14 @@ mod descriptors;
19use super::{StationManagement, PHY}; 18use super::{StationManagement, PHY};
20use descriptors::DescriptorRing; 19use descriptors::DescriptorRing;
21 20
21pub struct State<'d, const TX: usize, const RX: usize>(StateStorage<Inner<'d, TX, RX>>);
22impl<'d, const TX: usize, const RX: usize> State<'d, TX, RX> {
23 pub fn new() -> Self {
24 Self(StateStorage::new())
25 }
26}
22pub struct Ethernet<'d, P: PHY, const TX: usize, const RX: usize> { 27pub struct Ethernet<'d, P: PHY, const TX: usize, const RX: usize> {
23 state: PeripheralMutex<Inner<'d, TX, RX>>, 28 state: PeripheralMutex<'d, Inner<'d, TX, RX>>,
24 pins: [AnyPin; 9], 29 pins: [AnyPin; 9],
25 _phy: P, 30 _phy: P,
26 clock_range: u8, 31 clock_range: u8,
@@ -30,6 +35,7 @@ pub struct Ethernet<'d, P: PHY, const TX: usize, const RX: usize> {
30 35
31impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> { 36impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> {
32 pub fn new( 37 pub fn new(
38 state: &'d mut State<'d, TX, RX>,
33 peri: impl Unborrow<Target = peripherals::ETH> + 'd, 39 peri: impl Unborrow<Target = peripherals::ETH> + 'd,
34 interrupt: impl Unborrow<Target = crate::interrupt::ETH> + 'd, 40 interrupt: impl Unborrow<Target = crate::interrupt::ETH> + 'd,
35 ref_clk: impl Unborrow<Target = impl RefClkPin> + 'd, 41 ref_clk: impl Unborrow<Target = impl RefClkPin> + 'd,
@@ -72,7 +78,7 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> {
72 tx_en.configure(); 78 tx_en.configure();
73 79
74 let inner = Inner::new(peri); 80 let inner = Inner::new(peri);
75 let state = PeripheralMutex::new(inner, interrupt); 81 let state = unsafe { PeripheralMutex::new_unchecked(&mut state.0, inner, interrupt) };
76 82
77 // NOTE(unsafe) We have exclusive access to the registers 83 // NOTE(unsafe) We have exclusive access to the registers
78 unsafe { 84 unsafe {
@@ -145,24 +151,16 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> {
145 tx_en.degrade(), 151 tx_en.degrade(),
146 ]; 152 ];
147 153
148 Self { 154 let mut this = Self {
149 state, 155 state,
150 pins, 156 pins,
151 _phy: phy, 157 _phy: phy,
152 clock_range, 158 clock_range,
153 phy_addr, 159 phy_addr,
154 mac_addr, 160 mac_addr,
155 } 161 };
156 }
157
158 pub fn init(self: Pin<&mut Self>) {
159 // NOTE(unsafe) We won't move this
160 let this = unsafe { self.get_unchecked_mut() };
161 let mut mutex = unsafe { Pin::new_unchecked(&mut this.state) };
162 // SAFETY: The lifetime of `Inner` is only due to `PhantomData`; it isn't actually referencing any data with that lifetime.
163 unsafe { mutex.as_mut().register_interrupt_unchecked() }
164 162
165 mutex.with(|s| { 163 this.state.with(|s| {
166 s.desc_ring.init(); 164 s.desc_ring.init();
167 165
168 fence(Ordering::SeqCst); 166 fence(Ordering::SeqCst);
@@ -189,8 +187,10 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, P, TX, RX> {
189 }); 187 });
190 } 188 }
191 }); 189 });
192 P::phy_reset(this); 190 P::phy_reset(&mut this);
193 P::phy_init(this); 191 P::phy_init(&mut this);
192
193 this
194 } 194 }
195} 195}
196 196
@@ -232,29 +232,17 @@ unsafe impl<'d, P: PHY, const TX: usize, const RX: usize> StationManagement
232 } 232 }
233} 233}
234 234
235impl<'d, P: PHY, const TX: usize, const RX: usize> Device for Pin<&mut Ethernet<'d, P, TX, RX>> { 235impl<'d, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, P, TX, RX> {
236 fn is_transmit_ready(&mut self) -> bool { 236 fn is_transmit_ready(&mut self) -> bool {
237 // NOTE(unsafe) We won't move out of self 237 self.state.with(|s| s.desc_ring.tx.available())
238 let this = unsafe { self.as_mut().get_unchecked_mut() };
239 let mutex = unsafe { Pin::new_unchecked(&mut this.state) };
240
241 mutex.with(|s| s.desc_ring.tx.available())
242 } 238 }
243 239
244 fn transmit(&mut self, pkt: PacketBuf) { 240 fn transmit(&mut self, pkt: PacketBuf) {
245 // NOTE(unsafe) We won't move out of self 241 self.state.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt)));
246 let this = unsafe { self.as_mut().get_unchecked_mut() };
247 let mutex = unsafe { Pin::new_unchecked(&mut this.state) };
248
249 mutex.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt)));
250 } 242 }
251 243
252 fn receive(&mut self) -> Option<PacketBuf> { 244 fn receive(&mut self) -> Option<PacketBuf> {
253 // NOTE(unsafe) We won't move out of self 245 self.state.with(|s| s.desc_ring.rx.pop_packet())
254 let this = unsafe { self.as_mut().get_unchecked_mut() };
255 let mutex = unsafe { Pin::new_unchecked(&mut this.state) };
256
257 mutex.with(|s| s.desc_ring.rx.pop_packet())
258 } 246 }
259 247
260 fn register_waker(&mut self, waker: &Waker) { 248 fn register_waker(&mut self, waker: &Waker) {
@@ -269,10 +257,7 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Device for Pin<&mut Ethernet<
269 } 257 }
270 258
271 fn link_state(&mut self) -> LinkState { 259 fn link_state(&mut self) -> LinkState {
272 // NOTE(unsafe) We won't move out of self 260 if P::poll_link(self) {
273 let this = unsafe { self.as_mut().get_unchecked_mut() };
274
275 if P::poll_link(this) {
276 LinkState::Up 261 LinkState::Up
277 } else { 262 } else {
278 LinkState::Down 263 LinkState::Down
@@ -280,10 +265,7 @@ impl<'d, P: PHY, const TX: usize, const RX: usize> Device for Pin<&mut Ethernet<
280 } 265 }
281 266
282 fn ethernet_address(&mut self) -> [u8; 6] { 267 fn ethernet_address(&mut self) -> [u8; 6] {
283 // NOTE(unsafe) We won't move out of self 268 self.mac_addr
284 let this = unsafe { self.as_mut().get_unchecked_mut() };
285
286 this.mac_addr
287 } 269 }
288} 270}
289 271
diff --git a/examples/nrf/src/bin/buffered_uart.rs b/examples/nrf/src/bin/buffered_uart.rs
index c800e64fc..a78d2df44 100644
--- a/examples/nrf/src/bin/buffered_uart.rs
+++ b/examples/nrf/src/bin/buffered_uart.rs
@@ -11,6 +11,7 @@ mod example_common;
11use defmt::panic; 11use defmt::panic;
12use embassy::executor::Spawner; 12use embassy::executor::Spawner;
13use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; 13use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
14use embassy_nrf::buffered_uarte::State;
14use embassy_nrf::gpio::NoPin; 15use embassy_nrf::gpio::NoPin;
15use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals}; 16use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals};
16use example_common::*; 17use example_common::*;
@@ -26,8 +27,10 @@ async fn main(_spawner: Spawner, p: Peripherals) {
26 let mut rx_buffer = [0u8; 4096]; 27 let mut rx_buffer = [0u8; 4096];
27 28
28 let irq = interrupt::take!(UARTE0_UART0); 29 let irq = interrupt::take!(UARTE0_UART0);
30 let mut state = State::new();
29 let u = unsafe { 31 let u = unsafe {
30 BufferedUarte::new( 32 BufferedUarte::new(
33 &mut state,
31 p.UARTE0, 34 p.UARTE0,
32 p.TIMER0, 35 p.TIMER0,
33 p.PPI_CH0, 36 p.PPI_CH0,
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 7ae80d6e3..5cf49e82f 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -6,7 +6,6 @@
6#![feature(impl_trait_in_bindings)] 6#![feature(impl_trait_in_bindings)]
7#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
8 8
9use core::pin::Pin;
10use core::sync::atomic::{AtomicUsize, Ordering}; 9use core::sync::atomic::{AtomicUsize, Ordering};
11 10
12use cortex_m_rt::entry; 11use cortex_m_rt::entry;
@@ -22,7 +21,7 @@ use embassy_net::{
22}; 21};
23use embassy_stm32::clock::{Alarm, Clock}; 22use embassy_stm32::clock::{Alarm, Clock};
24use embassy_stm32::eth::lan8742a::LAN8742A; 23use embassy_stm32::eth::lan8742a::LAN8742A;
25use embassy_stm32::eth::Ethernet; 24use embassy_stm32::eth::{Ethernet, State};
26use embassy_stm32::rcc::{Config as RccConfig, Rcc}; 25use embassy_stm32::rcc::{Config as RccConfig, Rcc};
27use embassy_stm32::rng::Random; 26use embassy_stm32::rng::Random;
28use embassy_stm32::time::Hertz; 27use embassy_stm32::time::Hertz;
@@ -42,7 +41,7 @@ defmt::timestamp! {"{=u64}", {
42 41
43#[embassy::task] 42#[embassy::task]
44async fn main_task( 43async fn main_task(
45 device: &'static mut Pin<&'static mut Ethernet<'static, LAN8742A, 4, 4>>, 44 device: &'static mut Ethernet<'static, LAN8742A, 4, 4>,
46 config: &'static mut StaticConfigurator, 45 config: &'static mut StaticConfigurator,
47 spawner: Spawner, 46 spawner: Spawner,
48) { 47) {
@@ -99,8 +98,8 @@ static mut RNG_INST: Option<Random<RNG>> = None;
99static EXECUTOR: Forever<Executor> = Forever::new(); 98static EXECUTOR: Forever<Executor> = Forever::new();
100static TIMER_RTC: Forever<Clock<TIM2>> = Forever::new(); 99static TIMER_RTC: Forever<Clock<TIM2>> = Forever::new();
101static ALARM: Forever<Alarm<TIM2>> = Forever::new(); 100static ALARM: Forever<Alarm<TIM2>> = Forever::new();
101static STATE: Forever<State<'static, 4, 4>> = Forever::new();
102static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new(); 102static ETH: Forever<Ethernet<'static, LAN8742A, 4, 4>> = Forever::new();
103static DEVICE: Forever<Pin<&'static mut Ethernet<'static, LAN8742A, 4, 4>>> = Forever::new();
104static CONFIG: Forever<StaticConfigurator> = Forever::new(); 103static CONFIG: Forever<StaticConfigurator> = Forever::new();
105static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new(); 104static NET_RESOURCES: Forever<StackResources<1, 2, 8>> = Forever::new();
106 105
@@ -135,15 +134,12 @@ fn main() -> ! {
135 134
136 let eth_int = interrupt_take!(ETH); 135 let eth_int = interrupt_take!(ETH);
137 let mac_addr = [0x10; 6]; 136 let mac_addr = [0x10; 6];
137 let state = STATE.put(State::new());
138 let eth = ETH.put(Ethernet::new( 138 let eth = ETH.put(Ethernet::new(
139 p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PB12, p.PB13, p.PB11, LAN8742A, 139 state, p.ETH, eth_int, p.PA1, p.PA2, p.PC1, p.PA7, p.PC4, p.PC5, p.PB12, p.PB13, p.PB11,
140 mac_addr, 1, 140 LAN8742A, mac_addr, 1,
141 )); 141 ));
142 142
143 // NOTE(unsafe) This thing is a &'static
144 let net_device = DEVICE.put(unsafe { Pin::new_unchecked(eth) });
145 net_device.as_mut().init();
146
147 let config = StaticConfigurator::new(NetConfig { 143 let config = StaticConfigurator::new(NetConfig {
148 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 0, 61), 24), 144 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 0, 61), 24),
149 dns_servers: Vec::new(), 145 dns_servers: Vec::new(),
@@ -156,6 +152,6 @@ fn main() -> ! {
156 executor.set_alarm(alarm); 152 executor.set_alarm(alarm);
157 153
158 executor.run(move |spawner| { 154 executor.run(move |spawner| {
159 unwrap!(spawner.spawn(main_task(net_device, config, spawner))); 155 unwrap!(spawner.spawn(main_task(eth, config, spawner)));
160 }) 156 })
161} 157}