diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-01-03 01:40:40 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-01-03 01:40:40 +0100 |
| commit | ace4f40f8089f8cebbac023a4a1b960d976d2776 (patch) | |
| tree | da6148458eb7e98727df2c2f008aac3d66be8e6e | |
| parent | 4ce51795f2f4a9d6803dc4101b04f2a191f8d39d (diff) | |
Introduce "peripheral" abstraction to share state between main and interrupt.
| -rw-r--r-- | embassy-nrf-examples/.cargo/config | 6 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/buffered_uart.rs | 11 | ||||
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 303 | ||||
| -rw-r--r-- | embassy-nrf/src/lib.rs | 1 | ||||
| -rw-r--r-- | embassy-nrf/src/util/mod.rs | 2 | ||||
| -rw-r--r-- | embassy-nrf/src/util/peripheral.rs | 107 | ||||
| -rw-r--r-- | embassy-nrf/src/util/ring_buffer.rs | 80 |
7 files changed, 298 insertions, 212 deletions
diff --git a/embassy-nrf-examples/.cargo/config b/embassy-nrf-examples/.cargo/config index 3f319ae55..591288879 100644 --- a/embassy-nrf-examples/.cargo/config +++ b/embassy-nrf-examples/.cargo/config | |||
| @@ -20,8 +20,4 @@ rustflags = [ | |||
| 20 | ] | 20 | ] |
| 21 | 21 | ||
| 22 | [build] | 22 | [build] |
| 23 | # Pick ONE of these compilation targets | 23 | target = "thumbv7em-none-eabi" |
| 24 | # target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ | ||
| 25 | # target = "thumbv7m-none-eabi" # Cortex-M3 | ||
| 26 | # target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) | ||
| 27 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index 6e15fbcfa..68a76f71e 100644 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs | |||
| @@ -8,15 +8,17 @@ use example_common::*; | |||
| 8 | 8 | ||
| 9 | use cortex_m_rt::entry; | 9 | use cortex_m_rt::entry; |
| 10 | use defmt::panic; | 10 | use defmt::panic; |
| 11 | use futures::pin_mut; | ||
| 12 | use nrf52840_hal::gpio; | 11 | use nrf52840_hal::gpio; |
| 13 | 12 | ||
| 14 | use embassy::executor::{task, Executor}; | 13 | use embassy::executor::{task, Executor}; |
| 15 | use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; | 14 | use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; |
| 16 | use embassy::util::Forever; | 15 | use embassy::util::Forever; |
| 17 | use embassy_nrf::buffered_uarte; | 16 | use embassy_nrf::buffered_uarte; |
| 18 | use embassy_nrf::interrupt; | 17 | use embassy_nrf::interrupt; |
| 19 | 18 | ||
| 19 | static mut TX_BUFFER: [u8; 4096] = [0; 4096]; | ||
| 20 | static mut RX_BUFFER: [u8; 4096] = [0; 4096]; | ||
| 21 | |||
| 20 | #[task] | 22 | #[task] |
| 21 | async fn run() { | 23 | async fn run() { |
| 22 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | 24 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); |
| @@ -34,14 +36,15 @@ async fn run() { | |||
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 36 | let irq = interrupt::take!(UARTE0_UART0); | 38 | let irq = interrupt::take!(UARTE0_UART0); |
| 37 | let u = buffered_uarte::BufferedUarte::new( | 39 | let mut u = buffered_uarte::BufferedUarte::new( |
| 38 | p.UARTE0, | 40 | p.UARTE0, |
| 39 | irq, | 41 | irq, |
| 42 | unsafe { &mut RX_BUFFER }, | ||
| 43 | unsafe { &mut TX_BUFFER }, | ||
| 40 | pins, | 44 | pins, |
| 41 | buffered_uarte::Parity::EXCLUDED, | 45 | buffered_uarte::Parity::EXCLUDED, |
| 42 | buffered_uarte::Baudrate::BAUD115200, | 46 | buffered_uarte::Baudrate::BAUD115200, |
| 43 | ); | 47 | ); |
| 44 | pin_mut!(u); | ||
| 45 | 48 | ||
| 46 | info!("uarte initialized!"); | 49 | info!("uarte initialized!"); |
| 47 | 50 | ||
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 9863e3fab..4749c3b45 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -4,107 +4,29 @@ | |||
| 4 | //! | 4 | //! |
| 5 | //! - nrf52832: Section 35 | 5 | //! - nrf52832: Section 35 |
| 6 | //! - nrf52840: Section 6.34 | 6 | //! - nrf52840: Section 6.34 |
| 7 | use core::cell::UnsafeCell; | ||
| 8 | use core::cmp::min; | 7 | use core::cmp::min; |
| 9 | use core::marker::PhantomPinned; | 8 | use core::marker::PhantomData; |
| 9 | use core::mem; | ||
| 10 | use core::ops::Deref; | 10 | use core::ops::Deref; |
| 11 | use core::pin::Pin; | 11 | use core::pin::Pin; |
| 12 | use core::ptr; | ||
| 13 | use core::sync::atomic::{compiler_fence, Ordering}; | 12 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 14 | use core::task::{Context, Poll}; | 13 | use core::task::{Context, Poll}; |
| 15 | use embassy::io::{AsyncBufRead, AsyncWrite, Result}; | 14 | use embassy::io::{AsyncBufRead, AsyncWrite, Result}; |
| 16 | use embassy::util::WakerRegistration; | 15 | use embassy::util::WakerRegistration; |
| 17 | use embedded_hal::digital::v2::OutputPin; | 16 | use embedded_hal::digital::v2::OutputPin; |
| 18 | 17 | ||
| 19 | use crate::fmt::{assert, panic, todo, *}; | 18 | use crate::fmt::{panic, todo, *}; |
| 20 | use crate::hal::gpio::Port as GpioPort; | 19 | use crate::hal::gpio::Port as GpioPort; |
| 21 | use crate::interrupt::{self, CriticalSection, OwnedInterrupt}; | 20 | use crate::interrupt::{self, OwnedInterrupt}; |
| 21 | use crate::pac; | ||
| 22 | use crate::pac::uarte0; | 22 | use crate::pac::uarte0; |
| 23 | use crate::util::peripheral; | ||
| 24 | use crate::util::ring_buffer::RingBuffer; | ||
| 23 | 25 | ||
| 24 | // Re-export SVD variants to allow user to directly set values | 26 | // Re-export SVD variants to allow user to directly set values |
| 25 | pub use crate::hal::uarte::Pins; | 27 | pub use crate::hal::uarte::Pins; |
| 26 | pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 28 | pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 27 | 29 | ||
| 28 | const RINGBUF_SIZE: usize = 512; | ||
| 29 | struct RingBuf { | ||
| 30 | buf: [u8; RINGBUF_SIZE], | ||
| 31 | start: usize, | ||
| 32 | end: usize, | ||
| 33 | empty: bool, | ||
| 34 | } | ||
| 35 | |||
| 36 | impl RingBuf { | ||
| 37 | fn new() -> Self { | ||
| 38 | RingBuf { | ||
| 39 | buf: [0; RINGBUF_SIZE], | ||
| 40 | start: 0, | ||
| 41 | end: 0, | ||
| 42 | empty: true, | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | fn push_buf(&mut self) -> &mut [u8] { | ||
| 47 | if self.start == self.end && !self.empty { | ||
| 48 | trace!(" ringbuf: push_buf empty"); | ||
| 49 | return &mut self.buf[..0]; | ||
| 50 | } | ||
| 51 | |||
| 52 | let n = if self.start <= self.end { | ||
| 53 | RINGBUF_SIZE - self.end | ||
| 54 | } else { | ||
| 55 | self.start - self.end | ||
| 56 | }; | ||
| 57 | |||
| 58 | trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); | ||
| 59 | &mut self.buf[self.end..self.end + n] | ||
| 60 | } | ||
| 61 | |||
| 62 | fn push(&mut self, n: usize) { | ||
| 63 | trace!(" ringbuf: push {:?}", n); | ||
| 64 | if n == 0 { | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | self.end = Self::wrap(self.end + n); | ||
| 69 | self.empty = false; | ||
| 70 | } | ||
| 71 | |||
| 72 | fn pop_buf(&mut self) -> &mut [u8] { | ||
| 73 | if self.empty { | ||
| 74 | trace!(" ringbuf: pop_buf empty"); | ||
| 75 | return &mut self.buf[..0]; | ||
| 76 | } | ||
| 77 | |||
| 78 | let n = if self.end <= self.start { | ||
| 79 | RINGBUF_SIZE - self.start | ||
| 80 | } else { | ||
| 81 | self.end - self.start | ||
| 82 | }; | ||
| 83 | |||
| 84 | trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); | ||
| 85 | &mut self.buf[self.start..self.start + n] | ||
| 86 | } | ||
| 87 | |||
| 88 | fn pop(&mut self, n: usize) { | ||
| 89 | trace!(" ringbuf: pop {:?}", n); | ||
| 90 | if n == 0 { | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | self.start = Self::wrap(self.start + n); | ||
| 95 | self.empty = self.start == self.end; | ||
| 96 | } | ||
| 97 | |||
| 98 | fn wrap(n: usize) -> usize { | ||
| 99 | assert!(n <= RINGBUF_SIZE); | ||
| 100 | if n == RINGBUF_SIZE { | ||
| 101 | 0 | ||
| 102 | } else { | ||
| 103 | n | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | #[derive(Copy, Clone, Debug, PartialEq)] | 30 | #[derive(Copy, Clone, Debug, PartialEq)] |
| 109 | enum RxState { | 31 | enum RxState { |
| 110 | Idle, | 32 | Idle, |
| @@ -126,28 +48,12 @@ enum TxState { | |||
| 126 | /// are disabled before using `Uarte`. See product specification: | 48 | /// are disabled before using `Uarte`. See product specification: |
| 127 | /// - nrf52832: Section 15.2 | 49 | /// - nrf52832: Section 15.2 |
| 128 | /// - nrf52840: Section 6.1.2 | 50 | /// - nrf52840: Section 6.1.2 |
| 129 | pub struct BufferedUarte<T: Instance> { | 51 | pub struct BufferedUarte<'a, T: Instance> { |
| 130 | started: bool, | 52 | reg: peripheral::Registration<State<'a, T>>, |
| 131 | state: UnsafeCell<UarteState<T>>, | 53 | wtf: PhantomData<&'a ()>, |
| 132 | } | 54 | } |
| 133 | 55 | ||
| 134 | // public because it needs to be used in Instance::{get_state, set_state}, but | 56 | impl<'a, T: Instance> Unpin for BufferedUarte<'a, T> {} |
| 135 | // should not be used outside the module | ||
| 136 | #[doc(hidden)] | ||
| 137 | pub struct UarteState<T: Instance> { | ||
| 138 | inner: T, | ||
| 139 | irq: T::Interrupt, | ||
| 140 | |||
| 141 | rx: RingBuf, | ||
| 142 | rx_state: RxState, | ||
| 143 | rx_waker: WakerRegistration, | ||
| 144 | |||
| 145 | tx: RingBuf, | ||
| 146 | tx_state: TxState, | ||
| 147 | tx_waker: WakerRegistration, | ||
| 148 | |||
| 149 | _pin: PhantomPinned, | ||
| 150 | } | ||
| 151 | 57 | ||
| 152 | #[cfg(any(feature = "52833", feature = "52840"))] | 58 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 153 | fn port_bit(port: GpioPort) -> bool { | 59 | fn port_bit(port: GpioPort) -> bool { |
| @@ -157,10 +63,12 @@ fn port_bit(port: GpioPort) -> bool { | |||
| 157 | } | 63 | } |
| 158 | } | 64 | } |
| 159 | 65 | ||
| 160 | impl<T: Instance> BufferedUarte<T> { | 66 | impl<'a, T: Instance> BufferedUarte<'a, T> { |
| 161 | pub fn new( | 67 | pub fn new( |
| 162 | uarte: T, | 68 | uarte: T, |
| 163 | irq: T::Interrupt, | 69 | irq: T::Interrupt, |
| 70 | rx_buffer: &'a mut [u8], | ||
| 71 | tx_buffer: &'a mut [u8], | ||
| 164 | mut pins: Pins, | 72 | mut pins: Pins, |
| 165 | parity: Parity, | 73 | parity: Parity, |
| 166 | baudrate: Baudrate, | 74 | baudrate: Baudrate, |
| @@ -218,87 +126,79 @@ impl<T: Instance> BufferedUarte<T> { | |||
| 218 | // Configure frequency | 126 | // Configure frequency |
| 219 | uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); | 127 | uarte.baudrate.write(|w| w.baudrate().variant(baudrate)); |
| 220 | 128 | ||
| 129 | irq.pend(); | ||
| 130 | |||
| 221 | BufferedUarte { | 131 | BufferedUarte { |
| 222 | started: false, | 132 | reg: peripheral::Registration::new( |
| 223 | state: UnsafeCell::new(UarteState { | ||
| 224 | inner: uarte, | ||
| 225 | irq, | 133 | irq, |
| 226 | 134 | State { | |
| 227 | rx: RingBuf::new(), | 135 | inner: uarte, |
| 228 | rx_state: RxState::Idle, | 136 | |
| 229 | rx_waker: WakerRegistration::new(), | 137 | rx: RingBuffer::new(rx_buffer), |
| 230 | 138 | rx_state: RxState::Idle, | |
| 231 | tx: RingBuf::new(), | 139 | rx_waker: WakerRegistration::new(), |
| 232 | tx_state: TxState::Idle, | 140 | |
| 233 | tx_waker: WakerRegistration::new(), | 141 | tx: RingBuffer::new(tx_buffer), |
| 234 | 142 | tx_state: TxState::Idle, | |
| 235 | _pin: PhantomPinned, | 143 | tx_waker: WakerRegistration::new(), |
| 236 | }), | 144 | }, |
| 145 | ), | ||
| 146 | wtf: PhantomData, | ||
| 237 | } | 147 | } |
| 238 | } | 148 | } |
| 239 | |||
| 240 | fn with_state<'a, R>( | ||
| 241 | self: Pin<&'a mut Self>, | ||
| 242 | f: impl FnOnce(Pin<&'a mut UarteState<T>>) -> R, | ||
| 243 | ) -> R { | ||
| 244 | let Self { state, started } = unsafe { self.get_unchecked_mut() }; | ||
| 245 | |||
| 246 | interrupt::free(|cs| { | ||
| 247 | let ptr = state.get(); | ||
| 248 | |||
| 249 | if !*started { | ||
| 250 | T::set_state(cs, ptr); | ||
| 251 | |||
| 252 | *started = true; | ||
| 253 | |||
| 254 | // safety: safe because critical section ensures only one *mut UartState | ||
| 255 | // exists at the same time. | ||
| 256 | unsafe { Pin::new_unchecked(&mut *ptr) }.start(); | ||
| 257 | } | ||
| 258 | |||
| 259 | // safety: safe because critical section ensures only one *mut UartState | ||
| 260 | // exists at the same time. | ||
| 261 | f(unsafe { Pin::new_unchecked(&mut *ptr) }) | ||
| 262 | }) | ||
| 263 | } | ||
| 264 | } | 149 | } |
| 265 | 150 | ||
| 266 | impl<T: Instance> Drop for BufferedUarte<T> { | 151 | impl<'a, T: Instance> Drop for BufferedUarte<'a, T> { |
| 267 | fn drop(&mut self) { | 152 | fn drop(&mut self) { |
| 268 | // stop DMA before dropping, because DMA is using the buffer in `self`. | 153 | // stop DMA before dropping, because DMA is using the buffer in `self`. |
| 269 | todo!() | 154 | todo!() |
| 270 | } | 155 | } |
| 271 | } | 156 | } |
| 272 | 157 | ||
| 273 | impl<T: Instance> AsyncBufRead for BufferedUarte<T> { | 158 | impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> { |
| 274 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 159 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { |
| 275 | self.with_state(|s| s.poll_fill_buf(cx)) | 160 | let this = unsafe { self.get_unchecked_mut() }; |
| 161 | this.reg.with(|state, _| { | ||
| 162 | let z: Poll<Result<&[u8]>> = state.poll_fill_buf(cx); | ||
| 163 | let z: Poll<Result<&[u8]>> = unsafe { mem::transmute(z) }; | ||
| 164 | z | ||
| 165 | }) | ||
| 276 | } | 166 | } |
| 277 | 167 | ||
| 278 | fn consume(self: Pin<&mut Self>, amt: usize) { | 168 | fn consume(self: Pin<&mut Self>, amt: usize) { |
| 279 | self.with_state(|s| s.consume(amt)) | 169 | let this = unsafe { self.get_unchecked_mut() }; |
| 170 | this.reg.with(|state, irq| state.consume(irq, amt)) | ||
| 280 | } | 171 | } |
| 281 | } | 172 | } |
| 282 | 173 | ||
| 283 | impl<T: Instance> AsyncWrite for BufferedUarte<T> { | 174 | impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> { |
| 284 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 175 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { |
| 285 | self.with_state(|s| s.poll_write(cx, buf)) | 176 | let this = unsafe { self.get_unchecked_mut() }; |
| 177 | this.reg.with(|state, irq| state.poll_write(irq, cx, buf)) | ||
| 286 | } | 178 | } |
| 287 | } | 179 | } |
| 288 | 180 | ||
| 289 | impl<T: Instance> UarteState<T> { | 181 | // ==================================== |
| 290 | pub fn start(self: Pin<&mut Self>) { | 182 | // ==================================== |
| 291 | self.irq.set_handler(|| unsafe { | 183 | // ==================================== |
| 292 | interrupt::free(|cs| T::get_state(cs).as_mut().unwrap().on_interrupt()); | ||
| 293 | }); | ||
| 294 | 184 | ||
| 295 | self.irq.pend(); | 185 | // public because it needs to be used in Instance trait, but |
| 296 | self.irq.enable(); | 186 | // should not be used outside the module |
| 297 | } | 187 | #[doc(hidden)] |
| 188 | pub struct State<'a, T: Instance> { | ||
| 189 | inner: T, | ||
| 298 | 190 | ||
| 299 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 191 | rx: RingBuffer<'a>, |
| 300 | let this = unsafe { self.get_unchecked_mut() }; | 192 | rx_state: RxState, |
| 193 | rx_waker: WakerRegistration, | ||
| 194 | |||
| 195 | tx: RingBuffer<'a>, | ||
| 196 | tx_state: TxState, | ||
| 197 | tx_waker: WakerRegistration, | ||
| 198 | } | ||
| 301 | 199 | ||
| 200 | impl<'a, T: Instance> State<'a, T> { | ||
| 201 | fn poll_fill_buf(&mut self, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | ||
| 302 | // Conservative compiler fence to prevent optimizations that do not | 202 | // Conservative compiler fence to prevent optimizations that do not |
| 303 | // take in to account actions by DMA. The fence has been placed here, | 203 | // take in to account actions by DMA. The fence has been placed here, |
| 304 | // before any DMA action has started | 204 | // before any DMA action has started |
| @@ -306,7 +206,7 @@ impl<T: Instance> UarteState<T> { | |||
| 306 | trace!("poll_read"); | 206 | trace!("poll_read"); |
| 307 | 207 | ||
| 308 | // We have data ready in buffer? Return it. | 208 | // We have data ready in buffer? Return it. |
| 309 | let buf = this.rx.pop_buf(); | 209 | let buf = self.rx.pop_buf(); |
| 310 | if buf.len() != 0 { | 210 | if buf.len() != 0 { |
| 311 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | 211 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); |
| 312 | return Poll::Ready(Ok(buf)); | 212 | return Poll::Ready(Ok(buf)); |
| @@ -314,38 +214,40 @@ impl<T: Instance> UarteState<T> { | |||
| 314 | 214 | ||
| 315 | trace!(" empty"); | 215 | trace!(" empty"); |
| 316 | 216 | ||
| 317 | if this.rx_state == RxState::ReceivingReady { | 217 | if self.rx_state == RxState::ReceivingReady { |
| 318 | trace!(" stopping"); | 218 | trace!(" stopping"); |
| 319 | this.rx_state = RxState::Stopping; | 219 | self.rx_state = RxState::Stopping; |
| 320 | this.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 220 | self.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); |
| 321 | } | 221 | } |
| 322 | 222 | ||
| 323 | this.rx_waker.register(cx.waker()); | 223 | self.rx_waker.register(cx.waker()); |
| 324 | Poll::Pending | 224 | Poll::Pending |
| 325 | } | 225 | } |
| 326 | 226 | ||
| 327 | fn consume(self: Pin<&mut Self>, amt: usize) { | 227 | fn consume(&mut self, irq: &mut T::Interrupt, amt: usize) { |
| 328 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 329 | trace!("consume {:?}", amt); | 228 | trace!("consume {:?}", amt); |
| 330 | this.rx.pop(amt); | 229 | self.rx.pop(amt); |
| 331 | this.irq.pend(); | 230 | irq.pend(); |
| 332 | } | 231 | } |
| 333 | 232 | ||
| 334 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 233 | fn poll_write( |
| 335 | let this = unsafe { self.get_unchecked_mut() }; | 234 | &mut self, |
| 336 | 235 | irq: &mut T::Interrupt, | |
| 236 | cx: &mut Context<'_>, | ||
| 237 | buf: &[u8], | ||
| 238 | ) -> Poll<Result<usize>> { | ||
| 337 | trace!("poll_write: {:?}", buf.len()); | 239 | trace!("poll_write: {:?}", buf.len()); |
| 338 | 240 | ||
| 339 | let tx_buf = this.tx.push_buf(); | 241 | let tx_buf = self.tx.push_buf(); |
| 340 | if tx_buf.len() == 0 { | 242 | if tx_buf.len() == 0 { |
| 341 | trace!("poll_write: pending"); | 243 | trace!("poll_write: pending"); |
| 342 | this.tx_waker.register(cx.waker()); | 244 | self.tx_waker.register(cx.waker()); |
| 343 | return Poll::Pending; | 245 | return Poll::Pending; |
| 344 | } | 246 | } |
| 345 | 247 | ||
| 346 | let n = min(tx_buf.len(), buf.len()); | 248 | let n = min(tx_buf.len(), buf.len()); |
| 347 | tx_buf[..n].copy_from_slice(&buf[..n]); | 249 | tx_buf[..n].copy_from_slice(&buf[..n]); |
| 348 | this.tx.push(n); | 250 | self.tx.push(n); |
| 349 | 251 | ||
| 350 | trace!("poll_write: queued {:?}", n); | 252 | trace!("poll_write: queued {:?}", n); |
| 351 | 253 | ||
| @@ -354,10 +256,17 @@ impl<T: Instance> UarteState<T> { | |||
| 354 | // before any DMA action has started | 256 | // before any DMA action has started |
| 355 | compiler_fence(Ordering::SeqCst); | 257 | compiler_fence(Ordering::SeqCst); |
| 356 | 258 | ||
| 357 | this.irq.pend(); | 259 | irq.pend(); |
| 358 | 260 | ||
| 359 | Poll::Ready(Ok(n)) | 261 | Poll::Ready(Ok(n)) |
| 360 | } | 262 | } |
| 263 | } | ||
| 264 | |||
| 265 | impl<'a, T: Instance> peripheral::State for State<'a, T> { | ||
| 266 | type Interrupt = T::Interrupt; | ||
| 267 | fn store<'b>() -> &'b peripheral::Store<Self> { | ||
| 268 | unsafe { mem::transmute(T::storage()) } | ||
| 269 | } | ||
| 361 | 270 | ||
| 362 | fn on_interrupt(&mut self) { | 271 | fn on_interrupt(&mut self) { |
| 363 | trace!("irq: start"); | 272 | trace!("irq: start"); |
| @@ -505,39 +414,27 @@ mod private { | |||
| 505 | impl Sealed for crate::pac::UARTE1 {} | 414 | impl Sealed for crate::pac::UARTE1 {} |
| 506 | } | 415 | } |
| 507 | 416 | ||
| 508 | pub trait Instance: Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed { | 417 | pub trait Instance: |
| 418 | Deref<Target = uarte0::RegisterBlock> + Sized + private::Sealed + 'static | ||
| 419 | { | ||
| 509 | type Interrupt: OwnedInterrupt; | 420 | type Interrupt: OwnedInterrupt; |
| 510 | 421 | fn storage() -> &'static peripheral::Store<State<'static, Self>>; | |
| 511 | #[doc(hidden)] | ||
| 512 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self>; | ||
| 513 | |||
| 514 | #[doc(hidden)] | ||
| 515 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>); | ||
| 516 | } | 422 | } |
| 517 | 423 | ||
| 518 | static mut UARTE0_STATE: *mut UarteState<crate::pac::UARTE0> = ptr::null_mut(); | 424 | impl Instance for pac::UARTE0 { |
| 519 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | ||
| 520 | static mut UARTE1_STATE: *mut UarteState<crate::pac::UARTE1> = ptr::null_mut(); | ||
| 521 | |||
| 522 | impl Instance for crate::pac::UARTE0 { | ||
| 523 | type Interrupt = interrupt::UARTE0_UART0Interrupt; | 425 | type Interrupt = interrupt::UARTE0_UART0Interrupt; |
| 524 | 426 | fn storage() -> &'static peripheral::Store<State<'static, Self>> { | |
| 525 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { | 427 | static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE0>> = |
| 526 | unsafe { UARTE0_STATE } // Safe because of CriticalSection | 428 | peripheral::Store::uninit(); |
| 527 | } | 429 | &STORAGE |
| 528 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) { | ||
| 529 | unsafe { UARTE0_STATE = state } // Safe because of CriticalSection | ||
| 530 | } | 430 | } |
| 531 | } | 431 | } |
| 532 | 432 | ||
| 533 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | 433 | impl Instance for pac::UARTE1 { |
| 534 | impl Instance for crate::pac::UARTE1 { | ||
| 535 | type Interrupt = interrupt::UARTE1Interrupt; | 434 | type Interrupt = interrupt::UARTE1Interrupt; |
| 536 | 435 | fn storage() -> &'static peripheral::Store<State<'static, Self>> { | |
| 537 | fn get_state(_cs: &CriticalSection) -> *mut UarteState<Self> { | 436 | static STORAGE: peripheral::Store<State<'static, crate::pac::UARTE1>> = |
| 538 | unsafe { UARTE1_STATE } // Safe because of CriticalSection | 437 | peripheral::Store::uninit(); |
| 539 | } | 438 | &STORAGE |
| 540 | fn set_state(_cs: &CriticalSection, state: *mut UarteState<Self>) { | ||
| 541 | unsafe { UARTE1_STATE = state } // Safe because of CriticalSection | ||
| 542 | } | 439 | } |
| 543 | } | 440 | } |
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e97002a20..ac2371766 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -50,6 +50,7 @@ pub use nrf52840_hal as hal; | |||
| 50 | 50 | ||
| 51 | // This mod MUST go first, so that the others see its macros. | 51 | // This mod MUST go first, so that the others see its macros. |
| 52 | pub(crate) mod fmt; | 52 | pub(crate) mod fmt; |
| 53 | pub(crate) mod util; | ||
| 53 | 54 | ||
| 54 | pub mod buffered_uarte; | 55 | pub mod buffered_uarte; |
| 55 | pub mod gpiote; | 56 | pub mod gpiote; |
diff --git a/embassy-nrf/src/util/mod.rs b/embassy-nrf/src/util/mod.rs new file mode 100644 index 000000000..2fd5453d3 --- /dev/null +++ b/embassy-nrf/src/util/mod.rs | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | pub mod peripheral; | ||
| 2 | pub mod ring_buffer; | ||
diff --git a/embassy-nrf/src/util/peripheral.rs b/embassy-nrf/src/util/peripheral.rs new file mode 100644 index 000000000..85de3419e --- /dev/null +++ b/embassy-nrf/src/util/peripheral.rs | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | use core::mem; | ||
| 2 | use core::mem::MaybeUninit; | ||
| 3 | use core::ptr; | ||
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 5 | use core::{cell::UnsafeCell, marker::PhantomData}; | ||
| 6 | |||
| 7 | use crate::interrupt::OwnedInterrupt; | ||
| 8 | |||
| 9 | pub struct Store<T>(MaybeUninit<UnsafeCell<T>>); | ||
| 10 | impl<T> Store<T> { | ||
| 11 | pub const fn uninit() -> Self { | ||
| 12 | Self(MaybeUninit::uninit()) | ||
| 13 | } | ||
| 14 | |||
| 15 | unsafe fn as_mut_ptr(&self) -> *mut T { | ||
| 16 | (*self.0.as_ptr()).get() | ||
| 17 | } | ||
| 18 | |||
| 19 | unsafe fn as_mut(&self) -> &mut T { | ||
| 20 | &mut *self.as_mut_ptr() | ||
| 21 | } | ||
| 22 | |||
| 23 | unsafe fn write(&self, val: T) { | ||
| 24 | ptr::write(self.as_mut_ptr(), val) | ||
| 25 | } | ||
| 26 | |||
| 27 | unsafe fn drop_in_place(&self) { | ||
| 28 | ptr::drop_in_place(self.as_mut_ptr()) | ||
| 29 | } | ||
| 30 | |||
| 31 | unsafe fn read(&self) -> T { | ||
| 32 | ptr::read(self.as_mut_ptr()) | ||
| 33 | } | ||
| 34 | } | ||
| 35 | unsafe impl<T> Send for Store<T> {} | ||
| 36 | unsafe impl<T> Sync for Store<T> {} | ||
| 37 | |||
| 38 | pub trait State: Sized { | ||
| 39 | type Interrupt: OwnedInterrupt; | ||
| 40 | fn on_interrupt(&mut self); | ||
| 41 | #[doc(hidden)] | ||
| 42 | fn store<'a>() -> &'a Store<Self>; | ||
| 43 | } | ||
| 44 | |||
| 45 | pub struct Registration<P: State> { | ||
| 46 | irq: P::Interrupt, | ||
| 47 | not_send: PhantomData<*mut P>, | ||
| 48 | } | ||
| 49 | |||
| 50 | impl<P: State> Registration<P> { | ||
| 51 | pub fn new(irq: P::Interrupt, state: P) -> Self { | ||
| 52 | // safety: | ||
| 53 | // - No other PeripheralRegistration can already exist because we have the owned interrupt | ||
| 54 | // - therefore, storage is uninitialized | ||
| 55 | // - therefore it's safe to overwrite it without dropping the previous contents | ||
| 56 | unsafe { P::store().write(state) } | ||
| 57 | |||
| 58 | irq.set_handler(|| { | ||
| 59 | // safety: | ||
| 60 | // - If a PeripheralRegistration instance exists, P::storage() is initialized. | ||
| 61 | // - It's OK to get a &mut to it since the irq is disabled. | ||
| 62 | unsafe { P::store().as_mut() }.on_interrupt(); | ||
| 63 | }); | ||
| 64 | |||
| 65 | compiler_fence(Ordering::SeqCst); | ||
| 66 | irq.enable(); | ||
| 67 | |||
| 68 | Self { | ||
| 69 | irq, | ||
| 70 | not_send: PhantomData, | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn with<R>(&mut self, f: impl FnOnce(&mut P, &mut P::Interrupt) -> R) -> R { | ||
| 75 | self.irq.disable(); | ||
| 76 | compiler_fence(Ordering::SeqCst); | ||
| 77 | |||
| 78 | // safety: | ||
| 79 | // - If a PeripheralRegistration instance exists, P::storage() is initialized. | ||
| 80 | // - It's OK to get a &mut to it since the irq is disabled. | ||
| 81 | let r = f(unsafe { P::store().as_mut() }, &mut self.irq); | ||
| 82 | |||
| 83 | compiler_fence(Ordering::SeqCst); | ||
| 84 | self.irq.enable(); | ||
| 85 | |||
| 86 | r | ||
| 87 | } | ||
| 88 | |||
| 89 | pub fn free(self) -> (P::Interrupt, P) { | ||
| 90 | let irq = unsafe { ptr::read(&self.irq) }; | ||
| 91 | irq.disable(); | ||
| 92 | irq.set_handler(|| ()); | ||
| 93 | mem::forget(self); | ||
| 94 | let storage = P::store(); | ||
| 95 | (irq, unsafe { storage.read() }) | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | impl<P: State> Drop for Registration<P> { | ||
| 100 | fn drop(&mut self) { | ||
| 101 | self.irq.disable(); | ||
| 102 | self.irq.set_handler(|| ()); | ||
| 103 | |||
| 104 | let storage = P::store(); | ||
| 105 | unsafe { storage.drop_in_place() }; | ||
| 106 | } | ||
| 107 | } | ||
diff --git a/embassy-nrf/src/util/ring_buffer.rs b/embassy-nrf/src/util/ring_buffer.rs new file mode 100644 index 000000000..f395785a5 --- /dev/null +++ b/embassy-nrf/src/util/ring_buffer.rs | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | use crate::fmt::{assert, panic, todo, *}; | ||
| 2 | |||
| 3 | pub struct RingBuffer<'a> { | ||
| 4 | buf: &'a mut [u8], | ||
| 5 | start: usize, | ||
| 6 | end: usize, | ||
| 7 | empty: bool, | ||
| 8 | } | ||
| 9 | |||
| 10 | impl<'a> RingBuffer<'a> { | ||
| 11 | pub fn new(buf: &'a mut [u8]) -> Self { | ||
| 12 | Self { | ||
| 13 | buf, | ||
| 14 | start: 0, | ||
| 15 | end: 0, | ||
| 16 | empty: true, | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn push_buf(&mut self) -> &mut [u8] { | ||
| 21 | if self.start == self.end && !self.empty { | ||
| 22 | trace!(" ringbuf: push_buf empty"); | ||
| 23 | return &mut self.buf[..0]; | ||
| 24 | } | ||
| 25 | |||
| 26 | let n = if self.start <= self.end { | ||
| 27 | self.buf.len() - self.end | ||
| 28 | } else { | ||
| 29 | self.start - self.end | ||
| 30 | }; | ||
| 31 | |||
| 32 | trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); | ||
| 33 | &mut self.buf[self.end..self.end + n] | ||
| 34 | } | ||
| 35 | |||
| 36 | pub fn push(&mut self, n: usize) { | ||
| 37 | trace!(" ringbuf: push {:?}", n); | ||
| 38 | if n == 0 { | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | |||
| 42 | self.end = self.wrap(self.end + n); | ||
| 43 | self.empty = false; | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn pop_buf(&mut self) -> &mut [u8] { | ||
| 47 | if self.empty { | ||
| 48 | trace!(" ringbuf: pop_buf empty"); | ||
| 49 | return &mut self.buf[..0]; | ||
| 50 | } | ||
| 51 | |||
| 52 | let n = if self.end <= self.start { | ||
| 53 | self.buf.len() - self.start | ||
| 54 | } else { | ||
| 55 | self.end - self.start | ||
| 56 | }; | ||
| 57 | |||
| 58 | trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); | ||
| 59 | &mut self.buf[self.start..self.start + n] | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn pop(&mut self, n: usize) { | ||
| 63 | trace!(" ringbuf: pop {:?}", n); | ||
| 64 | if n == 0 { | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | self.start = self.wrap(self.start + n); | ||
| 69 | self.empty = self.start == self.end; | ||
| 70 | } | ||
| 71 | |||
| 72 | fn wrap(&self, n: usize) -> usize { | ||
| 73 | assert!(n <= self.buf.len()); | ||
| 74 | if n == self.buf.len() { | ||
| 75 | 0 | ||
| 76 | } else { | ||
| 77 | n | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
