diff options
| author | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
|---|---|---|
| committer | Quentin Smith <[email protected]> | 2023-07-17 21:31:43 -0400 |
| commit | 6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch) | |
| tree | 748f510e190bb2724750507a6e69ed1a8e08cb20 /embassy-nrf/src | |
| parent | d896f80405aa8963877049ed999e4aba25d6e2bb (diff) | |
| parent | 6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff) | |
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'embassy-nrf/src')
36 files changed, 6329 insertions, 2645 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 62af544ae..9bc1c1e7a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -1,9 +1,4 @@ | |||
| 1 | //! Async buffered UART | 1 | //! Async buffered UART driver. |
| 2 | //! | ||
| 3 | //! WARNING!!! The functionality provided here is intended to be used only | ||
| 4 | //! in situations where hardware flow control are available i.e. CTS and RTS. | ||
| 5 | //! This is a problem that should be addressed at a later stage and can be | ||
| 6 | //! fully explained at <https://github.com/embassy-rs/embassy/issues/536>. | ||
| 7 | //! | 2 | //! |
| 8 | //! Note that discarding a future from a read or write operation may lead to losing | 3 | //! Note that discarding a future from a read or write operation may lead to losing |
| 9 | //! data. For example, when using `futures_util::future::select` and completion occurs | 4 | //! data. For example, when using `futures_util::future::select` and completion occurs |
| @@ -14,82 +9,234 @@ | |||
| 14 | //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. | 9 | //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. |
| 15 | 10 | ||
| 16 | use core::cmp::min; | 11 | use core::cmp::min; |
| 17 | use core::future::Future; | 12 | use core::future::poll_fn; |
| 18 | use core::sync::atomic::{compiler_fence, Ordering}; | 13 | use core::marker::PhantomData; |
| 14 | use core::slice; | ||
| 15 | use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; | ||
| 19 | use core::task::Poll; | 16 | use core::task::Poll; |
| 20 | 17 | ||
| 21 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 18 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 22 | use embassy_hal_common::ring_buffer::RingBuffer; | ||
| 23 | use embassy_hal_common::{into_ref, PeripheralRef}; | 19 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 24 | use embassy_sync::waitqueue::WakerRegistration; | 20 | use embassy_sync::waitqueue::AtomicWaker; |
| 25 | use futures::future::poll_fn; | ||
| 26 | // Re-export SVD variants to allow user to directly set values | 21 | // Re-export SVD variants to allow user to directly set values |
| 27 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 22 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 28 | 23 | ||
| 29 | use crate::gpio::Pin as GpioPin; | 24 | use crate::gpio::sealed::Pin; |
| 30 | use crate::interrupt::InterruptExt; | 25 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 26 | use crate::interrupt::typelevel::Interrupt; |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 27 | use crate::ppi::{ |
| 28 | self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, | ||
| 29 | }; | ||
| 30 | use crate::timer::{Instance as TimerInstance, Timer}; | ||
| 33 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; | 31 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; |
| 34 | use crate::{pac, Peripheral}; | 32 | use crate::{interrupt, pac, Peripheral}; |
| 33 | |||
| 34 | mod sealed { | ||
| 35 | use super::*; | ||
| 36 | |||
| 37 | pub struct State { | ||
| 38 | pub tx_waker: AtomicWaker, | ||
| 39 | pub tx_buf: RingBuffer, | ||
| 40 | pub tx_count: AtomicUsize, | ||
| 35 | 41 | ||
| 36 | #[derive(Copy, Clone, Debug, PartialEq)] | 42 | pub rx_waker: AtomicWaker, |
| 37 | enum RxState { | 43 | pub rx_buf: RingBuffer, |
| 38 | Idle, | 44 | pub rx_bufs: AtomicU8, |
| 39 | Receiving, | 45 | pub rx_ppi_ch: AtomicU8, |
| 46 | } | ||
| 40 | } | 47 | } |
| 41 | 48 | ||
| 42 | #[derive(Copy, Clone, Debug, PartialEq)] | 49 | /// UART error. |
| 43 | enum TxState { | 50 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 44 | Idle, | 51 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 45 | Transmitting(usize), | 52 | #[non_exhaustive] |
| 53 | pub enum Error { | ||
| 54 | // No errors for now | ||
| 46 | } | 55 | } |
| 47 | 56 | ||
| 48 | /// A type for storing the state of the UARTE peripheral that can be stored in a static. | 57 | pub(crate) use sealed::State; |
| 49 | pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>); | 58 | |
| 50 | impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { | 59 | impl State { |
| 51 | /// Create an instance for storing UARTE peripheral state. | 60 | pub(crate) const fn new() -> Self { |
| 52 | pub fn new() -> Self { | 61 | Self { |
| 53 | Self(StateStorage::new()) | 62 | tx_waker: AtomicWaker::new(), |
| 63 | tx_buf: RingBuffer::new(), | ||
| 64 | tx_count: AtomicUsize::new(0), | ||
| 65 | |||
| 66 | rx_waker: AtomicWaker::new(), | ||
| 67 | rx_buf: RingBuffer::new(), | ||
| 68 | rx_bufs: AtomicU8::new(0), | ||
| 69 | rx_ppi_ch: AtomicU8::new(0), | ||
| 70 | } | ||
| 54 | } | 71 | } |
| 55 | } | 72 | } |
| 56 | 73 | ||
| 57 | struct StateInner<'d, U: UarteInstance, T: TimerInstance> { | 74 | /// Interrupt handler. |
| 58 | _peri: PeripheralRef<'d, U>, | 75 | pub struct InterruptHandler<U: UarteInstance> { |
| 59 | timer: Timer<'d, T>, | 76 | _phantom: PhantomData<U>, |
| 60 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, | 77 | } |
| 61 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, | 78 | |
| 79 | impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for InterruptHandler<U> { | ||
| 80 | unsafe fn on_interrupt() { | ||
| 81 | //trace!("irq: start"); | ||
| 82 | let r = U::regs(); | ||
| 83 | let s = U::buffered_state(); | ||
| 84 | |||
| 85 | let buf_len = s.rx_buf.len(); | ||
| 86 | let half_len = buf_len / 2; | ||
| 87 | let mut tx = unsafe { s.tx_buf.reader() }; | ||
| 88 | let mut rx = unsafe { s.rx_buf.writer() }; | ||
| 89 | |||
| 90 | if r.events_error.read().bits() != 0 { | ||
| 91 | r.events_error.reset(); | ||
| 92 | let errs = r.errorsrc.read(); | ||
| 93 | r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); | ||
| 94 | |||
| 95 | if errs.overrun().bit() { | ||
| 96 | panic!("BufferedUarte overrun"); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | // Received some bytes, wake task. | ||
| 101 | if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { | ||
| 102 | r.intenclr.write(|w| w.rxdrdy().clear()); | ||
| 103 | r.events_rxdrdy.reset(); | ||
| 104 | s.rx_waker.wake(); | ||
| 105 | } | ||
| 106 | |||
| 107 | // If not RXing, start. | ||
| 108 | if s.rx_bufs.load(Ordering::Relaxed) == 0 { | ||
| 109 | let (ptr, len) = rx.push_buf(); | ||
| 110 | if len >= half_len { | ||
| 111 | //trace!(" irq_rx: starting {:?}", half_len); | ||
| 112 | s.rx_bufs.store(1, Ordering::Relaxed); | ||
| 113 | |||
| 114 | // Set up the DMA read | ||
| 115 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 116 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); | ||
| 117 | |||
| 118 | // Start UARTE Receive transaction | ||
| 119 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 120 | rx.push_done(half_len); | ||
| 121 | r.intenset.write(|w| w.rxstarted().set()); | ||
| 122 | } | ||
| 123 | } | ||
| 62 | 124 | ||
| 63 | rx: RingBuffer<'d>, | 125 | if r.events_rxstarted.read().bits() != 0 { |
| 64 | rx_state: RxState, | 126 | //trace!(" irq_rx: rxstarted"); |
| 65 | rx_waker: WakerRegistration, | 127 | let (ptr, len) = rx.push_buf(); |
| 128 | if len >= half_len { | ||
| 129 | //trace!(" irq_rx: starting second {:?}", half_len); | ||
| 66 | 130 | ||
| 67 | tx: RingBuffer<'d>, | 131 | // Set up the DMA read |
| 68 | tx_state: TxState, | 132 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); |
| 69 | tx_waker: WakerRegistration, | 133 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); |
| 134 | |||
| 135 | let chn = s.rx_ppi_ch.load(Ordering::Relaxed); | ||
| 136 | |||
| 137 | ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); | ||
| 138 | |||
| 139 | rx.push_done(half_len); | ||
| 140 | |||
| 141 | r.events_rxstarted.reset(); | ||
| 142 | } else { | ||
| 143 | //trace!(" irq_rx: rxstarted no buf"); | ||
| 144 | r.intenclr.write(|w| w.rxstarted().clear()); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | // ============================= | ||
| 149 | |||
| 150 | // TX end | ||
| 151 | if r.events_endtx.read().bits() != 0 { | ||
| 152 | r.events_endtx.reset(); | ||
| 153 | |||
| 154 | let n = s.tx_count.load(Ordering::Relaxed); | ||
| 155 | //trace!(" irq_tx: endtx {:?}", n); | ||
| 156 | tx.pop_done(n); | ||
| 157 | s.tx_waker.wake(); | ||
| 158 | s.tx_count.store(0, Ordering::Relaxed); | ||
| 159 | } | ||
| 160 | |||
| 161 | // If not TXing, start. | ||
| 162 | if s.tx_count.load(Ordering::Relaxed) == 0 { | ||
| 163 | let (ptr, len) = tx.pop_buf(); | ||
| 164 | if len != 0 { | ||
| 165 | //trace!(" irq_tx: starting {:?}", len); | ||
| 166 | s.tx_count.store(len, Ordering::Relaxed); | ||
| 167 | |||
| 168 | // Set up the DMA write | ||
| 169 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 170 | r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 171 | |||
| 172 | // Start UARTE Transmit transaction | ||
| 173 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | //trace!("irq: end"); | ||
| 178 | } | ||
| 70 | } | 179 | } |
| 71 | 180 | ||
| 72 | /// Interface to a UARTE instance | 181 | /// Buffered UARTE driver. |
| 73 | pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { | 182 | pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { |
| 74 | inner: PeripheralMutex<'d, StateInner<'d, U, T>>, | 183 | _peri: PeripheralRef<'d, U>, |
| 184 | timer: Timer<'d, T>, | ||
| 185 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, | ||
| 186 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, | ||
| 187 | _ppi_group: PpiGroup<'d, AnyGroup>, | ||
| 75 | } | 188 | } |
| 76 | 189 | ||
| 77 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} | 190 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} |
| 78 | 191 | ||
| 79 | impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | 192 | impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { |
| 80 | /// Create a new instance of a BufferedUarte. | 193 | /// Create a new BufferedUarte without hardware flow control. |
| 81 | /// | 194 | /// |
| 82 | /// See the [module documentation](crate::buffered_uarte) for more details about the intended use. | 195 | /// # Panics |
| 83 | /// | 196 | /// |
| 84 | /// The BufferedUarte uses the provided state to store the buffers and peripheral state. The timer and ppi channels are used to 'emulate' idle line detection so that read operations | 197 | /// Panics if `rx_buffer.len()` is odd. |
| 85 | /// can return early if there is no data to receive. | ||
| 86 | pub fn new( | 198 | pub fn new( |
| 87 | state: &'d mut State<'d, U, T>, | 199 | uarte: impl Peripheral<P = U> + 'd, |
| 88 | peri: impl Peripheral<P = U> + 'd, | ||
| 89 | timer: impl Peripheral<P = T> + 'd, | 200 | timer: impl Peripheral<P = T> + 'd, |
| 90 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 201 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 91 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 202 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 92 | irq: impl Peripheral<P = U::Interrupt> + 'd, | 203 | ppi_group: impl Peripheral<P = impl Group> + 'd, |
| 204 | _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | ||
| 205 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 206 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 207 | config: Config, | ||
| 208 | rx_buffer: &'d mut [u8], | ||
| 209 | tx_buffer: &'d mut [u8], | ||
| 210 | ) -> Self { | ||
| 211 | into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); | ||
| 212 | Self::new_inner( | ||
| 213 | uarte, | ||
| 214 | timer, | ||
| 215 | ppi_ch1.map_into(), | ||
| 216 | ppi_ch2.map_into(), | ||
| 217 | ppi_group.map_into(), | ||
| 218 | rxd.map_into(), | ||
| 219 | txd.map_into(), | ||
| 220 | None, | ||
| 221 | None, | ||
| 222 | config, | ||
| 223 | rx_buffer, | ||
| 224 | tx_buffer, | ||
| 225 | ) | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Create a new BufferedUarte with hardware flow control (RTS/CTS) | ||
| 229 | /// | ||
| 230 | /// # Panics | ||
| 231 | /// | ||
| 232 | /// Panics if `rx_buffer.len()` is odd. | ||
| 233 | pub fn new_with_rtscts( | ||
| 234 | uarte: impl Peripheral<P = U> + 'd, | ||
| 235 | timer: impl Peripheral<P = T> + 'd, | ||
| 236 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||
| 237 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||
| 238 | ppi_group: impl Peripheral<P = impl Group> + 'd, | ||
| 239 | _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd, | ||
| 93 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 240 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 94 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 241 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 95 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 242 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -98,11 +245,42 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 98 | rx_buffer: &'d mut [u8], | 245 | rx_buffer: &'d mut [u8], |
| 99 | tx_buffer: &'d mut [u8], | 246 | tx_buffer: &'d mut [u8], |
| 100 | ) -> Self { | 247 | ) -> Self { |
| 101 | into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); | 248 | into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); |
| 249 | Self::new_inner( | ||
| 250 | uarte, | ||
| 251 | timer, | ||
| 252 | ppi_ch1.map_into(), | ||
| 253 | ppi_ch2.map_into(), | ||
| 254 | ppi_group.map_into(), | ||
| 255 | rxd.map_into(), | ||
| 256 | txd.map_into(), | ||
| 257 | Some(cts.map_into()), | ||
| 258 | Some(rts.map_into()), | ||
| 259 | config, | ||
| 260 | rx_buffer, | ||
| 261 | tx_buffer, | ||
| 262 | ) | ||
| 263 | } | ||
| 102 | 264 | ||
| 103 | let r = U::regs(); | 265 | fn new_inner( |
| 266 | peri: impl Peripheral<P = U> + 'd, | ||
| 267 | timer: impl Peripheral<P = T> + 'd, | ||
| 268 | ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, | ||
| 269 | ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, | ||
| 270 | ppi_group: PeripheralRef<'d, AnyGroup>, | ||
| 271 | rxd: PeripheralRef<'d, AnyPin>, | ||
| 272 | txd: PeripheralRef<'d, AnyPin>, | ||
| 273 | cts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 274 | rts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 275 | config: Config, | ||
| 276 | rx_buffer: &'d mut [u8], | ||
| 277 | tx_buffer: &'d mut [u8], | ||
| 278 | ) -> Self { | ||
| 279 | into_ref!(peri, timer); | ||
| 280 | |||
| 281 | assert!(rx_buffer.len() % 2 == 0); | ||
| 104 | 282 | ||
| 105 | let mut timer = Timer::new(timer); | 283 | let r = U::regs(); |
| 106 | 284 | ||
| 107 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); | 285 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); |
| 108 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | 286 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); |
| @@ -111,361 +289,388 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 111 | txd.conf().write(|w| w.dir().output().drive().h0h1()); | 289 | txd.conf().write(|w| w.dir().output().drive().h0h1()); |
| 112 | r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | 290 | r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); |
| 113 | 291 | ||
| 114 | cts.conf().write(|w| w.input().connect().drive().h0h1()); | 292 | if let Some(pin) = &cts { |
| 293 | pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 294 | } | ||
| 115 | r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | 295 | r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); |
| 116 | 296 | ||
| 117 | rts.set_high(); | 297 | if let Some(pin) = &rts { |
| 118 | rts.conf().write(|w| w.dir().output().drive().h0h1()); | 298 | pin.set_high(); |
| 299 | pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||
| 300 | } | ||
| 119 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | 301 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); |
| 120 | 302 | ||
| 121 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | 303 | // Initialize state |
| 122 | r.config.write(|w| w.parity().variant(config.parity)); | 304 | let s = U::buffered_state(); |
| 305 | s.tx_count.store(0, Ordering::Relaxed); | ||
| 306 | s.rx_bufs.store(0, Ordering::Relaxed); | ||
| 307 | let len = tx_buffer.len(); | ||
| 308 | unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; | ||
| 309 | let len = rx_buffer.len(); | ||
| 310 | unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | ||
| 123 | 311 | ||
| 124 | // Configure | 312 | // Configure |
| 125 | r.config.write(|w| { | 313 | r.config.write(|w| { |
| 126 | w.hwfc().bit(true); | 314 | w.hwfc().bit(false); |
| 127 | w.parity().variant(config.parity); | 315 | w.parity().variant(config.parity); |
| 128 | w | 316 | w |
| 129 | }); | 317 | }); |
| 130 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | 318 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); |
| 131 | 319 | ||
| 132 | // Enable interrupts | 320 | // clear errors |
| 133 | r.intenset.write(|w| w.endrx().set().endtx().set()); | 321 | let errors = r.errorsrc.read().bits(); |
| 322 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 323 | |||
| 324 | r.events_rxstarted.reset(); | ||
| 325 | r.events_txstarted.reset(); | ||
| 326 | r.events_error.reset(); | ||
| 327 | r.events_endrx.reset(); | ||
| 328 | r.events_endtx.reset(); | ||
| 134 | 329 | ||
| 135 | // Disable the irq, let the Registration enable it when everything is set up. | 330 | // Enable interrupts |
| 136 | irq.disable(); | 331 | r.intenclr.write(|w| unsafe { w.bits(!0) }); |
| 137 | irq.pend(); | 332 | r.intenset.write(|w| { |
| 333 | w.endtx().set(); | ||
| 334 | w.rxstarted().set(); | ||
| 335 | w.error().set(); | ||
| 336 | w | ||
| 337 | }); | ||
| 138 | 338 | ||
| 139 | // Enable UARTE instance | 339 | // Enable UARTE instance |
| 140 | apply_workaround_for_enable_anomaly(&r); | 340 | apply_workaround_for_enable_anomaly(&r); |
| 141 | r.enable.write(|w| w.enable().enabled()); | 341 | r.enable.write(|w| w.enable().enabled()); |
| 142 | 342 | ||
| 143 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | 343 | // Configure byte counter. |
| 144 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | 344 | let timer = Timer::new_counter(timer); |
| 145 | // | 345 | timer.cc(1).write(rx_buffer.len() as u32 * 2); |
| 146 | // We want to stop RX if line is idle for 2 bytes worth of time | 346 | timer.cc(1).short_compare_clear(); |
| 147 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | 347 | timer.clear(); |
| 148 | // This gives us the amount of 16M ticks for 20 bits. | 348 | timer.start(); |
| 149 | let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); | ||
| 150 | 349 | ||
| 151 | timer.set_frequency(Frequency::F16MHz); | 350 | let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); |
| 152 | timer.cc(0).write(timeout); | ||
| 153 | timer.cc(0).short_compare_clear(); | ||
| 154 | timer.cc(0).short_compare_stop(); | ||
| 155 | |||
| 156 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 157 | ppi_ch1.map_into(), | ||
| 158 | Event::from_reg(&r.events_rxdrdy), | ||
| 159 | timer.task_clear(), | ||
| 160 | timer.task_start(), | ||
| 161 | ); | ||
| 162 | ppi_ch1.enable(); | 351 | ppi_ch1.enable(); |
| 163 | 352 | ||
| 164 | let mut ppi_ch2 = Ppi::new_one_to_one( | 353 | s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); |
| 165 | ppi_ch2.map_into(), | 354 | let mut ppi_group = PpiGroup::new(ppi_group); |
| 166 | timer.cc(0).event_compare(), | 355 | let mut ppi_ch2 = Ppi::new_one_to_two( |
| 167 | Task::from_reg(&r.tasks_stoprx), | 356 | ppi_ch2, |
| 357 | Event::from_reg(&r.events_endrx), | ||
| 358 | Task::from_reg(&r.tasks_startrx), | ||
| 359 | ppi_group.task_disable_all(), | ||
| 168 | ); | 360 | ); |
| 169 | ppi_ch2.enable(); | 361 | ppi_ch2.disable(); |
| 362 | ppi_group.add_channel(&ppi_ch2); | ||
| 363 | |||
| 364 | U::Interrupt::pend(); | ||
| 365 | unsafe { U::Interrupt::enable() }; | ||
| 170 | 366 | ||
| 171 | Self { | 367 | Self { |
| 172 | inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { | 368 | _peri: peri, |
| 173 | _peri: peri, | 369 | timer, |
| 174 | timer, | 370 | _ppi_ch1: ppi_ch1, |
| 175 | _ppi_ch1: ppi_ch1, | 371 | _ppi_ch2: ppi_ch2, |
| 176 | _ppi_ch2: ppi_ch2, | 372 | _ppi_group: ppi_group, |
| 177 | |||
| 178 | rx: RingBuffer::new(rx_buffer), | ||
| 179 | rx_state: RxState::Idle, | ||
| 180 | rx_waker: WakerRegistration::new(), | ||
| 181 | |||
| 182 | tx: RingBuffer::new(tx_buffer), | ||
| 183 | tx_state: TxState::Idle, | ||
| 184 | tx_waker: WakerRegistration::new(), | ||
| 185 | }), | ||
| 186 | } | 373 | } |
| 187 | } | 374 | } |
| 188 | 375 | ||
| 376 | fn pend_irq() { | ||
| 377 | U::Interrupt::pend() | ||
| 378 | } | ||
| 379 | |||
| 189 | /// Adjust the baud rate to the provided value. | 380 | /// Adjust the baud rate to the provided value. |
| 190 | pub fn set_baudrate(&mut self, baudrate: Baudrate) { | 381 | pub fn set_baudrate(&mut self, baudrate: Baudrate) { |
| 191 | self.inner.with(|state| { | 382 | let r = U::regs(); |
| 192 | let r = U::regs(); | 383 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); |
| 384 | } | ||
| 193 | 385 | ||
| 194 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | 386 | /// Split the UART in reader and writer parts. |
| 195 | state.timer.cc(0).write(timeout); | 387 | /// |
| 196 | state.timer.clear(); | 388 | /// This allows reading and writing concurrently from independent tasks. |
| 389 | pub fn split<'u>(&'u mut self) -> (BufferedUarteRx<'u, 'd, U, T>, BufferedUarteTx<'u, 'd, U, T>) { | ||
| 390 | (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) | ||
| 391 | } | ||
| 197 | 392 | ||
| 198 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); | 393 | async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, Error> { |
| 199 | }); | 394 | let data = self.inner_fill_buf().await?; |
| 395 | let n = data.len().min(buf.len()); | ||
| 396 | buf[..n].copy_from_slice(&data[..n]); | ||
| 397 | self.inner_consume(n); | ||
| 398 | Ok(n) | ||
| 200 | } | 399 | } |
| 201 | } | ||
| 202 | 400 | ||
| 203 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> { | 401 | async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> { |
| 204 | type Error = core::convert::Infallible; | 402 | poll_fn(move |cx| { |
| 205 | } | 403 | //trace!("poll_write: {:?}", buf.len()); |
| 404 | let s = U::buffered_state(); | ||
| 405 | let mut tx = unsafe { s.tx_buf.writer() }; | ||
| 406 | |||
| 407 | let tx_buf = tx.push_slice(); | ||
| 408 | if tx_buf.is_empty() { | ||
| 409 | //trace!("poll_write: pending"); | ||
| 410 | s.tx_waker.register(cx.waker()); | ||
| 411 | return Poll::Pending; | ||
| 412 | } | ||
| 413 | |||
| 414 | let n = min(tx_buf.len(), buf.len()); | ||
| 415 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 416 | tx.push_done(n); | ||
| 417 | |||
| 418 | //trace!("poll_write: queued {:?}", n); | ||
| 206 | 419 | ||
| 207 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { | 420 | compiler_fence(Ordering::SeqCst); |
| 208 | type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 421 | Self::pend_irq(); |
| 209 | where | ||
| 210 | Self: 'a; | ||
| 211 | 422 | ||
| 212 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | 423 | Poll::Ready(Ok(n)) |
| 424 | }) | ||
| 425 | .await | ||
| 426 | } | ||
| 427 | |||
| 428 | async fn inner_flush<'a>(&'a self) -> Result<(), Error> { | ||
| 213 | poll_fn(move |cx| { | 429 | poll_fn(move |cx| { |
| 214 | let mut do_pend = false; | 430 | //trace!("poll_flush"); |
| 215 | let res = self.inner.with(|state| { | 431 | let s = U::buffered_state(); |
| 216 | compiler_fence(Ordering::SeqCst); | 432 | if !s.tx_buf.is_empty() { |
| 217 | trace!("poll_read"); | 433 | //trace!("poll_flush: pending"); |
| 218 | 434 | s.tx_waker.register(cx.waker()); | |
| 219 | // We have data ready in buffer? Return it. | 435 | return Poll::Pending; |
| 220 | let data = state.rx.pop_buf(); | ||
| 221 | if !data.is_empty() { | ||
| 222 | trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len()); | ||
| 223 | let len = data.len().min(buf.len()); | ||
| 224 | buf[..len].copy_from_slice(&data[..len]); | ||
| 225 | state.rx.pop(len); | ||
| 226 | do_pend = true; | ||
| 227 | return Poll::Ready(Ok(len)); | ||
| 228 | } | ||
| 229 | |||
| 230 | trace!(" empty"); | ||
| 231 | state.rx_waker.register(cx.waker()); | ||
| 232 | Poll::Pending | ||
| 233 | }); | ||
| 234 | if do_pend { | ||
| 235 | self.inner.pend(); | ||
| 236 | } | 436 | } |
| 237 | 437 | ||
| 238 | res | 438 | Poll::Ready(Ok(())) |
| 239 | }) | 439 | }) |
| 440 | .await | ||
| 240 | } | 441 | } |
| 241 | } | ||
| 242 | |||
| 243 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { | ||
| 244 | type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>> | ||
| 245 | where | ||
| 246 | Self: 'a; | ||
| 247 | 442 | ||
| 248 | fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { | 443 | async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> { |
| 249 | poll_fn(move |cx| { | 444 | poll_fn(move |cx| { |
| 250 | self.inner.with(|state| { | 445 | compiler_fence(Ordering::SeqCst); |
| 251 | compiler_fence(Ordering::SeqCst); | 446 | //trace!("poll_read"); |
| 252 | trace!("fill_buf"); | 447 | |
| 253 | 448 | let r = U::regs(); | |
| 254 | // We have data ready in buffer? Return it. | 449 | let s = U::buffered_state(); |
| 255 | let buf = state.rx.pop_buf(); | 450 | |
| 256 | if !buf.is_empty() { | 451 | // Read the RXDRDY counter. |
| 257 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | 452 | T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); |
| 258 | let buf: &[u8] = buf; | 453 | let mut end = T::regs().cc[0].read().bits() as usize; |
| 259 | // Safety: buffer lives as long as uart | 454 | //trace!(" rxdrdy count = {:?}", end); |
| 260 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | 455 | |
| 261 | return Poll::Ready(Ok(buf)); | 456 | // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. |
| 262 | } | 457 | // However, it's unclear if that's instant, or there's a small window where you can |
| 263 | 458 | // still read `len()*2`. | |
| 264 | trace!(" empty"); | 459 | // This could happen if in one clock cycle the counter is updated, and in the next the |
| 265 | state.rx_waker.register(cx.waker()); | 460 | // clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER |
| 266 | Poll::<Result<&[u8], Self::Error>>::Pending | 461 | // is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one |
| 267 | }) | 462 | // clock cycle of the PCLK16M." :shrug: |
| 463 | // So, we wrap the counter ourselves, just in case. | ||
| 464 | if end > s.rx_buf.len() * 2 { | ||
| 465 | end = 0 | ||
| 466 | } | ||
| 467 | |||
| 468 | // This logic mirrors `atomic_ring_buffer::Reader::pop_buf()` | ||
| 469 | let mut start = s.rx_buf.start.load(Ordering::Relaxed); | ||
| 470 | let len = s.rx_buf.len(); | ||
| 471 | if start == end { | ||
| 472 | //trace!(" empty"); | ||
| 473 | s.rx_waker.register(cx.waker()); | ||
| 474 | r.intenset.write(|w| w.rxdrdy().set_bit()); | ||
| 475 | return Poll::Pending; | ||
| 476 | } | ||
| 477 | |||
| 478 | if start >= len { | ||
| 479 | start -= len | ||
| 480 | } | ||
| 481 | if end >= len { | ||
| 482 | end -= len | ||
| 483 | } | ||
| 484 | |||
| 485 | let n = if end > start { end - start } else { len - start }; | ||
| 486 | assert!(n != 0); | ||
| 487 | //trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n); | ||
| 488 | |||
| 489 | let buf = s.rx_buf.buf.load(Ordering::Relaxed); | ||
| 490 | Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) })) | ||
| 268 | }) | 491 | }) |
| 492 | .await | ||
| 269 | } | 493 | } |
| 270 | 494 | ||
| 271 | fn consume(&mut self, amt: usize) { | 495 | fn inner_consume(&self, amt: usize) { |
| 272 | let signal = self.inner.with(|state| { | 496 | if amt == 0 { |
| 273 | let full = state.rx.is_full(); | 497 | return; |
| 274 | state.rx.pop(amt); | ||
| 275 | full | ||
| 276 | }); | ||
| 277 | if signal { | ||
| 278 | self.inner.pend(); | ||
| 279 | } | 498 | } |
| 280 | } | ||
| 281 | } | ||
| 282 | 499 | ||
| 283 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { | 500 | let s = U::buffered_state(); |
| 284 | type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>> | 501 | let mut rx = unsafe { s.rx_buf.reader() }; |
| 285 | where | 502 | rx.pop_done(amt); |
| 286 | Self: 'a; | 503 | U::regs().intenset.write(|w| w.rxstarted().set()); |
| 504 | } | ||
| 287 | 505 | ||
| 288 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | 506 | /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. |
| 289 | poll_fn(move |cx| { | 507 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { |
| 290 | let res = self.inner.with(|state| { | 508 | self.inner_read(buf).await |
| 291 | trace!("poll_write: {:?}", buf.len()); | 509 | } |
| 292 | 510 | ||
| 293 | let tx_buf = state.tx.push_buf(); | 511 | /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. |
| 294 | if tx_buf.is_empty() { | 512 | pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { |
| 295 | trace!("poll_write: pending"); | 513 | self.inner_fill_buf().await |
| 296 | state.tx_waker.register(cx.waker()); | 514 | } |
| 297 | return Poll::Pending; | ||
| 298 | } | ||
| 299 | 515 | ||
| 300 | let n = min(tx_buf.len(), buf.len()); | 516 | /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. |
| 301 | tx_buf[..n].copy_from_slice(&buf[..n]); | 517 | pub fn consume(&mut self, amt: usize) { |
| 302 | state.tx.push(n); | 518 | self.inner_consume(amt) |
| 519 | } | ||
| 303 | 520 | ||
| 304 | trace!("poll_write: queued {:?}", n); | 521 | /// Write a buffer into this writer, returning how many bytes were written. |
| 522 | pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { | ||
| 523 | self.inner_write(buf).await | ||
| 524 | } | ||
| 305 | 525 | ||
| 306 | compiler_fence(Ordering::SeqCst); | 526 | /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. |
| 527 | pub async fn flush(&mut self) -> Result<(), Error> { | ||
| 528 | self.inner_flush().await | ||
| 529 | } | ||
| 530 | } | ||
| 307 | 531 | ||
| 308 | Poll::Ready(Ok(n)) | 532 | /// Reader part of the buffered UARTE driver. |
| 309 | }); | 533 | pub struct BufferedUarteTx<'u, 'd, U: UarteInstance, T: TimerInstance> { |
| 534 | inner: &'u BufferedUarte<'d, U, T>, | ||
| 535 | } | ||
| 310 | 536 | ||
| 311 | self.inner.pend(); | 537 | impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteTx<'u, 'd, U, T> { |
| 538 | /// Write a buffer into this writer, returning how many bytes were written. | ||
| 539 | pub async fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { | ||
| 540 | self.inner.inner_write(buf).await | ||
| 541 | } | ||
| 312 | 542 | ||
| 313 | res | 543 | /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. |
| 314 | }) | 544 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 545 | self.inner.inner_flush().await | ||
| 315 | } | 546 | } |
| 547 | } | ||
| 316 | 548 | ||
| 317 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> | 549 | /// Writer part of the buffered UARTE driver. |
| 318 | where | 550 | pub struct BufferedUarteRx<'u, 'd, U: UarteInstance, T: TimerInstance> { |
| 319 | Self: 'a; | 551 | inner: &'u BufferedUarte<'d, U, T>, |
| 552 | } | ||
| 320 | 553 | ||
| 321 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | 554 | impl<'u, 'd, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'u, 'd, U, T> { |
| 322 | poll_fn(move |cx| { | 555 | /// Pull some bytes from this source into the specified buffer, returning how many bytes were read. |
| 323 | self.inner.with(|state| { | 556 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { |
| 324 | trace!("poll_flush"); | 557 | self.inner.inner_read(buf).await |
| 558 | } | ||
| 325 | 559 | ||
| 326 | if !state.tx.is_empty() { | 560 | /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. |
| 327 | trace!("poll_flush: pending"); | 561 | pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { |
| 328 | state.tx_waker.register(cx.waker()); | 562 | self.inner.inner_fill_buf().await |
| 329 | return Poll::Pending; | 563 | } |
| 330 | } | ||
| 331 | 564 | ||
| 332 | Poll::Ready(Ok(())) | 565 | /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. |
| 333 | }) | 566 | pub fn consume(&mut self, amt: usize) { |
| 334 | }) | 567 | self.inner.inner_consume(amt) |
| 335 | } | 568 | } |
| 336 | } | 569 | } |
| 337 | 570 | ||
| 338 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { | 571 | #[cfg(feature = "nightly")] |
| 339 | fn drop(&mut self) { | 572 | mod _embedded_io { |
| 340 | let r = U::regs(); | 573 | use super::*; |
| 341 | 574 | ||
| 342 | // TODO this probably deadlocks. do like Uarte instead. | 575 | impl embedded_io::Error for Error { |
| 576 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 577 | match *self {} | ||
| 578 | } | ||
| 579 | } | ||
| 343 | 580 | ||
| 344 | self.timer.stop(); | 581 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarte<'d, U, T> { |
| 345 | if let RxState::Receiving = self.rx_state { | 582 | type Error = Error; |
| 346 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | 583 | } |
| 584 | |||
| 585 | impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteRx<'u, 'd, U, T> { | ||
| 586 | type Error = Error; | ||
| 587 | } | ||
| 588 | |||
| 589 | impl<'u, 'd, U: UarteInstance, T: TimerInstance> embedded_io::Io for BufferedUarteTx<'u, 'd, U, T> { | ||
| 590 | type Error = Error; | ||
| 591 | } | ||
| 592 | |||
| 593 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarte<'d, U, T> { | ||
| 594 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | ||
| 595 | self.inner_read(buf).await | ||
| 347 | } | 596 | } |
| 348 | if let TxState::Transmitting(_) = self.tx_state { | 597 | } |
| 349 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | 598 | |
| 599 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Read for BufferedUarteRx<'u, 'd, U, T> { | ||
| 600 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | ||
| 601 | self.inner.inner_read(buf).await | ||
| 350 | } | 602 | } |
| 351 | if let RxState::Receiving = self.rx_state { | 603 | } |
| 352 | low_power_wait_until(|| r.events_endrx.read().bits() == 1); | 604 | |
| 605 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarte<'d, U, T> { | ||
| 606 | async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { | ||
| 607 | self.inner_fill_buf().await | ||
| 353 | } | 608 | } |
| 354 | if let TxState::Transmitting(_) = self.tx_state { | 609 | |
| 355 | low_power_wait_until(|| r.events_endtx.read().bits() == 1); | 610 | fn consume(&mut self, amt: usize) { |
| 611 | self.inner_consume(amt) | ||
| 356 | } | 612 | } |
| 357 | } | 613 | } |
| 358 | } | ||
| 359 | 614 | ||
| 360 | impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> { | 615 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::BufRead for BufferedUarteRx<'u, 'd, U, T> { |
| 361 | type Interrupt = U::Interrupt; | 616 | async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { |
| 362 | fn on_interrupt(&mut self) { | 617 | self.inner.inner_fill_buf().await |
| 363 | trace!("irq: start"); | 618 | } |
| 364 | let r = U::regs(); | ||
| 365 | 619 | ||
| 366 | loop { | 620 | fn consume(&mut self, amt: usize) { |
| 367 | match self.rx_state { | 621 | self.inner.inner_consume(amt) |
| 368 | RxState::Idle => { | ||
| 369 | trace!(" irq_rx: in state idle"); | ||
| 370 | |||
| 371 | let buf = self.rx.push_buf(); | ||
| 372 | if !buf.is_empty() { | ||
| 373 | trace!(" irq_rx: starting {:?}", buf.len()); | ||
| 374 | self.rx_state = RxState::Receiving; | ||
| 375 | |||
| 376 | // Set up the DMA read | ||
| 377 | r.rxd.ptr.write(|w| | ||
| 378 | // The PTR field is a full 32 bits wide and accepts the full range | ||
| 379 | // of values. | ||
| 380 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | ||
| 381 | r.rxd.maxcnt.write(|w| | ||
| 382 | // We're giving it the length of the buffer, so no danger of | ||
| 383 | // accessing invalid memory. We have verified that the length of the | ||
| 384 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||
| 385 | // | ||
| 386 | // The MAXCNT field is at least 8 bits wide and accepts the full | ||
| 387 | // range of values. | ||
| 388 | unsafe { w.maxcnt().bits(buf.len() as _) }); | ||
| 389 | trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); | ||
| 390 | |||
| 391 | // Start UARTE Receive transaction | ||
| 392 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 393 | } | ||
| 394 | break; | ||
| 395 | } | ||
| 396 | RxState::Receiving => { | ||
| 397 | trace!(" irq_rx: in state receiving"); | ||
| 398 | if r.events_endrx.read().bits() != 0 { | ||
| 399 | self.timer.stop(); | ||
| 400 | |||
| 401 | let n: usize = r.rxd.amount.read().amount().bits() as usize; | ||
| 402 | trace!(" irq_rx: endrx {:?}", n); | ||
| 403 | self.rx.push(n); | ||
| 404 | |||
| 405 | r.events_endrx.reset(); | ||
| 406 | |||
| 407 | self.rx_waker.wake(); | ||
| 408 | self.rx_state = RxState::Idle; | ||
| 409 | } else { | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | } | ||
| 414 | } | 622 | } |
| 623 | } | ||
| 415 | 624 | ||
| 416 | loop { | 625 | impl<'d, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarte<'d, U, T> { |
| 417 | match self.tx_state { | 626 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 418 | TxState::Idle => { | 627 | self.inner_write(buf).await |
| 419 | trace!(" irq_tx: in state Idle"); | 628 | } |
| 420 | let buf = self.tx.pop_buf(); | 629 | |
| 421 | if !buf.is_empty() { | 630 | async fn flush(&mut self) -> Result<(), Self::Error> { |
| 422 | trace!(" irq_tx: starting {:?}", buf.len()); | 631 | self.inner_flush().await |
| 423 | self.tx_state = TxState::Transmitting(buf.len()); | 632 | } |
| 424 | 633 | } | |
| 425 | // Set up the DMA write | 634 | |
| 426 | r.txd.ptr.write(|w| | 635 | impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write for BufferedUarteTx<'u, 'd, U, T> { |
| 427 | // The PTR field is a full 32 bits wide and accepts the full range | 636 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 428 | // of values. | 637 | self.inner.inner_write(buf).await |
| 429 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | 638 | } |
| 430 | r.txd.maxcnt.write(|w| | 639 | |
| 431 | // We're giving it the length of the buffer, so no danger of | 640 | async fn flush(&mut self) -> Result<(), Self::Error> { |
| 432 | // accessing invalid memory. We have verified that the length of the | 641 | self.inner.inner_flush().await |
| 433 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||
| 434 | // | ||
| 435 | // The MAXCNT field is 8 bits wide and accepts the full range of | ||
| 436 | // values. | ||
| 437 | unsafe { w.maxcnt().bits(buf.len() as _) }); | ||
| 438 | |||
| 439 | // Start UARTE Transmit transaction | ||
| 440 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 441 | } | ||
| 442 | break; | ||
| 443 | } | ||
| 444 | TxState::Transmitting(n) => { | ||
| 445 | trace!(" irq_tx: in state Transmitting"); | ||
| 446 | if r.events_endtx.read().bits() != 0 { | ||
| 447 | r.events_endtx.reset(); | ||
| 448 | |||
| 449 | trace!(" irq_tx: endtx {:?}", n); | ||
| 450 | self.tx.pop(n); | ||
| 451 | self.tx_waker.wake(); | ||
| 452 | self.tx_state = TxState::Idle; | ||
| 453 | } else { | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | 642 | } |
| 459 | trace!("irq: end"); | ||
| 460 | } | 643 | } |
| 461 | } | 644 | } |
| 462 | 645 | ||
| 463 | /// Low power blocking wait loop using WFE/SEV. | 646 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> { |
| 464 | fn low_power_wait_until(mut condition: impl FnMut() -> bool) { | 647 | fn drop(&mut self) { |
| 465 | while !condition() { | 648 | self._ppi_group.disable_all(); |
| 466 | // WFE might "eat" an event that would have otherwise woken the executor. | 649 | |
| 467 | cortex_m::asm::wfe(); | 650 | let r = U::regs(); |
| 651 | |||
| 652 | self.timer.stop(); | ||
| 653 | |||
| 654 | r.inten.reset(); | ||
| 655 | r.events_rxto.reset(); | ||
| 656 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 657 | r.events_txstopped.reset(); | ||
| 658 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 659 | |||
| 660 | while r.events_txstopped.read().bits() == 0 {} | ||
| 661 | while r.events_rxto.read().bits() == 0 {} | ||
| 662 | |||
| 663 | r.enable.write(|w| w.enable().disabled()); | ||
| 664 | |||
| 665 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 666 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 667 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 668 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 669 | |||
| 670 | let s = U::buffered_state(); | ||
| 671 | unsafe { | ||
| 672 | s.rx_buf.deinit(); | ||
| 673 | s.tx_buf.deinit(); | ||
| 674 | } | ||
| 468 | } | 675 | } |
| 469 | // Retrigger an event to be transparent to the executor. | ||
| 470 | cortex_m::asm::sev(); | ||
| 471 | } | 676 | } |
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index d078fa0ad..8776000c8 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | 7 | pub const FLASH_SIZE: usize = 192 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 21; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // RTC | 12 | // RTC |
| 11 | RTC0, | 13 | RTC0, |
| @@ -108,6 +110,7 @@ embassy_hal_common::peripherals! { | |||
| 108 | P0_18, | 110 | P0_18, |
| 109 | P0_19, | 111 | P0_19, |
| 110 | P0_20, | 112 | P0_20, |
| 113 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 111 | P0_21, | 114 | P0_21, |
| 112 | P0_22, | 115 | P0_22, |
| 113 | P0_23, | 116 | P0_23, |
| @@ -131,8 +134,16 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | |||
| 131 | 134 | ||
| 132 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | 135 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); |
| 133 | 136 | ||
| 137 | impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); | ||
| 138 | |||
| 134 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | 139 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); |
| 135 | 140 | ||
| 141 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||
| 142 | |||
| 143 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 144 | |||
| 145 | impl_rng!(RNG, RNG, RNG); | ||
| 146 | |||
| 136 | impl_timer!(TIMER0, TIMER0, TIMER0); | 147 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 137 | impl_timer!(TIMER1, TIMER1, TIMER1); | 148 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 138 | impl_timer!(TIMER2, TIMER2, TIMER2); | 149 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -158,6 +169,7 @@ impl_pin!(P0_17, 0, 17); | |||
| 158 | impl_pin!(P0_18, 0, 18); | 169 | impl_pin!(P0_18, 0, 18); |
| 159 | impl_pin!(P0_19, 0, 19); | 170 | impl_pin!(P0_19, 0, 19); |
| 160 | impl_pin!(P0_20, 0, 20); | 171 | impl_pin!(P0_20, 0, 20); |
| 172 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 161 | impl_pin!(P0_21, 0, 21); | 173 | impl_pin!(P0_21, 0, 21); |
| 162 | impl_pin!(P0_22, 0, 22); | 174 | impl_pin!(P0_22, 0, 22); |
| 163 | impl_pin!(P0_23, 0, 23); | 175 | impl_pin!(P0_23, 0, 23); |
| @@ -193,36 +205,32 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 193 | impl_ppi_channel!(PPI_CH30, 30 => static); | 205 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 194 | impl_ppi_channel!(PPI_CH31, 31 => static); | 206 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 195 | 207 | ||
| 196 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 208 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 197 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 209 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 198 | 210 | ||
| 199 | pub mod irqs { | 211 | embassy_hal_common::interrupt_mod!( |
| 200 | use embassy_cortex_m::interrupt::_export::declare; | 212 | POWER_CLOCK, |
| 201 | 213 | RADIO, | |
| 202 | use crate::pac::Interrupt as InterruptEnum; | 214 | UARTE0_UART0, |
| 203 | 215 | TWIM0_TWIS0_TWI0, | |
| 204 | declare!(POWER_CLOCK); | 216 | SPIM0_SPIS0_SPI0, |
| 205 | declare!(RADIO); | 217 | GPIOTE, |
| 206 | declare!(UARTE0_UART0); | 218 | SAADC, |
| 207 | declare!(TWIM0_TWIS0_TWI0); | 219 | TIMER0, |
| 208 | declare!(SPIM0_SPIS0_SPI0); | 220 | TIMER1, |
| 209 | declare!(GPIOTE); | 221 | TIMER2, |
| 210 | declare!(SAADC); | 222 | RTC0, |
| 211 | declare!(TIMER0); | 223 | TEMP, |
| 212 | declare!(TIMER1); | 224 | RNG, |
| 213 | declare!(TIMER2); | 225 | ECB, |
| 214 | declare!(RTC0); | 226 | CCM_AAR, |
| 215 | declare!(TEMP); | 227 | WDT, |
| 216 | declare!(RNG); | 228 | RTC1, |
| 217 | declare!(ECB); | 229 | QDEC, |
| 218 | declare!(CCM_AAR); | 230 | SWI0_EGU0, |
| 219 | declare!(WDT); | 231 | SWI1_EGU1, |
| 220 | declare!(RTC1); | 232 | SWI2, |
| 221 | declare!(QDEC); | 233 | SWI3, |
| 222 | declare!(SWI0_EGU0); | 234 | SWI4, |
| 223 | declare!(SWI1_EGU1); | 235 | SWI5, |
| 224 | declare!(SWI2); | 236 | ); |
| 225 | declare!(SWI3); | ||
| 226 | declare!(SWI4); | ||
| 227 | declare!(SWI5); | ||
| 228 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 3e500098c..5519e8953 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | 7 | pub const FLASH_SIZE: usize = 192 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 21; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // RTC | 12 | // RTC |
| 11 | RTC0, | 13 | RTC0, |
| @@ -111,6 +113,7 @@ embassy_hal_common::peripherals! { | |||
| 111 | P0_18, | 113 | P0_18, |
| 112 | P0_19, | 114 | P0_19, |
| 113 | P0_20, | 115 | P0_20, |
| 116 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 114 | P0_21, | 117 | P0_21, |
| 115 | P0_22, | 118 | P0_22, |
| 116 | P0_23, | 119 | P0_23, |
| @@ -137,10 +140,20 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | |||
| 137 | 140 | ||
| 138 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); | 141 | impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); |
| 139 | 142 | ||
| 143 | impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); | ||
| 144 | |||
| 140 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); | 145 | impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); |
| 141 | 146 | ||
| 147 | impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); | ||
| 148 | |||
| 142 | impl_pwm!(PWM0, PWM0, PWM0); | 149 | impl_pwm!(PWM0, PWM0, PWM0); |
| 143 | 150 | ||
| 151 | impl_pdm!(PDM, PDM, PDM); | ||
| 152 | |||
| 153 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 154 | |||
| 155 | impl_rng!(RNG, RNG, RNG); | ||
| 156 | |||
| 144 | impl_timer!(TIMER0, TIMER0, TIMER0); | 157 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 145 | impl_timer!(TIMER1, TIMER1, TIMER1); | 158 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 146 | impl_timer!(TIMER2, TIMER2, TIMER2); | 159 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -166,6 +179,7 @@ impl_pin!(P0_17, 0, 17); | |||
| 166 | impl_pin!(P0_18, 0, 18); | 179 | impl_pin!(P0_18, 0, 18); |
| 167 | impl_pin!(P0_19, 0, 19); | 180 | impl_pin!(P0_19, 0, 19); |
| 168 | impl_pin!(P0_20, 0, 20); | 181 | impl_pin!(P0_20, 0, 20); |
| 182 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 169 | impl_pin!(P0_21, 0, 21); | 183 | impl_pin!(P0_21, 0, 21); |
| 170 | impl_pin!(P0_22, 0, 22); | 184 | impl_pin!(P0_22, 0, 22); |
| 171 | impl_pin!(P0_23, 0, 23); | 185 | impl_pin!(P0_23, 0, 23); |
| @@ -211,45 +225,41 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 211 | impl_ppi_channel!(PPI_CH30, 30 => static); | 225 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 212 | impl_ppi_channel!(PPI_CH31, 31 => static); | 226 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 213 | 227 | ||
| 214 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 228 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 215 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 229 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 216 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 230 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 217 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 231 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 218 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 232 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 219 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 233 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 220 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 234 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 221 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 235 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 222 | 236 | ||
| 223 | pub mod irqs { | 237 | embassy_hal_common::interrupt_mod!( |
| 224 | use embassy_cortex_m::interrupt::_export::declare; | 238 | POWER_CLOCK, |
| 225 | 239 | RADIO, | |
| 226 | use crate::pac::Interrupt as InterruptEnum; | 240 | UARTE0_UART0, |
| 227 | 241 | TWIM0_TWIS0_TWI0, | |
| 228 | declare!(POWER_CLOCK); | 242 | SPIM0_SPIS0_SPI0, |
| 229 | declare!(RADIO); | 243 | GPIOTE, |
| 230 | declare!(UARTE0_UART0); | 244 | SAADC, |
| 231 | declare!(TWIM0_TWIS0_TWI0); | 245 | TIMER0, |
| 232 | declare!(SPIM0_SPIS0_SPI0); | 246 | TIMER1, |
| 233 | declare!(GPIOTE); | 247 | TIMER2, |
| 234 | declare!(SAADC); | 248 | RTC0, |
| 235 | declare!(TIMER0); | 249 | TEMP, |
| 236 | declare!(TIMER1); | 250 | RNG, |
| 237 | declare!(TIMER2); | 251 | ECB, |
| 238 | declare!(RTC0); | 252 | CCM_AAR, |
| 239 | declare!(TEMP); | 253 | WDT, |
| 240 | declare!(RNG); | 254 | RTC1, |
| 241 | declare!(ECB); | 255 | QDEC, |
| 242 | declare!(CCM_AAR); | 256 | COMP, |
| 243 | declare!(WDT); | 257 | SWI0_EGU0, |
| 244 | declare!(RTC1); | 258 | SWI1_EGU1, |
| 245 | declare!(QDEC); | 259 | SWI2, |
| 246 | declare!(COMP); | 260 | SWI3, |
| 247 | declare!(SWI0_EGU0); | 261 | SWI4, |
| 248 | declare!(SWI1_EGU1); | 262 | SWI5, |
| 249 | declare!(SWI2); | 263 | PWM0, |
| 250 | declare!(SWI3); | 264 | PDM, |
| 251 | declare!(SWI4); | 265 | ); |
| 252 | declare!(SWI5); | ||
| 253 | declare!(PWM0); | ||
| 254 | declare!(PDM); | ||
| 255 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 25c7c0d91..d5367c59a 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 256; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 192 * 1024; | 7 | pub const FLASH_SIZE: usize = 192 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 21; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // RTC | 12 | // RTC |
| 11 | RTC0, | 13 | RTC0, |
| @@ -111,6 +113,7 @@ embassy_hal_common::peripherals! { | |||
| 111 | P0_18, | 113 | P0_18, |
| 112 | P0_19, | 114 | P0_19, |
| 113 | P0_20, | 115 | P0_20, |
| 116 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 114 | P0_21, | 117 | P0_21, |
| 115 | P0_22, | 118 | P0_22, |
| 116 | P0_23, | 119 | P0_23, |
| @@ -138,10 +141,21 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | |||
| 138 | impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 141 | impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); |
| 139 | impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); | 142 | impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); |
| 140 | 143 | ||
| 144 | impl_spis!(TWISPI0, SPIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||
| 145 | impl_spis!(SPI1, SPIS1, SPIM1_SPIS1_SPI1); | ||
| 146 | |||
| 141 | impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 147 | impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); |
| 142 | 148 | ||
| 149 | impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | ||
| 150 | |||
| 143 | impl_pwm!(PWM0, PWM0, PWM0); | 151 | impl_pwm!(PWM0, PWM0, PWM0); |
| 144 | 152 | ||
| 153 | impl_pdm!(PDM, PDM, PDM); | ||
| 154 | |||
| 155 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 156 | |||
| 157 | impl_rng!(RNG, RNG, RNG); | ||
| 158 | |||
| 145 | impl_timer!(TIMER0, TIMER0, TIMER0); | 159 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 146 | impl_timer!(TIMER1, TIMER1, TIMER1); | 160 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 147 | impl_timer!(TIMER2, TIMER2, TIMER2); | 161 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -167,6 +181,7 @@ impl_pin!(P0_17, 0, 17); | |||
| 167 | impl_pin!(P0_18, 0, 18); | 181 | impl_pin!(P0_18, 0, 18); |
| 168 | impl_pin!(P0_19, 0, 19); | 182 | impl_pin!(P0_19, 0, 19); |
| 169 | impl_pin!(P0_20, 0, 20); | 183 | impl_pin!(P0_20, 0, 20); |
| 184 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 170 | impl_pin!(P0_21, 0, 21); | 185 | impl_pin!(P0_21, 0, 21); |
| 171 | impl_pin!(P0_22, 0, 22); | 186 | impl_pin!(P0_22, 0, 22); |
| 172 | impl_pin!(P0_23, 0, 23); | 187 | impl_pin!(P0_23, 0, 23); |
| @@ -212,45 +227,41 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 212 | impl_ppi_channel!(PPI_CH30, 30 => static); | 227 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 213 | impl_ppi_channel!(PPI_CH31, 31 => static); | 228 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 214 | 229 | ||
| 215 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 230 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 216 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 231 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 217 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 232 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 218 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 233 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 219 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 234 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 220 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 235 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 221 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 236 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 222 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 237 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 223 | 238 | ||
| 224 | pub mod irqs { | 239 | embassy_hal_common::interrupt_mod!( |
| 225 | use embassy_cortex_m::interrupt::_export::declare; | 240 | POWER_CLOCK, |
| 226 | 241 | RADIO, | |
| 227 | use crate::pac::Interrupt as InterruptEnum; | 242 | UARTE0_UART0, |
| 228 | 243 | TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0, | |
| 229 | declare!(POWER_CLOCK); | 244 | SPIM1_SPIS1_SPI1, |
| 230 | declare!(RADIO); | 245 | GPIOTE, |
| 231 | declare!(UARTE0_UART0); | 246 | SAADC, |
| 232 | declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); | 247 | TIMER0, |
| 233 | declare!(SPIM1_SPIS1_SPI1); | 248 | TIMER1, |
| 234 | declare!(GPIOTE); | 249 | TIMER2, |
| 235 | declare!(SAADC); | 250 | RTC0, |
| 236 | declare!(TIMER0); | 251 | TEMP, |
| 237 | declare!(TIMER1); | 252 | RNG, |
| 238 | declare!(TIMER2); | 253 | ECB, |
| 239 | declare!(RTC0); | 254 | CCM_AAR, |
| 240 | declare!(TEMP); | 255 | WDT, |
| 241 | declare!(RNG); | 256 | RTC1, |
| 242 | declare!(ECB); | 257 | QDEC, |
| 243 | declare!(CCM_AAR); | 258 | COMP, |
| 244 | declare!(WDT); | 259 | SWI0_EGU0, |
| 245 | declare!(RTC1); | 260 | SWI1_EGU1, |
| 246 | declare!(QDEC); | 261 | SWI2, |
| 247 | declare!(COMP); | 262 | SWI3, |
| 248 | declare!(SWI0_EGU0); | 263 | SWI4, |
| 249 | declare!(SWI1_EGU1); | 264 | SWI5, |
| 250 | declare!(SWI2); | 265 | PWM0, |
| 251 | declare!(SWI3); | 266 | PDM, |
| 252 | declare!(SWI4); | 267 | ); |
| 253 | declare!(SWI5); | ||
| 254 | declare!(PWM0); | ||
| 255 | declare!(PDM); | ||
| 256 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index dba033b0f..785170447 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 256 * 1024; | 7 | pub const FLASH_SIZE: usize = 256 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 18; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // USB | 12 | // USB |
| 11 | USBD, | 13 | USBD, |
| @@ -106,6 +108,7 @@ embassy_hal_common::peripherals! { | |||
| 106 | P0_15, | 108 | P0_15, |
| 107 | P0_16, | 109 | P0_16, |
| 108 | P0_17, | 110 | P0_17, |
| 111 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 109 | P0_18, | 112 | P0_18, |
| 110 | P0_19, | 113 | P0_19, |
| 111 | P0_20, | 114 | P0_20, |
| @@ -136,14 +139,24 @@ impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); | |||
| 136 | impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 139 | impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 137 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 140 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 138 | 141 | ||
| 142 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 143 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 144 | |||
| 139 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 145 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 140 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 146 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 141 | 147 | ||
| 148 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 149 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 150 | |||
| 142 | impl_timer!(TIMER0, TIMER0, TIMER0); | 151 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 143 | impl_timer!(TIMER1, TIMER1, TIMER1); | 152 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 144 | impl_timer!(TIMER2, TIMER2, TIMER2); | 153 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 145 | impl_timer!(TIMER3, TIMER3, TIMER3, extended); | 154 | impl_timer!(TIMER3, TIMER3, TIMER3, extended); |
| 146 | 155 | ||
| 156 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 157 | |||
| 158 | impl_rng!(RNG, RNG, RNG); | ||
| 159 | |||
| 147 | impl_pin!(P0_00, 0, 0); | 160 | impl_pin!(P0_00, 0, 0); |
| 148 | impl_pin!(P0_01, 0, 1); | 161 | impl_pin!(P0_01, 0, 1); |
| 149 | impl_pin!(P0_02, 0, 2); | 162 | impl_pin!(P0_02, 0, 2); |
| @@ -162,6 +175,7 @@ impl_pin!(P0_14, 0, 14); | |||
| 162 | impl_pin!(P0_15, 0, 15); | 175 | impl_pin!(P0_15, 0, 15); |
| 163 | impl_pin!(P0_16, 0, 16); | 176 | impl_pin!(P0_16, 0, 16); |
| 164 | impl_pin!(P0_17, 0, 17); | 177 | impl_pin!(P0_17, 0, 17); |
| 178 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 165 | impl_pin!(P0_18, 0, 18); | 179 | impl_pin!(P0_18, 0, 18); |
| 166 | impl_pin!(P0_19, 0, 19); | 180 | impl_pin!(P0_19, 0, 19); |
| 167 | impl_pin!(P0_20, 0, 20); | 181 | impl_pin!(P0_20, 0, 20); |
| @@ -210,35 +224,31 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 210 | impl_ppi_channel!(PPI_CH30, 30 => static); | 224 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 211 | impl_ppi_channel!(PPI_CH31, 31 => static); | 225 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 212 | 226 | ||
| 213 | pub mod irqs { | 227 | embassy_hal_common::interrupt_mod!( |
| 214 | use embassy_cortex_m::interrupt::_export::declare; | 228 | POWER_CLOCK, |
| 215 | 229 | RADIO, | |
| 216 | use crate::pac::Interrupt as InterruptEnum; | 230 | UARTE0_UART0, |
| 217 | 231 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, | |
| 218 | declare!(POWER_CLOCK); | 232 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 219 | declare!(RADIO); | 233 | GPIOTE, |
| 220 | declare!(UARTE0_UART0); | 234 | TIMER0, |
| 221 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 235 | TIMER1, |
| 222 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 236 | TIMER2, |
| 223 | declare!(GPIOTE); | 237 | RTC0, |
| 224 | declare!(TIMER0); | 238 | TEMP, |
| 225 | declare!(TIMER1); | 239 | RNG, |
| 226 | declare!(TIMER2); | 240 | ECB, |
| 227 | declare!(RTC0); | 241 | CCM_AAR, |
| 228 | declare!(TEMP); | 242 | WDT, |
| 229 | declare!(RNG); | 243 | RTC1, |
| 230 | declare!(ECB); | 244 | QDEC, |
| 231 | declare!(CCM_AAR); | 245 | COMP, |
| 232 | declare!(WDT); | 246 | SWI0_EGU0, |
| 233 | declare!(RTC1); | 247 | SWI1_EGU1, |
| 234 | declare!(QDEC); | 248 | SWI2_EGU2, |
| 235 | declare!(COMP); | 249 | SWI3_EGU3, |
| 236 | declare!(SWI0_EGU0); | 250 | SWI4_EGU4, |
| 237 | declare!(SWI1_EGU1); | 251 | SWI5_EGU5, |
| 238 | declare!(SWI2_EGU2); | 252 | TIMER3, |
| 239 | declare!(SWI3_EGU3); | 253 | USBD, |
| 240 | declare!(SWI4_EGU4); | 254 | ); |
| 241 | declare!(SWI5_EGU5); | ||
| 242 | declare!(TIMER3); | ||
| 243 | declare!(USBD); | ||
| 244 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 2c6276d4a..b77564a5c 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs | |||
| @@ -10,6 +10,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 255; | |||
| 10 | // nrf52832xxAB = 256kb | 10 | // nrf52832xxAB = 256kb |
| 11 | pub const FLASH_SIZE: usize = 512 * 1024; | 11 | pub const FLASH_SIZE: usize = 512 * 1024; |
| 12 | 12 | ||
| 13 | pub const RESET_PIN: u32 = 21; | ||
| 14 | |||
| 13 | embassy_hal_common::peripherals! { | 15 | embassy_hal_common::peripherals! { |
| 14 | // RTC | 16 | // RTC |
| 15 | RTC0, | 17 | RTC0, |
| @@ -109,7 +111,9 @@ embassy_hal_common::peripherals! { | |||
| 109 | P0_06, | 111 | P0_06, |
| 110 | P0_07, | 112 | P0_07, |
| 111 | P0_08, | 113 | P0_08, |
| 114 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 112 | P0_09, | 115 | P0_09, |
| 116 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 113 | P0_10, | 117 | P0_10, |
| 114 | P0_11, | 118 | P0_11, |
| 115 | P0_12, | 119 | P0_12, |
| @@ -121,6 +125,7 @@ embassy_hal_common::peripherals! { | |||
| 121 | P0_18, | 125 | P0_18, |
| 122 | P0_19, | 126 | P0_19, |
| 123 | P0_20, | 127 | P0_20, |
| 128 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 124 | P0_21, | 129 | P0_21, |
| 125 | P0_22, | 130 | P0_22, |
| 126 | P0_23, | 131 | P0_23, |
| @@ -139,6 +144,9 @@ embassy_hal_common::peripherals! { | |||
| 139 | // QDEC | 144 | // QDEC |
| 140 | QDEC, | 145 | QDEC, |
| 141 | 146 | ||
| 147 | // I2S | ||
| 148 | I2S, | ||
| 149 | |||
| 142 | // PDM | 150 | // PDM |
| 143 | PDM, | 151 | PDM, |
| 144 | } | 152 | } |
| @@ -149,13 +157,26 @@ impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | |||
| 149 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 157 | impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 150 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 158 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 151 | 159 | ||
| 160 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 161 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 162 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 163 | |||
| 152 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 164 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 153 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 165 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 154 | 166 | ||
| 167 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 168 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 169 | |||
| 155 | impl_pwm!(PWM0, PWM0, PWM0); | 170 | impl_pwm!(PWM0, PWM0, PWM0); |
| 156 | impl_pwm!(PWM1, PWM1, PWM1); | 171 | impl_pwm!(PWM1, PWM1, PWM1); |
| 157 | impl_pwm!(PWM2, PWM2, PWM2); | 172 | impl_pwm!(PWM2, PWM2, PWM2); |
| 158 | 173 | ||
| 174 | impl_pdm!(PDM, PDM, PDM); | ||
| 175 | |||
| 176 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 177 | |||
| 178 | impl_rng!(RNG, RNG, RNG); | ||
| 179 | |||
| 159 | impl_timer!(TIMER0, TIMER0, TIMER0); | 180 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 160 | impl_timer!(TIMER1, TIMER1, TIMER1); | 181 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 161 | impl_timer!(TIMER2, TIMER2, TIMER2); | 182 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -171,7 +192,9 @@ impl_pin!(P0_05, 0, 5); | |||
| 171 | impl_pin!(P0_06, 0, 6); | 192 | impl_pin!(P0_06, 0, 6); |
| 172 | impl_pin!(P0_07, 0, 7); | 193 | impl_pin!(P0_07, 0, 7); |
| 173 | impl_pin!(P0_08, 0, 8); | 194 | impl_pin!(P0_08, 0, 8); |
| 195 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 174 | impl_pin!(P0_09, 0, 9); | 196 | impl_pin!(P0_09, 0, 9); |
| 197 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 175 | impl_pin!(P0_10, 0, 10); | 198 | impl_pin!(P0_10, 0, 10); |
| 176 | impl_pin!(P0_11, 0, 11); | 199 | impl_pin!(P0_11, 0, 11); |
| 177 | impl_pin!(P0_12, 0, 12); | 200 | impl_pin!(P0_12, 0, 12); |
| @@ -183,6 +206,7 @@ impl_pin!(P0_17, 0, 17); | |||
| 183 | impl_pin!(P0_18, 0, 18); | 206 | impl_pin!(P0_18, 0, 18); |
| 184 | impl_pin!(P0_19, 0, 19); | 207 | impl_pin!(P0_19, 0, 19); |
| 185 | impl_pin!(P0_20, 0, 20); | 208 | impl_pin!(P0_20, 0, 20); |
| 209 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 186 | impl_pin!(P0_21, 0, 21); | 210 | impl_pin!(P0_21, 0, 21); |
| 187 | impl_pin!(P0_22, 0, 22); | 211 | impl_pin!(P0_22, 0, 22); |
| 188 | impl_pin!(P0_23, 0, 23); | 212 | impl_pin!(P0_23, 0, 23); |
| @@ -228,55 +252,53 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 228 | impl_ppi_channel!(PPI_CH30, 30 => static); | 252 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 229 | impl_ppi_channel!(PPI_CH31, 31 => static); | 253 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 230 | 254 | ||
| 231 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 255 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 232 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 256 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 233 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 257 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 234 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 258 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 235 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 259 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 236 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 260 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 237 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 261 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 238 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 262 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 239 | 263 | ||
| 240 | pub mod irqs { | 264 | impl_i2s!(I2S, I2S, I2S); |
| 241 | use embassy_cortex_m::interrupt::_export::declare; | 265 | |
| 242 | 266 | embassy_hal_common::interrupt_mod!( | |
| 243 | use crate::pac::Interrupt as InterruptEnum; | 267 | POWER_CLOCK, |
| 244 | 268 | RADIO, | |
| 245 | declare!(POWER_CLOCK); | 269 | UARTE0_UART0, |
| 246 | declare!(RADIO); | 270 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, |
| 247 | declare!(UARTE0_UART0); | 271 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 248 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 272 | NFCT, |
| 249 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 273 | GPIOTE, |
| 250 | declare!(NFCT); | 274 | SAADC, |
| 251 | declare!(GPIOTE); | 275 | TIMER0, |
| 252 | declare!(SAADC); | 276 | TIMER1, |
| 253 | declare!(TIMER0); | 277 | TIMER2, |
| 254 | declare!(TIMER1); | 278 | RTC0, |
| 255 | declare!(TIMER2); | 279 | TEMP, |
| 256 | declare!(RTC0); | 280 | RNG, |
| 257 | declare!(TEMP); | 281 | ECB, |
| 258 | declare!(RNG); | 282 | CCM_AAR, |
| 259 | declare!(ECB); | 283 | WDT, |
| 260 | declare!(CCM_AAR); | 284 | RTC1, |
| 261 | declare!(WDT); | 285 | QDEC, |
| 262 | declare!(RTC1); | 286 | COMP_LPCOMP, |
| 263 | declare!(QDEC); | 287 | SWI0_EGU0, |
| 264 | declare!(COMP_LPCOMP); | 288 | SWI1_EGU1, |
| 265 | declare!(SWI0_EGU0); | 289 | SWI2_EGU2, |
| 266 | declare!(SWI1_EGU1); | 290 | SWI3_EGU3, |
| 267 | declare!(SWI2_EGU2); | 291 | SWI4_EGU4, |
| 268 | declare!(SWI3_EGU3); | 292 | SWI5_EGU5, |
| 269 | declare!(SWI4_EGU4); | 293 | TIMER3, |
| 270 | declare!(SWI5_EGU5); | 294 | TIMER4, |
| 271 | declare!(TIMER3); | 295 | PWM0, |
| 272 | declare!(TIMER4); | 296 | PDM, |
| 273 | declare!(PWM0); | 297 | MWU, |
| 274 | declare!(PDM); | 298 | PWM1, |
| 275 | declare!(MWU); | 299 | PWM2, |
| 276 | declare!(PWM1); | 300 | SPIM2_SPIS2_SPI2, |
| 277 | declare!(PWM2); | 301 | RTC2, |
| 278 | declare!(SPIM2_SPIS2_SPI2); | 302 | FPU, |
| 279 | declare!(RTC2); | 303 | I2S, |
| 280 | declare!(I2S); | 304 | ); |
| 281 | declare!(FPU); | ||
| 282 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 3b33907d2..bff7f4ebb 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 512 * 1024; | 7 | pub const FLASH_SIZE: usize = 512 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 18; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // USB | 12 | // USB |
| 11 | USBD, | 13 | USBD, |
| @@ -111,7 +113,9 @@ embassy_hal_common::peripherals! { | |||
| 111 | P0_06, | 113 | P0_06, |
| 112 | P0_07, | 114 | P0_07, |
| 113 | P0_08, | 115 | P0_08, |
| 116 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 114 | P0_09, | 117 | P0_09, |
| 118 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 115 | P0_10, | 119 | P0_10, |
| 116 | P0_11, | 120 | P0_11, |
| 117 | P0_12, | 121 | P0_12, |
| @@ -120,6 +124,7 @@ embassy_hal_common::peripherals! { | |||
| 120 | P0_15, | 124 | P0_15, |
| 121 | P0_16, | 125 | P0_16, |
| 122 | P0_17, | 126 | P0_17, |
| 127 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 123 | P0_18, | 128 | P0_18, |
| 124 | P0_19, | 129 | P0_19, |
| 125 | P0_20, | 130 | P0_20, |
| @@ -161,6 +166,9 @@ embassy_hal_common::peripherals! { | |||
| 161 | 166 | ||
| 162 | // PDM | 167 | // PDM |
| 163 | PDM, | 168 | PDM, |
| 169 | |||
| 170 | // I2S | ||
| 171 | I2S, | ||
| 164 | } | 172 | } |
| 165 | 173 | ||
| 166 | #[cfg(feature = "nightly")] | 174 | #[cfg(feature = "nightly")] |
| @@ -174,14 +182,27 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | |||
| 174 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 182 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 175 | impl_spim!(SPI3, SPIM3, SPIM3); | 183 | impl_spim!(SPI3, SPIM3, SPIM3); |
| 176 | 184 | ||
| 185 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 186 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 187 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 188 | |||
| 177 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 189 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 178 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 190 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 179 | 191 | ||
| 192 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 193 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 194 | |||
| 180 | impl_pwm!(PWM0, PWM0, PWM0); | 195 | impl_pwm!(PWM0, PWM0, PWM0); |
| 181 | impl_pwm!(PWM1, PWM1, PWM1); | 196 | impl_pwm!(PWM1, PWM1, PWM1); |
| 182 | impl_pwm!(PWM2, PWM2, PWM2); | 197 | impl_pwm!(PWM2, PWM2, PWM2); |
| 183 | impl_pwm!(PWM3, PWM3, PWM3); | 198 | impl_pwm!(PWM3, PWM3, PWM3); |
| 184 | 199 | ||
| 200 | impl_pdm!(PDM, PDM, PDM); | ||
| 201 | |||
| 202 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 203 | |||
| 204 | impl_rng!(RNG, RNG, RNG); | ||
| 205 | |||
| 185 | impl_timer!(TIMER0, TIMER0, TIMER0); | 206 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 186 | impl_timer!(TIMER1, TIMER1, TIMER1); | 207 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 187 | impl_timer!(TIMER2, TIMER2, TIMER2); | 208 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -197,7 +218,9 @@ impl_pin!(P0_05, 0, 5); | |||
| 197 | impl_pin!(P0_06, 0, 6); | 218 | impl_pin!(P0_06, 0, 6); |
| 198 | impl_pin!(P0_07, 0, 7); | 219 | impl_pin!(P0_07, 0, 7); |
| 199 | impl_pin!(P0_08, 0, 8); | 220 | impl_pin!(P0_08, 0, 8); |
| 221 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 200 | impl_pin!(P0_09, 0, 9); | 222 | impl_pin!(P0_09, 0, 9); |
| 223 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 201 | impl_pin!(P0_10, 0, 10); | 224 | impl_pin!(P0_10, 0, 10); |
| 202 | impl_pin!(P0_11, 0, 11); | 225 | impl_pin!(P0_11, 0, 11); |
| 203 | impl_pin!(P0_12, 0, 12); | 226 | impl_pin!(P0_12, 0, 12); |
| @@ -206,6 +229,7 @@ impl_pin!(P0_14, 0, 14); | |||
| 206 | impl_pin!(P0_15, 0, 15); | 229 | impl_pin!(P0_15, 0, 15); |
| 207 | impl_pin!(P0_16, 0, 16); | 230 | impl_pin!(P0_16, 0, 16); |
| 208 | impl_pin!(P0_17, 0, 17); | 231 | impl_pin!(P0_17, 0, 17); |
| 232 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 209 | impl_pin!(P0_18, 0, 18); | 233 | impl_pin!(P0_18, 0, 18); |
| 210 | impl_pin!(P0_19, 0, 19); | 234 | impl_pin!(P0_19, 0, 19); |
| 211 | impl_pin!(P0_20, 0, 20); | 235 | impl_pin!(P0_20, 0, 20); |
| @@ -271,59 +295,57 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 271 | impl_ppi_channel!(PPI_CH30, 30 => static); | 295 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 272 | impl_ppi_channel!(PPI_CH31, 31 => static); | 296 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 273 | 297 | ||
| 274 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 298 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 275 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 299 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 276 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 300 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 277 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 301 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 278 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 302 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 279 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 303 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 280 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 304 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 281 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 305 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 282 | 306 | ||
| 283 | pub mod irqs { | 307 | impl_i2s!(I2S, I2S, I2S); |
| 284 | use embassy_cortex_m::interrupt::_export::declare; | 308 | |
| 285 | 309 | embassy_hal_common::interrupt_mod!( | |
| 286 | use crate::pac::Interrupt as InterruptEnum; | 310 | POWER_CLOCK, |
| 287 | 311 | RADIO, | |
| 288 | declare!(POWER_CLOCK); | 312 | UARTE0_UART0, |
| 289 | declare!(RADIO); | 313 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, |
| 290 | declare!(UARTE0_UART0); | 314 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 291 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 315 | NFCT, |
| 292 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 316 | GPIOTE, |
| 293 | declare!(NFCT); | 317 | SAADC, |
| 294 | declare!(GPIOTE); | 318 | TIMER0, |
| 295 | declare!(SAADC); | 319 | TIMER1, |
| 296 | declare!(TIMER0); | 320 | TIMER2, |
| 297 | declare!(TIMER1); | 321 | RTC0, |
| 298 | declare!(TIMER2); | 322 | TEMP, |
| 299 | declare!(RTC0); | 323 | RNG, |
| 300 | declare!(TEMP); | 324 | ECB, |
| 301 | declare!(RNG); | 325 | CCM_AAR, |
| 302 | declare!(ECB); | 326 | WDT, |
| 303 | declare!(CCM_AAR); | 327 | RTC1, |
| 304 | declare!(WDT); | 328 | QDEC, |
| 305 | declare!(RTC1); | 329 | COMP_LPCOMP, |
| 306 | declare!(QDEC); | 330 | SWI0_EGU0, |
| 307 | declare!(COMP_LPCOMP); | 331 | SWI1_EGU1, |
| 308 | declare!(SWI0_EGU0); | 332 | SWI2_EGU2, |
| 309 | declare!(SWI1_EGU1); | 333 | SWI3_EGU3, |
| 310 | declare!(SWI2_EGU2); | 334 | SWI4_EGU4, |
| 311 | declare!(SWI3_EGU3); | 335 | SWI5_EGU5, |
| 312 | declare!(SWI4_EGU4); | 336 | TIMER3, |
| 313 | declare!(SWI5_EGU5); | 337 | TIMER4, |
| 314 | declare!(TIMER3); | 338 | PWM0, |
| 315 | declare!(TIMER4); | 339 | PDM, |
| 316 | declare!(PWM0); | 340 | MWU, |
| 317 | declare!(PDM); | 341 | PWM1, |
| 318 | declare!(MWU); | 342 | PWM2, |
| 319 | declare!(PWM1); | 343 | SPIM2_SPIS2_SPI2, |
| 320 | declare!(PWM2); | 344 | RTC2, |
| 321 | declare!(SPIM2_SPIS2_SPI2); | 345 | FPU, |
| 322 | declare!(RTC2); | 346 | USBD, |
| 323 | declare!(I2S); | 347 | UARTE1, |
| 324 | declare!(FPU); | 348 | PWM3, |
| 325 | declare!(USBD); | 349 | SPIM3, |
| 326 | declare!(UARTE1); | 350 | I2S, |
| 327 | declare!(PWM3); | 351 | ); |
| 328 | declare!(SPIM3); | ||
| 329 | } | ||
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index ae59f8b25..9b0050823 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs | |||
| @@ -6,6 +6,8 @@ pub const FORCE_COPY_BUFFER_SIZE: usize = 512; | |||
| 6 | 6 | ||
| 7 | pub const FLASH_SIZE: usize = 1024 * 1024; | 7 | pub const FLASH_SIZE: usize = 1024 * 1024; |
| 8 | 8 | ||
| 9 | pub const RESET_PIN: u32 = 18; | ||
| 10 | |||
| 9 | embassy_hal_common::peripherals! { | 11 | embassy_hal_common::peripherals! { |
| 10 | // USB | 12 | // USB |
| 11 | USBD, | 13 | USBD, |
| @@ -117,7 +119,9 @@ embassy_hal_common::peripherals! { | |||
| 117 | P0_06, | 119 | P0_06, |
| 118 | P0_07, | 120 | P0_07, |
| 119 | P0_08, | 121 | P0_08, |
| 122 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 120 | P0_09, | 123 | P0_09, |
| 124 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 121 | P0_10, | 125 | P0_10, |
| 122 | P0_11, | 126 | P0_11, |
| 123 | P0_12, | 127 | P0_12, |
| @@ -126,6 +130,7 @@ embassy_hal_common::peripherals! { | |||
| 126 | P0_15, | 130 | P0_15, |
| 127 | P0_16, | 131 | P0_16, |
| 128 | P0_17, | 132 | P0_17, |
| 133 | #[cfg(feature="reset-pin-as-gpio")] | ||
| 129 | P0_18, | 134 | P0_18, |
| 130 | P0_19, | 135 | P0_19, |
| 131 | P0_20, | 136 | P0_20, |
| @@ -164,6 +169,9 @@ embassy_hal_common::peripherals! { | |||
| 164 | 169 | ||
| 165 | // PDM | 170 | // PDM |
| 166 | PDM, | 171 | PDM, |
| 172 | |||
| 173 | // I2S | ||
| 174 | I2S, | ||
| 167 | } | 175 | } |
| 168 | 176 | ||
| 169 | #[cfg(feature = "nightly")] | 177 | #[cfg(feature = "nightly")] |
| @@ -177,9 +185,16 @@ impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | |||
| 177 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); | 185 | impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); |
| 178 | impl_spim!(SPI3, SPIM3, SPIM3); | 186 | impl_spim!(SPI3, SPIM3, SPIM3); |
| 179 | 187 | ||
| 188 | impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 189 | impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 190 | impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); | ||
| 191 | |||
| 180 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 192 | impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); |
| 181 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 193 | impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); |
| 182 | 194 | ||
| 195 | impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | ||
| 196 | impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | ||
| 197 | |||
| 183 | impl_pwm!(PWM0, PWM0, PWM0); | 198 | impl_pwm!(PWM0, PWM0, PWM0); |
| 184 | impl_pwm!(PWM1, PWM1, PWM1); | 199 | impl_pwm!(PWM1, PWM1, PWM1); |
| 185 | impl_pwm!(PWM2, PWM2, PWM2); | 200 | impl_pwm!(PWM2, PWM2, PWM2); |
| @@ -193,6 +208,12 @@ impl_timer!(TIMER4, TIMER4, TIMER4, extended); | |||
| 193 | 208 | ||
| 194 | impl_qspi!(QSPI, QSPI, QSPI); | 209 | impl_qspi!(QSPI, QSPI, QSPI); |
| 195 | 210 | ||
| 211 | impl_pdm!(PDM, PDM, PDM); | ||
| 212 | |||
| 213 | impl_qdec!(QDEC, QDEC, QDEC); | ||
| 214 | |||
| 215 | impl_rng!(RNG, RNG, RNG); | ||
| 216 | |||
| 196 | impl_pin!(P0_00, 0, 0); | 217 | impl_pin!(P0_00, 0, 0); |
| 197 | impl_pin!(P0_01, 0, 1); | 218 | impl_pin!(P0_01, 0, 1); |
| 198 | impl_pin!(P0_02, 0, 2); | 219 | impl_pin!(P0_02, 0, 2); |
| @@ -202,7 +223,9 @@ impl_pin!(P0_05, 0, 5); | |||
| 202 | impl_pin!(P0_06, 0, 6); | 223 | impl_pin!(P0_06, 0, 6); |
| 203 | impl_pin!(P0_07, 0, 7); | 224 | impl_pin!(P0_07, 0, 7); |
| 204 | impl_pin!(P0_08, 0, 8); | 225 | impl_pin!(P0_08, 0, 8); |
| 226 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 205 | impl_pin!(P0_09, 0, 9); | 227 | impl_pin!(P0_09, 0, 9); |
| 228 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 206 | impl_pin!(P0_10, 0, 10); | 229 | impl_pin!(P0_10, 0, 10); |
| 207 | impl_pin!(P0_11, 0, 11); | 230 | impl_pin!(P0_11, 0, 11); |
| 208 | impl_pin!(P0_12, 0, 12); | 231 | impl_pin!(P0_12, 0, 12); |
| @@ -211,6 +234,7 @@ impl_pin!(P0_14, 0, 14); | |||
| 211 | impl_pin!(P0_15, 0, 15); | 234 | impl_pin!(P0_15, 0, 15); |
| 212 | impl_pin!(P0_16, 0, 16); | 235 | impl_pin!(P0_16, 0, 16); |
| 213 | impl_pin!(P0_17, 0, 17); | 236 | impl_pin!(P0_17, 0, 17); |
| 237 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 214 | impl_pin!(P0_18, 0, 18); | 238 | impl_pin!(P0_18, 0, 18); |
| 215 | impl_pin!(P0_19, 0, 19); | 239 | impl_pin!(P0_19, 0, 19); |
| 216 | impl_pin!(P0_20, 0, 20); | 240 | impl_pin!(P0_20, 0, 20); |
| @@ -276,61 +300,59 @@ impl_ppi_channel!(PPI_CH29, 29 => static); | |||
| 276 | impl_ppi_channel!(PPI_CH30, 30 => static); | 300 | impl_ppi_channel!(PPI_CH30, 30 => static); |
| 277 | impl_ppi_channel!(PPI_CH31, 31 => static); | 301 | impl_ppi_channel!(PPI_CH31, 31 => static); |
| 278 | 302 | ||
| 279 | impl_saadc_input!(P0_02, ANALOGINPUT0); | 303 | impl_saadc_input!(P0_02, ANALOG_INPUT0); |
| 280 | impl_saadc_input!(P0_03, ANALOGINPUT1); | 304 | impl_saadc_input!(P0_03, ANALOG_INPUT1); |
| 281 | impl_saadc_input!(P0_04, ANALOGINPUT2); | 305 | impl_saadc_input!(P0_04, ANALOG_INPUT2); |
| 282 | impl_saadc_input!(P0_05, ANALOGINPUT3); | 306 | impl_saadc_input!(P0_05, ANALOG_INPUT3); |
| 283 | impl_saadc_input!(P0_28, ANALOGINPUT4); | 307 | impl_saadc_input!(P0_28, ANALOG_INPUT4); |
| 284 | impl_saadc_input!(P0_29, ANALOGINPUT5); | 308 | impl_saadc_input!(P0_29, ANALOG_INPUT5); |
| 285 | impl_saadc_input!(P0_30, ANALOGINPUT6); | 309 | impl_saadc_input!(P0_30, ANALOG_INPUT6); |
| 286 | impl_saadc_input!(P0_31, ANALOGINPUT7); | 310 | impl_saadc_input!(P0_31, ANALOG_INPUT7); |
| 287 | 311 | ||
| 288 | pub mod irqs { | 312 | impl_i2s!(I2S, I2S, I2S); |
| 289 | use embassy_cortex_m::interrupt::_export::declare; | 313 | |
| 290 | 314 | embassy_hal_common::interrupt_mod!( | |
| 291 | use crate::pac::Interrupt as InterruptEnum; | 315 | POWER_CLOCK, |
| 292 | 316 | RADIO, | |
| 293 | declare!(POWER_CLOCK); | 317 | UARTE0_UART0, |
| 294 | declare!(RADIO); | 318 | SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, |
| 295 | declare!(UARTE0_UART0); | 319 | SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, |
| 296 | declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); | 320 | NFCT, |
| 297 | declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); | 321 | GPIOTE, |
| 298 | declare!(NFCT); | 322 | SAADC, |
| 299 | declare!(GPIOTE); | 323 | TIMER0, |
| 300 | declare!(SAADC); | 324 | TIMER1, |
| 301 | declare!(TIMER0); | 325 | TIMER2, |
| 302 | declare!(TIMER1); | 326 | RTC0, |
| 303 | declare!(TIMER2); | 327 | TEMP, |
| 304 | declare!(RTC0); | 328 | RNG, |
| 305 | declare!(TEMP); | 329 | ECB, |
| 306 | declare!(RNG); | 330 | CCM_AAR, |
| 307 | declare!(ECB); | 331 | WDT, |
| 308 | declare!(CCM_AAR); | 332 | RTC1, |
| 309 | declare!(WDT); | 333 | QDEC, |
| 310 | declare!(RTC1); | 334 | COMP_LPCOMP, |
| 311 | declare!(QDEC); | 335 | SWI0_EGU0, |
| 312 | declare!(COMP_LPCOMP); | 336 | SWI1_EGU1, |
| 313 | declare!(SWI0_EGU0); | 337 | SWI2_EGU2, |
| 314 | declare!(SWI1_EGU1); | 338 | SWI3_EGU3, |
| 315 | declare!(SWI2_EGU2); | 339 | SWI4_EGU4, |
| 316 | declare!(SWI3_EGU3); | 340 | SWI5_EGU5, |
| 317 | declare!(SWI4_EGU4); | 341 | TIMER3, |
| 318 | declare!(SWI5_EGU5); | 342 | TIMER4, |
| 319 | declare!(TIMER3); | 343 | PWM0, |
| 320 | declare!(TIMER4); | 344 | PDM, |
| 321 | declare!(PWM0); | 345 | MWU, |
| 322 | declare!(PDM); | 346 | PWM1, |
| 323 | declare!(MWU); | 347 | PWM2, |
| 324 | declare!(PWM1); | 348 | SPIM2_SPIS2_SPI2, |
| 325 | declare!(PWM2); | 349 | RTC2, |
| 326 | declare!(SPIM2_SPIS2_SPI2); | 350 | FPU, |
| 327 | declare!(RTC2); | 351 | USBD, |
| 328 | declare!(I2S); | 352 | UARTE1, |
| 329 | declare!(FPU); | 353 | QSPI, |
| 330 | declare!(USBD); | 354 | CRYPTOCELL, |
| 331 | declare!(UARTE1); | 355 | PWM3, |
| 332 | declare!(QSPI); | 356 | SPIM3, |
| 333 | declare!(CRYPTOCELL); | 357 | I2S, |
| 334 | declare!(PWM3); | 358 | ); |
| 335 | declare!(SPIM3); | ||
| 336 | } | ||
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index edf800ef3..410ae921c 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | /// Peripheral Access Crate | ||
| 1 | #[allow(unused_imports)] | 2 | #[allow(unused_imports)] |
| 2 | #[rustfmt::skip] | 3 | #[rustfmt::skip] |
| 3 | pub mod pac { | 4 | pub mod pac { |
| 4 | // The nRF5340 has a secure and non-secure (NS) mode. | 5 | // The nRF5340 has a secure and non-secure (NS) mode. |
| 5 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 6 | 7 | ||
| 8 | pub use nrf5340_app_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 7 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 8 | pub use nrf5340_app_pac::{ | 11 | pub use nrf5340_app_pac::{ |
| 9 | interrupt, | 12 | interrupt, |
| @@ -33,10 +36,10 @@ pub mod pac { | |||
| 33 | nvmc_ns as nvmc, | 36 | nvmc_ns as nvmc, |
| 34 | oscillators_ns as oscillators, | 37 | oscillators_ns as oscillators, |
| 35 | p0_ns as p0, | 38 | p0_ns as p0, |
| 36 | pdm0_ns as pdm0, | 39 | pdm0_ns as pdm, |
| 37 | power_ns as power, | 40 | power_ns as power, |
| 38 | pwm0_ns as pwm0, | 41 | pwm0_ns as pwm0, |
| 39 | qdec0_ns as qdec0, | 42 | qdec0_ns as qdec, |
| 40 | qspi_ns as qspi, | 43 | qspi_ns as qspi, |
| 41 | regulators_ns as regulators, | 44 | regulators_ns as regulators, |
| 42 | reset_ns as reset, | 45 | reset_ns as reset, |
| @@ -213,6 +216,8 @@ pub mod pac { | |||
| 213 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | 216 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; |
| 214 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; | 217 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; |
| 215 | 218 | ||
| 219 | pub const FLASH_SIZE: usize = 1024 * 1024; | ||
| 220 | |||
| 216 | embassy_hal_common::peripherals! { | 221 | embassy_hal_common::peripherals! { |
| 217 | // USB | 222 | // USB |
| 218 | USBD, | 223 | USBD, |
| @@ -224,11 +229,14 @@ embassy_hal_common::peripherals! { | |||
| 224 | // WDT | 229 | // WDT |
| 225 | WDT, | 230 | WDT, |
| 226 | 231 | ||
| 232 | // NVMC | ||
| 233 | NVMC, | ||
| 234 | |||
| 227 | // UARTE, TWI & SPI | 235 | // UARTE, TWI & SPI |
| 228 | UARTETWISPI0, | 236 | SERIAL0, |
| 229 | UARTETWISPI1, | 237 | SERIAL1, |
| 230 | UARTETWISPI2, | 238 | SERIAL2, |
| 231 | UARTETWISPI3, | 239 | SERIAL3, |
| 232 | 240 | ||
| 233 | // SAADC | 241 | // SAADC |
| 234 | SAADC, | 242 | SAADC, |
| @@ -244,6 +252,16 @@ embassy_hal_common::peripherals! { | |||
| 244 | TIMER1, | 252 | TIMER1, |
| 245 | TIMER2, | 253 | TIMER2, |
| 246 | 254 | ||
| 255 | // QSPI | ||
| 256 | QSPI, | ||
| 257 | |||
| 258 | // PDM | ||
| 259 | PDM0, | ||
| 260 | |||
| 261 | // QDEC | ||
| 262 | QDEC0, | ||
| 263 | QDEC1, | ||
| 264 | |||
| 247 | // GPIOTE | 265 | // GPIOTE |
| 248 | GPIOTE_CH0, | 266 | GPIOTE_CH0, |
| 249 | GPIOTE_CH1, | 267 | GPIOTE_CH1, |
| @@ -298,7 +316,9 @@ embassy_hal_common::peripherals! { | |||
| 298 | // GPIO port 0 | 316 | // GPIO port 0 |
| 299 | P0_00, | 317 | P0_00, |
| 300 | P0_01, | 318 | P0_01, |
| 319 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 301 | P0_02, | 320 | P0_02, |
| 321 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 302 | P0_03, | 322 | P0_03, |
| 303 | P0_04, | 323 | P0_04, |
| 304 | P0_05, | 324 | P0_05, |
| @@ -351,20 +371,30 @@ embassy_hal_common::peripherals! { | |||
| 351 | #[cfg(feature = "nightly")] | 371 | #[cfg(feature = "nightly")] |
| 352 | impl_usb!(USBD, USBD, USBD); | 372 | impl_usb!(USBD, USBD, USBD); |
| 353 | 373 | ||
| 354 | impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); | 374 | impl_uarte!(SERIAL0, UARTE0, SERIAL0); |
| 355 | impl_uarte!(UARTETWISPI1, UARTE1, SERIAL1); | 375 | impl_uarte!(SERIAL1, UARTE1, SERIAL1); |
| 356 | impl_uarte!(UARTETWISPI2, UARTE2, SERIAL2); | 376 | impl_uarte!(SERIAL2, UARTE2, SERIAL2); |
| 357 | impl_uarte!(UARTETWISPI3, UARTE3, SERIAL3); | 377 | impl_uarte!(SERIAL3, UARTE3, SERIAL3); |
| 358 | 378 | ||
| 359 | impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); | 379 | impl_spim!(SERIAL0, SPIM0, SERIAL0); |
| 360 | impl_spim!(UARTETWISPI1, SPIM1, SERIAL1); | 380 | impl_spim!(SERIAL1, SPIM1, SERIAL1); |
| 361 | impl_spim!(UARTETWISPI2, SPIM2, SERIAL2); | 381 | impl_spim!(SERIAL2, SPIM2, SERIAL2); |
| 362 | impl_spim!(UARTETWISPI3, SPIM3, SERIAL3); | 382 | impl_spim!(SERIAL3, SPIM3, SERIAL3); |
| 363 | 383 | ||
| 364 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); | 384 | impl_spis!(SERIAL0, SPIS0, SERIAL0); |
| 365 | impl_twim!(UARTETWISPI1, TWIM1, SERIAL1); | 385 | impl_spis!(SERIAL1, SPIS1, SERIAL1); |
| 366 | impl_twim!(UARTETWISPI2, TWIM2, SERIAL2); | 386 | impl_spis!(SERIAL2, SPIS2, SERIAL2); |
| 367 | impl_twim!(UARTETWISPI3, TWIM3, SERIAL3); | 387 | impl_spis!(SERIAL3, SPIS3, SERIAL3); |
| 388 | |||
| 389 | impl_twim!(SERIAL0, TWIM0, SERIAL0); | ||
| 390 | impl_twim!(SERIAL1, TWIM1, SERIAL1); | ||
| 391 | impl_twim!(SERIAL2, TWIM2, SERIAL2); | ||
| 392 | impl_twim!(SERIAL3, TWIM3, SERIAL3); | ||
| 393 | |||
| 394 | impl_twis!(SERIAL0, TWIS0, SERIAL0); | ||
| 395 | impl_twis!(SERIAL1, TWIS1, SERIAL1); | ||
| 396 | impl_twis!(SERIAL2, TWIS2, SERIAL2); | ||
| 397 | impl_twis!(SERIAL3, TWIS3, SERIAL3); | ||
| 368 | 398 | ||
| 369 | impl_pwm!(PWM0, PWM0, PWM0); | 399 | impl_pwm!(PWM0, PWM0, PWM0); |
| 370 | impl_pwm!(PWM1, PWM1, PWM1); | 400 | impl_pwm!(PWM1, PWM1, PWM1); |
| @@ -375,9 +405,18 @@ impl_timer!(TIMER0, TIMER0, TIMER0); | |||
| 375 | impl_timer!(TIMER1, TIMER1, TIMER1); | 405 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 376 | impl_timer!(TIMER2, TIMER2, TIMER2); | 406 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 377 | 407 | ||
| 408 | impl_qspi!(QSPI, QSPI, QSPI); | ||
| 409 | |||
| 410 | impl_pdm!(PDM0, PDM0, PDM0); | ||
| 411 | |||
| 412 | impl_qdec!(QDEC0, QDEC0, QDEC0); | ||
| 413 | impl_qdec!(QDEC1, QDEC1, QDEC1); | ||
| 414 | |||
| 378 | impl_pin!(P0_00, 0, 0); | 415 | impl_pin!(P0_00, 0, 0); |
| 379 | impl_pin!(P0_01, 0, 1); | 416 | impl_pin!(P0_01, 0, 1); |
| 417 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 380 | impl_pin!(P0_02, 0, 2); | 418 | impl_pin!(P0_02, 0, 2); |
| 419 | #[cfg(feature = "nfc-pins-as-gpio")] | ||
| 381 | impl_pin!(P0_03, 0, 3); | 420 | impl_pin!(P0_03, 0, 3); |
| 382 | impl_pin!(P0_04, 0, 4); | 421 | impl_pin!(P0_04, 0, 4); |
| 383 | impl_pin!(P0_05, 0, 5); | 422 | impl_pin!(P0_05, 0, 5); |
| @@ -458,59 +497,55 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); | |||
| 458 | impl_ppi_channel!(PPI_CH30, 30 => configurable); | 497 | impl_ppi_channel!(PPI_CH30, 30 => configurable); |
| 459 | impl_ppi_channel!(PPI_CH31, 31 => configurable); | 498 | impl_ppi_channel!(PPI_CH31, 31 => configurable); |
| 460 | 499 | ||
| 461 | impl_saadc_input!(P0_13, ANALOGINPUT0); | 500 | impl_saadc_input!(P0_13, ANALOG_INPUT0); |
| 462 | impl_saadc_input!(P0_14, ANALOGINPUT1); | 501 | impl_saadc_input!(P0_14, ANALOG_INPUT1); |
| 463 | impl_saadc_input!(P0_15, ANALOGINPUT2); | 502 | impl_saadc_input!(P0_15, ANALOG_INPUT2); |
| 464 | impl_saadc_input!(P0_16, ANALOGINPUT3); | 503 | impl_saadc_input!(P0_16, ANALOG_INPUT3); |
| 465 | impl_saadc_input!(P0_17, ANALOGINPUT4); | 504 | impl_saadc_input!(P0_17, ANALOG_INPUT4); |
| 466 | impl_saadc_input!(P0_18, ANALOGINPUT5); | 505 | impl_saadc_input!(P0_18, ANALOG_INPUT5); |
| 467 | impl_saadc_input!(P0_19, ANALOGINPUT6); | 506 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 468 | impl_saadc_input!(P0_20, ANALOGINPUT7); | 507 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 469 | 508 | ||
| 470 | pub mod irqs { | 509 | embassy_hal_common::interrupt_mod!( |
| 471 | use embassy_cortex_m::interrupt::_export::declare; | 510 | FPU, |
| 472 | 511 | CACHE, | |
| 473 | use crate::pac::Interrupt as InterruptEnum; | 512 | SPU, |
| 474 | 513 | CLOCK_POWER, | |
| 475 | declare!(FPU); | 514 | SERIAL0, |
| 476 | declare!(CACHE); | 515 | SERIAL1, |
| 477 | declare!(SPU); | 516 | SPIM4, |
| 478 | declare!(CLOCK_POWER); | 517 | SERIAL2, |
| 479 | declare!(SERIAL0); | 518 | SERIAL3, |
| 480 | declare!(SERIAL1); | 519 | GPIOTE0, |
| 481 | declare!(SPIM4); | 520 | SAADC, |
| 482 | declare!(SERIAL2); | 521 | TIMER0, |
| 483 | declare!(SERIAL3); | 522 | TIMER1, |
| 484 | declare!(GPIOTE0); | 523 | TIMER2, |
| 485 | declare!(SAADC); | 524 | RTC0, |
| 486 | declare!(TIMER0); | 525 | RTC1, |
| 487 | declare!(TIMER1); | 526 | WDT0, |
| 488 | declare!(TIMER2); | 527 | WDT1, |
| 489 | declare!(RTC0); | 528 | COMP_LPCOMP, |
| 490 | declare!(RTC1); | 529 | EGU0, |
| 491 | declare!(WDT0); | 530 | EGU1, |
| 492 | declare!(WDT1); | 531 | EGU2, |
| 493 | declare!(COMP_LPCOMP); | 532 | EGU3, |
| 494 | declare!(EGU0); | 533 | EGU4, |
| 495 | declare!(EGU1); | 534 | EGU5, |
| 496 | declare!(EGU2); | 535 | PWM0, |
| 497 | declare!(EGU3); | 536 | PWM1, |
| 498 | declare!(EGU4); | 537 | PWM2, |
| 499 | declare!(EGU5); | 538 | PWM3, |
| 500 | declare!(PWM0); | 539 | PDM0, |
| 501 | declare!(PWM1); | 540 | I2S0, |
| 502 | declare!(PWM2); | 541 | IPC, |
| 503 | declare!(PWM3); | 542 | QSPI, |
| 504 | declare!(PDM0); | 543 | NFCT, |
| 505 | declare!(I2S0); | 544 | GPIOTE1, |
| 506 | declare!(IPC); | 545 | QDEC0, |
| 507 | declare!(QSPI); | 546 | QDEC1, |
| 508 | declare!(NFCT); | 547 | USBD, |
| 509 | declare!(GPIOTE1); | 548 | USBREGULATOR, |
| 510 | declare!(QDEC0); | 549 | KMU, |
| 511 | declare!(QDEC1); | 550 | CRYPTOCELL, |
| 512 | declare!(USBD); | 551 | ); |
| 513 | declare!(USBREGULATOR); | ||
| 514 | declare!(KMU); | ||
| 515 | declare!(CRYPTOCELL); | ||
| 516 | } | ||
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index ae136e09d..6ac783085 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | /// Peripheral Access Crate | ||
| 1 | #[allow(unused_imports)] | 2 | #[allow(unused_imports)] |
| 2 | #[rustfmt::skip] | 3 | #[rustfmt::skip] |
| 3 | pub mod pac { | 4 | pub mod pac { |
| 4 | // The nRF5340 has a secure and non-secure (NS) mode. | 5 | // The nRF5340 has a secure and non-secure (NS) mode. |
| 5 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 6 | 7 | ||
| 8 | pub use nrf5340_net_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 7 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 8 | pub use nrf5340_net_pac::{ | 11 | pub use nrf5340_net_pac::{ |
| 9 | interrupt, | 12 | interrupt, |
| @@ -104,6 +107,8 @@ pub mod pac { | |||
| 104 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; | 107 | pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; |
| 105 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; | 108 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; |
| 106 | 109 | ||
| 110 | pub const FLASH_SIZE: usize = 256 * 1024; | ||
| 111 | |||
| 107 | embassy_hal_common::peripherals! { | 112 | embassy_hal_common::peripherals! { |
| 108 | // RTC | 113 | // RTC |
| 109 | RTC0, | 114 | RTC0, |
| @@ -112,15 +117,21 @@ embassy_hal_common::peripherals! { | |||
| 112 | // WDT | 117 | // WDT |
| 113 | WDT, | 118 | WDT, |
| 114 | 119 | ||
| 120 | // NVMC | ||
| 121 | NVMC, | ||
| 122 | |||
| 115 | // UARTE, TWI & SPI | 123 | // UARTE, TWI & SPI |
| 116 | UARTETWISPI0, | 124 | SERIAL0, |
| 117 | UARTETWISPI1, | 125 | SERIAL1, |
| 118 | UARTETWISPI2, | 126 | SERIAL2, |
| 119 | UARTETWISPI3, | 127 | SERIAL3, |
| 120 | 128 | ||
| 121 | // SAADC | 129 | // SAADC |
| 122 | SAADC, | 130 | SAADC, |
| 123 | 131 | ||
| 132 | // RNG | ||
| 133 | RNG, | ||
| 134 | |||
| 124 | // PWM | 135 | // PWM |
| 125 | PWM0, | 136 | PWM0, |
| 126 | PWM1, | 137 | PWM1, |
| @@ -236,14 +247,18 @@ embassy_hal_common::peripherals! { | |||
| 236 | P1_15, | 247 | P1_15, |
| 237 | } | 248 | } |
| 238 | 249 | ||
| 239 | impl_uarte!(UARTETWISPI0, UARTE0, SERIAL0); | 250 | impl_uarte!(SERIAL0, UARTE0, SERIAL0); |
| 240 | impl_spim!(UARTETWISPI0, SPIM0, SERIAL0); | 251 | impl_spim!(SERIAL0, SPIM0, SERIAL0); |
| 241 | impl_twim!(UARTETWISPI0, TWIM0, SERIAL0); | 252 | impl_spis!(SERIAL0, SPIS0, SERIAL0); |
| 253 | impl_twim!(SERIAL0, TWIM0, SERIAL0); | ||
| 254 | impl_twis!(SERIAL0, TWIS0, SERIAL0); | ||
| 242 | 255 | ||
| 243 | impl_timer!(TIMER0, TIMER0, TIMER0); | 256 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 244 | impl_timer!(TIMER1, TIMER1, TIMER1); | 257 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 245 | impl_timer!(TIMER2, TIMER2, TIMER2); | 258 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| 246 | 259 | ||
| 260 | impl_rng!(RNG, RNG, RNG); | ||
| 261 | |||
| 247 | impl_pin!(P0_00, 0, 0); | 262 | impl_pin!(P0_00, 0, 0); |
| 248 | impl_pin!(P0_01, 0, 1); | 263 | impl_pin!(P0_01, 0, 1); |
| 249 | impl_pin!(P0_02, 0, 2); | 264 | impl_pin!(P0_02, 0, 2); |
| @@ -327,29 +342,25 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable); | |||
| 327 | impl_ppi_channel!(PPI_CH30, 30 => configurable); | 342 | impl_ppi_channel!(PPI_CH30, 30 => configurable); |
| 328 | impl_ppi_channel!(PPI_CH31, 31 => configurable); | 343 | impl_ppi_channel!(PPI_CH31, 31 => configurable); |
| 329 | 344 | ||
| 330 | pub mod irqs { | 345 | embassy_hal_common::interrupt_mod!( |
| 331 | use embassy_cortex_m::interrupt::_export::declare; | 346 | CLOCK_POWER, |
| 332 | 347 | RADIO, | |
| 333 | use crate::pac::Interrupt as InterruptEnum; | 348 | RNG, |
| 334 | 349 | GPIOTE, | |
| 335 | declare!(CLOCK_POWER); | 350 | WDT, |
| 336 | declare!(RADIO); | 351 | TIMER0, |
| 337 | declare!(RNG); | 352 | ECB, |
| 338 | declare!(GPIOTE); | 353 | AAR_CCM, |
| 339 | declare!(WDT); | 354 | TEMP, |
| 340 | declare!(TIMER0); | 355 | RTC0, |
| 341 | declare!(ECB); | 356 | IPC, |
| 342 | declare!(AAR_CCM); | 357 | SERIAL0, |
| 343 | declare!(TEMP); | 358 | EGU0, |
| 344 | declare!(RTC0); | 359 | RTC1, |
| 345 | declare!(IPC); | 360 | TIMER1, |
| 346 | declare!(SERIAL0); | 361 | TIMER2, |
| 347 | declare!(EGU0); | 362 | SWI0, |
| 348 | declare!(RTC1); | 363 | SWI1, |
| 349 | declare!(TIMER1); | 364 | SWI2, |
| 350 | declare!(TIMER2); | 365 | SWI3, |
| 351 | declare!(SWI0); | 366 | ); |
| 352 | declare!(SWI1); | ||
| 353 | declare!(SWI2); | ||
| 354 | declare!(SWI3); | ||
| 355 | } | ||
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index a4be8564e..67ea032ff 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs | |||
| @@ -1,9 +1,12 @@ | |||
| 1 | /// Peripheral Access Crate | ||
| 1 | #[allow(unused_imports)] | 2 | #[allow(unused_imports)] |
| 2 | #[rustfmt::skip] | 3 | #[rustfmt::skip] |
| 3 | pub mod pac { | 4 | pub mod pac { |
| 4 | // The nRF9160 has a secure and non-secure (NS) mode. | 5 | // The nRF9160 has a secure and non-secure (NS) mode. |
| 5 | // To avoid cfg spam, we remove _ns or _s suffixes here. | 6 | // To avoid cfg spam, we remove _ns or _s suffixes here. |
| 6 | 7 | ||
| 8 | pub use nrf9160_pac::NVIC_PRIO_BITS; | ||
| 9 | |||
| 7 | #[doc(no_inline)] | 10 | #[doc(no_inline)] |
| 8 | pub use nrf9160_pac::{ | 11 | pub use nrf9160_pac::{ |
| 9 | interrupt, | 12 | interrupt, |
| @@ -164,6 +167,8 @@ pub mod pac { | |||
| 164 | pub const EASY_DMA_SIZE: usize = (1 << 13) - 1; | 167 | pub const EASY_DMA_SIZE: usize = (1 << 13) - 1; |
| 165 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; | 168 | pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; |
| 166 | 169 | ||
| 170 | pub const FLASH_SIZE: usize = 1024 * 1024; | ||
| 171 | |||
| 167 | embassy_hal_common::peripherals! { | 172 | embassy_hal_common::peripherals! { |
| 168 | // RTC | 173 | // RTC |
| 169 | RTC0, | 174 | RTC0, |
| @@ -172,11 +177,14 @@ embassy_hal_common::peripherals! { | |||
| 172 | // WDT | 177 | // WDT |
| 173 | WDT, | 178 | WDT, |
| 174 | 179 | ||
| 180 | // NVMC | ||
| 181 | NVMC, | ||
| 182 | |||
| 175 | // UARTE, TWI & SPI | 183 | // UARTE, TWI & SPI |
| 176 | UARTETWISPI0, | 184 | SERIAL0, |
| 177 | UARTETWISPI1, | 185 | SERIAL1, |
| 178 | UARTETWISPI2, | 186 | SERIAL2, |
| 179 | UARTETWISPI3, | 187 | SERIAL3, |
| 180 | 188 | ||
| 181 | // SAADC | 189 | // SAADC |
| 182 | SAADC, | 190 | SAADC, |
| @@ -260,28 +268,43 @@ embassy_hal_common::peripherals! { | |||
| 260 | P0_29, | 268 | P0_29, |
| 261 | P0_30, | 269 | P0_30, |
| 262 | P0_31, | 270 | P0_31, |
| 271 | |||
| 272 | // PDM | ||
| 273 | PDM, | ||
| 263 | } | 274 | } |
| 264 | 275 | ||
| 265 | impl_uarte!(UARTETWISPI0, UARTE0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 276 | impl_uarte!(SERIAL0, UARTE0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); |
| 266 | impl_uarte!(UARTETWISPI1, UARTE1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 277 | impl_uarte!(SERIAL1, UARTE1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); |
| 267 | impl_uarte!(UARTETWISPI2, UARTE2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 278 | impl_uarte!(SERIAL2, UARTE2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); |
| 268 | impl_uarte!(UARTETWISPI3, UARTE3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 279 | impl_uarte!(SERIAL3, UARTE3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); |
| 280 | |||
| 281 | impl_spim!(SERIAL0, SPIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | ||
| 282 | impl_spim!(SERIAL1, SPIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | ||
| 283 | impl_spim!(SERIAL2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | ||
| 284 | impl_spim!(SERIAL3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | ||
| 285 | |||
| 286 | impl_spis!(SERIAL0, SPIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | ||
| 287 | impl_spis!(SERIAL1, SPIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | ||
| 288 | impl_spis!(SERIAL2, SPIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | ||
| 289 | impl_spis!(SERIAL3, SPIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | ||
| 269 | 290 | ||
| 270 | impl_spim!(UARTETWISPI0, SPIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 291 | impl_twim!(SERIAL0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); |
| 271 | impl_spim!(UARTETWISPI1, SPIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 292 | impl_twim!(SERIAL1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); |
| 272 | impl_spim!(UARTETWISPI2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 293 | impl_twim!(SERIAL2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); |
| 273 | impl_spim!(UARTETWISPI3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 294 | impl_twim!(SERIAL3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); |
| 274 | 295 | ||
| 275 | impl_twim!(UARTETWISPI0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 296 | impl_twis!(SERIAL0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); |
| 276 | impl_twim!(UARTETWISPI1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 297 | impl_twis!(SERIAL1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); |
| 277 | impl_twim!(UARTETWISPI2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 298 | impl_twis!(SERIAL2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); |
| 278 | impl_twim!(UARTETWISPI3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 299 | impl_twis!(SERIAL3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); |
| 279 | 300 | ||
| 280 | impl_pwm!(PWM0, PWM0, PWM0); | 301 | impl_pwm!(PWM0, PWM0, PWM0); |
| 281 | impl_pwm!(PWM1, PWM1, PWM1); | 302 | impl_pwm!(PWM1, PWM1, PWM1); |
| 282 | impl_pwm!(PWM2, PWM2, PWM2); | 303 | impl_pwm!(PWM2, PWM2, PWM2); |
| 283 | impl_pwm!(PWM3, PWM3, PWM3); | 304 | impl_pwm!(PWM3, PWM3, PWM3); |
| 284 | 305 | ||
| 306 | impl_pdm!(PDM, PDM, PDM); | ||
| 307 | |||
| 285 | impl_timer!(TIMER0, TIMER0, TIMER0); | 308 | impl_timer!(TIMER0, TIMER0, TIMER0); |
| 286 | impl_timer!(TIMER1, TIMER1, TIMER1); | 309 | impl_timer!(TIMER1, TIMER1, TIMER1); |
| 287 | impl_timer!(TIMER2, TIMER2, TIMER2); | 310 | impl_timer!(TIMER2, TIMER2, TIMER2); |
| @@ -336,49 +359,45 @@ impl_ppi_channel!(PPI_CH13, 13 => configurable); | |||
| 336 | impl_ppi_channel!(PPI_CH14, 14 => configurable); | 359 | impl_ppi_channel!(PPI_CH14, 14 => configurable); |
| 337 | impl_ppi_channel!(PPI_CH15, 15 => configurable); | 360 | impl_ppi_channel!(PPI_CH15, 15 => configurable); |
| 338 | 361 | ||
| 339 | impl_saadc_input!(P0_13, ANALOGINPUT0); | 362 | impl_saadc_input!(P0_13, ANALOG_INPUT0); |
| 340 | impl_saadc_input!(P0_14, ANALOGINPUT1); | 363 | impl_saadc_input!(P0_14, ANALOG_INPUT1); |
| 341 | impl_saadc_input!(P0_15, ANALOGINPUT2); | 364 | impl_saadc_input!(P0_15, ANALOG_INPUT2); |
| 342 | impl_saadc_input!(P0_16, ANALOGINPUT3); | 365 | impl_saadc_input!(P0_16, ANALOG_INPUT3); |
| 343 | impl_saadc_input!(P0_17, ANALOGINPUT4); | 366 | impl_saadc_input!(P0_17, ANALOG_INPUT4); |
| 344 | impl_saadc_input!(P0_18, ANALOGINPUT5); | 367 | impl_saadc_input!(P0_18, ANALOG_INPUT5); |
| 345 | impl_saadc_input!(P0_19, ANALOGINPUT6); | 368 | impl_saadc_input!(P0_19, ANALOG_INPUT6); |
| 346 | impl_saadc_input!(P0_20, ANALOGINPUT7); | 369 | impl_saadc_input!(P0_20, ANALOG_INPUT7); |
| 347 | |||
| 348 | pub mod irqs { | ||
| 349 | use embassy_cortex_m::interrupt::_export::declare; | ||
| 350 | |||
| 351 | use crate::pac::Interrupt as InterruptEnum; | ||
| 352 | 370 | ||
| 353 | declare!(SPU); | 371 | embassy_hal_common::interrupt_mod!( |
| 354 | declare!(CLOCK_POWER); | 372 | SPU, |
| 355 | declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); | 373 | CLOCK_POWER, |
| 356 | declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); | 374 | UARTE0_SPIM0_SPIS0_TWIM0_TWIS0, |
| 357 | declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); | 375 | UARTE1_SPIM1_SPIS1_TWIM1_TWIS1, |
| 358 | declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); | 376 | UARTE2_SPIM2_SPIS2_TWIM2_TWIS2, |
| 359 | declare!(GPIOTE0); | 377 | UARTE3_SPIM3_SPIS3_TWIM3_TWIS3, |
| 360 | declare!(SAADC); | 378 | GPIOTE0, |
| 361 | declare!(TIMER0); | 379 | SAADC, |
| 362 | declare!(TIMER1); | 380 | TIMER0, |
| 363 | declare!(TIMER2); | 381 | TIMER1, |
| 364 | declare!(RTC0); | 382 | TIMER2, |
| 365 | declare!(RTC1); | 383 | RTC0, |
| 366 | declare!(WDT); | 384 | RTC1, |
| 367 | declare!(EGU0); | 385 | WDT, |
| 368 | declare!(EGU1); | 386 | EGU0, |
| 369 | declare!(EGU2); | 387 | EGU1, |
| 370 | declare!(EGU3); | 388 | EGU2, |
| 371 | declare!(EGU4); | 389 | EGU3, |
| 372 | declare!(EGU5); | 390 | EGU4, |
| 373 | declare!(PWM0); | 391 | EGU5, |
| 374 | declare!(PWM1); | 392 | PWM0, |
| 375 | declare!(PWM2); | 393 | PWM1, |
| 376 | declare!(PDM); | 394 | PWM2, |
| 377 | declare!(PWM3); | 395 | PDM, |
| 378 | declare!(I2S); | 396 | PWM3, |
| 379 | declare!(IPC); | 397 | I2S, |
| 380 | declare!(FPU); | 398 | IPC, |
| 381 | declare!(GPIOTE1); | 399 | FPU, |
| 382 | declare!(KMU); | 400 | GPIOTE1, |
| 383 | declare!(CRYPTOCELL); | 401 | KMU, |
| 384 | } | 402 | CRYPTOCELL, |
| 403 | ); | ||
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 924629908..895ab9340 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! General purpose input/output for nRF. | 1 | //! General purpose input/output (GPIO) driver. |
| 2 | #![macro_use] | 2 | #![macro_use] |
| 3 | 3 | ||
| 4 | use core::convert::Infallible; | 4 | use core::convert::Infallible; |
| @@ -70,7 +70,7 @@ impl<'d, T: Pin> Input<'d, T> { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | /// Digital input or output level. | 72 | /// Digital input or output level. |
| 73 | #[derive(Debug, Eq, PartialEq)] | 73 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| 74 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 74 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 75 | pub enum Level { | 75 | pub enum Level { |
| 76 | /// Logical low. | 76 | /// Logical low. |
| @@ -88,9 +88,9 @@ impl From<bool> for Level { | |||
| 88 | } | 88 | } |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | impl Into<bool> for Level { | 91 | impl From<Level> for bool { |
| 92 | fn into(self) -> bool { | 92 | fn from(level: Level) -> bool { |
| 93 | match self { | 93 | match level { |
| 94 | Level::Low => false, | 94 | Level::Low => false, |
| 95 | Level::High => true, | 95 | Level::High => true, |
| 96 | } | 96 | } |
| @@ -574,7 +574,7 @@ mod eh1 { | |||
| 574 | type Error = Infallible; | 574 | type Error = Infallible; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Input<'d, T> { | 577 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Input<'d, T> { |
| 578 | fn is_high(&self) -> Result<bool, Self::Error> { | 578 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 579 | Ok(self.is_high()) | 579 | Ok(self.is_high()) |
| 580 | } | 580 | } |
| @@ -588,7 +588,7 @@ mod eh1 { | |||
| 588 | type Error = Infallible; | 588 | type Error = Infallible; |
| 589 | } | 589 | } |
| 590 | 590 | ||
| 591 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Output<'d, T> { | 591 | impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Output<'d, T> { |
| 592 | fn set_high(&mut self) -> Result<(), Self::Error> { | 592 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 593 | Ok(self.set_high()) | 593 | Ok(self.set_high()) |
| 594 | } | 594 | } |
| @@ -598,7 +598,7 @@ mod eh1 { | |||
| 598 | } | 598 | } |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Output<'d, T> { | 601 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Output<'d, T> { |
| 602 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 602 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 603 | Ok(self.is_set_high()) | 603 | Ok(self.is_set_high()) |
| 604 | } | 604 | } |
| @@ -615,7 +615,7 @@ mod eh1 { | |||
| 615 | /// Implement [`InputPin`] for [`Flex`]; | 615 | /// Implement [`InputPin`] for [`Flex`]; |
| 616 | /// | 616 | /// |
| 617 | /// If the pin is not in input mode the result is unspecified. | 617 | /// If the pin is not in input mode the result is unspecified. |
| 618 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Flex<'d, T> { | 618 | impl<'d, T: Pin> embedded_hal_1::digital::InputPin for Flex<'d, T> { |
| 619 | fn is_high(&self) -> Result<bool, Self::Error> { | 619 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 620 | Ok(self.is_high()) | 620 | Ok(self.is_high()) |
| 621 | } | 621 | } |
| @@ -625,7 +625,7 @@ mod eh1 { | |||
| 625 | } | 625 | } |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Flex<'d, T> { | 628 | impl<'d, T: Pin> embedded_hal_1::digital::OutputPin for Flex<'d, T> { |
| 629 | fn set_high(&mut self) -> Result<(), Self::Error> { | 629 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 630 | Ok(self.set_high()) | 630 | Ok(self.set_high()) |
| 631 | } | 631 | } |
| @@ -635,7 +635,7 @@ mod eh1 { | |||
| 635 | } | 635 | } |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Flex<'d, T> { | 638 | impl<'d, T: Pin> embedded_hal_1::digital::StatefulOutputPin for Flex<'d, T> { |
| 639 | fn is_set_high(&self) -> Result<bool, Self::Error> { | 639 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 640 | Ok(self.is_set_high()) | 640 | Ok(self.is_set_high()) |
| 641 | } | 641 | } |
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index b52035705..6550f2abd 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -1,40 +1,50 @@ | |||
| 1 | //! GPIO task/event (GPIOTE) driver. | ||
| 2 | |||
| 1 | use core::convert::Infallible; | 3 | use core::convert::Infallible; |
| 2 | use core::future::Future; | 4 | use core::future::{poll_fn, Future}; |
| 3 | use core::task::{Context, Poll}; | 5 | use core::task::{Context, Poll}; |
| 4 | 6 | ||
| 5 | use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef}; | 7 | use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; |
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | use futures::future::poll_fn; | ||
| 8 | 9 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 10 | use crate::gpio::sealed::Pin as _; |
| 10 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; | 11 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; |
| 11 | use crate::interrupt::{Interrupt, InterruptExt}; | 12 | use crate::interrupt::InterruptExt; |
| 12 | use crate::ppi::{Event, Task}; | 13 | use crate::ppi::{Event, Task}; |
| 13 | use crate::{interrupt, pac, peripherals}; | 14 | use crate::{interrupt, pac, peripherals}; |
| 14 | 15 | ||
| 15 | pub const CHANNEL_COUNT: usize = 8; | 16 | /// Amount of GPIOTE channels in the chip. |
| 17 | const CHANNEL_COUNT: usize = 8; | ||
| 16 | 18 | ||
| 17 | #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] | 19 | #[cfg(any(feature = "nrf52833", feature = "nrf52840"))] |
| 18 | pub const PIN_COUNT: usize = 48; | 20 | const PIN_COUNT: usize = 48; |
| 19 | #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] | 21 | #[cfg(not(any(feature = "nrf52833", feature = "nrf52840")))] |
| 20 | pub const PIN_COUNT: usize = 32; | 22 | const PIN_COUNT: usize = 32; |
| 21 | 23 | ||
| 22 | #[allow(clippy::declare_interior_mutable_const)] | 24 | #[allow(clippy::declare_interior_mutable_const)] |
| 23 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 25 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 24 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; | 26 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; |
| 25 | static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT]; | 27 | static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT]; |
| 26 | 28 | ||
| 29 | /// Polarity for listening to events for GPIOTE input channels. | ||
| 27 | pub enum InputChannelPolarity { | 30 | pub enum InputChannelPolarity { |
| 31 | /// Don't listen for any pin changes. | ||
| 28 | None, | 32 | None, |
| 33 | /// Listen for high to low changes. | ||
| 29 | HiToLo, | 34 | HiToLo, |
| 35 | /// Listen for low to high changes. | ||
| 30 | LoToHi, | 36 | LoToHi, |
| 37 | /// Listen for any change, either low to high or high to low. | ||
| 31 | Toggle, | 38 | Toggle, |
| 32 | } | 39 | } |
| 33 | 40 | ||
| 34 | /// Polarity of the `task out` operation. | 41 | /// Polarity of the OUT task operation for GPIOTE output channels. |
| 35 | pub enum OutputChannelPolarity { | 42 | pub enum OutputChannelPolarity { |
| 43 | /// Set the pin high. | ||
| 36 | Set, | 44 | Set, |
| 45 | /// Set the pin low. | ||
| 37 | Clear, | 46 | Clear, |
| 47 | /// Toggle the pin. | ||
| 38 | Toggle, | 48 | Toggle, |
| 39 | } | 49 | } |
| 40 | 50 | ||
| @@ -64,42 +74,41 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | |||
| 64 | } | 74 | } |
| 65 | 75 | ||
| 66 | // Enable interrupts | 76 | // Enable interrupts |
| 67 | cfg_if::cfg_if! { | 77 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] |
| 68 | if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { | 78 | let irq = interrupt::GPIOTE0; |
| 69 | let irq = unsafe { interrupt::GPIOTE0::steal() }; | 79 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] |
| 70 | } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { | 80 | let irq = interrupt::GPIOTE1; |
| 71 | let irq = unsafe { interrupt::GPIOTE1::steal() }; | 81 | #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] |
| 72 | } else { | 82 | let irq = interrupt::GPIOTE; |
| 73 | let irq = unsafe { interrupt::GPIOTE::steal() }; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | 83 | ||
| 77 | irq.unpend(); | 84 | irq.unpend(); |
| 78 | irq.set_priority(irq_prio); | 85 | irq.set_priority(irq_prio); |
| 79 | irq.enable(); | 86 | unsafe { irq.enable() }; |
| 80 | 87 | ||
| 81 | let g = regs(); | 88 | let g = regs(); |
| 82 | g.events_port.write(|w| w); | 89 | g.events_port.write(|w| w); |
| 83 | g.intenset.write(|w| w.port().set()); | 90 | g.intenset.write(|w| w.port().set()); |
| 84 | } | 91 | } |
| 85 | 92 | ||
| 86 | cfg_if::cfg_if! { | 93 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] |
| 87 | if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { | 94 | #[cfg(feature = "rt")] |
| 88 | #[interrupt] | 95 | #[interrupt] |
| 89 | fn GPIOTE0() { | 96 | fn GPIOTE0() { |
| 90 | unsafe { handle_gpiote_interrupt() }; | 97 | unsafe { handle_gpiote_interrupt() }; |
| 91 | } | 98 | } |
| 92 | } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { | 99 | |
| 93 | #[interrupt] | 100 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] |
| 94 | fn GPIOTE1() { | 101 | #[cfg(feature = "rt")] |
| 95 | unsafe { handle_gpiote_interrupt() }; | 102 | #[interrupt] |
| 96 | } | 103 | fn GPIOTE1() { |
| 97 | } else { | 104 | unsafe { handle_gpiote_interrupt() }; |
| 98 | #[interrupt] | 105 | } |
| 99 | fn GPIOTE() { | 106 | |
| 100 | unsafe { handle_gpiote_interrupt() }; | 107 | #[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))] |
| 101 | } | 108 | #[cfg(feature = "rt")] |
| 102 | } | 109 | #[interrupt] |
| 110 | fn GPIOTE() { | ||
| 111 | unsafe { handle_gpiote_interrupt() }; | ||
| 103 | } | 112 | } |
| 104 | 113 | ||
| 105 | unsafe fn handle_gpiote_interrupt() { | 114 | unsafe fn handle_gpiote_interrupt() { |
| @@ -149,7 +158,7 @@ impl Iterator for BitIter { | |||
| 149 | 158 | ||
| 150 | /// GPIOTE channel driver in input mode | 159 | /// GPIOTE channel driver in input mode |
| 151 | pub struct InputChannel<'d, C: Channel, T: GpioPin> { | 160 | pub struct InputChannel<'d, C: Channel, T: GpioPin> { |
| 152 | ch: C, | 161 | ch: PeripheralRef<'d, C>, |
| 153 | pin: Input<'d, T>, | 162 | pin: Input<'d, T>, |
| 154 | } | 163 | } |
| 155 | 164 | ||
| @@ -163,7 +172,10 @@ impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { | |||
| 163 | } | 172 | } |
| 164 | 173 | ||
| 165 | impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | 174 | impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { |
| 166 | pub fn new(ch: C, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { | 175 | /// Create a new GPIOTE input channel driver. |
| 176 | pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Input<'d, T>, polarity: InputChannelPolarity) -> Self { | ||
| 177 | into_ref!(ch); | ||
| 178 | |||
| 167 | let g = regs(); | 179 | let g = regs(); |
| 168 | let num = ch.number(); | 180 | let num = ch.number(); |
| 169 | 181 | ||
| @@ -187,6 +199,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | |||
| 187 | InputChannel { ch, pin } | 199 | InputChannel { ch, pin } |
| 188 | } | 200 | } |
| 189 | 201 | ||
| 202 | /// Asynchronously wait for an event in this channel. | ||
| 190 | pub async fn wait(&self) { | 203 | pub async fn wait(&self) { |
| 191 | let g = regs(); | 204 | let g = regs(); |
| 192 | let num = self.ch.number(); | 205 | let num = self.ch.number(); |
| @@ -208,7 +221,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | |||
| 208 | } | 221 | } |
| 209 | 222 | ||
| 210 | /// Returns the IN event, for use with PPI. | 223 | /// Returns the IN event, for use with PPI. |
| 211 | pub fn event_in(&self) -> Event { | 224 | pub fn event_in(&self) -> Event<'d> { |
| 212 | let g = regs(); | 225 | let g = regs(); |
| 213 | Event::from_reg(&g.events_in[self.ch.number()]) | 226 | Event::from_reg(&g.events_in[self.ch.number()]) |
| 214 | } | 227 | } |
| @@ -216,7 +229,7 @@ impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { | |||
| 216 | 229 | ||
| 217 | /// GPIOTE channel driver in output mode | 230 | /// GPIOTE channel driver in output mode |
| 218 | pub struct OutputChannel<'d, C: Channel, T: GpioPin> { | 231 | pub struct OutputChannel<'d, C: Channel, T: GpioPin> { |
| 219 | ch: C, | 232 | ch: PeripheralRef<'d, C>, |
| 220 | _pin: Output<'d, T>, | 233 | _pin: Output<'d, T>, |
| 221 | } | 234 | } |
| 222 | 235 | ||
| @@ -230,7 +243,9 @@ impl<'d, C: Channel, T: GpioPin> Drop for OutputChannel<'d, C, T> { | |||
| 230 | } | 243 | } |
| 231 | 244 | ||
| 232 | impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | 245 | impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { |
| 233 | pub fn new(ch: C, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { | 246 | /// Create a new GPIOTE output channel driver. |
| 247 | pub fn new(ch: impl Peripheral<P = C> + 'd, pin: Output<'d, T>, polarity: OutputChannelPolarity) -> Self { | ||
| 248 | into_ref!(ch); | ||
| 234 | let g = regs(); | 249 | let g = regs(); |
| 235 | let num = ch.number(); | 250 | let num = ch.number(); |
| 236 | 251 | ||
| @@ -256,20 +271,20 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | |||
| 256 | OutputChannel { ch, _pin: pin } | 271 | OutputChannel { ch, _pin: pin } |
| 257 | } | 272 | } |
| 258 | 273 | ||
| 259 | /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). | 274 | /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). |
| 260 | pub fn out(&self) { | 275 | pub fn out(&self) { |
| 261 | let g = regs(); | 276 | let g = regs(); |
| 262 | g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); | 277 | g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); |
| 263 | } | 278 | } |
| 264 | 279 | ||
| 265 | /// Triggers `task set` (set associated pin high). | 280 | /// Triggers the SET task (set associated pin high). |
| 266 | #[cfg(not(feature = "nrf51"))] | 281 | #[cfg(not(feature = "nrf51"))] |
| 267 | pub fn set(&self) { | 282 | pub fn set(&self) { |
| 268 | let g = regs(); | 283 | let g = regs(); |
| 269 | g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); | 284 | g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); |
| 270 | } | 285 | } |
| 271 | 286 | ||
| 272 | /// Triggers `task clear` (set associated pin low). | 287 | /// Triggers the CLEAR task (set associated pin low). |
| 273 | #[cfg(not(feature = "nrf51"))] | 288 | #[cfg(not(feature = "nrf51"))] |
| 274 | pub fn clear(&self) { | 289 | pub fn clear(&self) { |
| 275 | let g = regs(); | 290 | let g = regs(); |
| @@ -277,21 +292,21 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | |||
| 277 | } | 292 | } |
| 278 | 293 | ||
| 279 | /// Returns the OUT task, for use with PPI. | 294 | /// Returns the OUT task, for use with PPI. |
| 280 | pub fn task_out(&self) -> Task { | 295 | pub fn task_out(&self) -> Task<'d> { |
| 281 | let g = regs(); | 296 | let g = regs(); |
| 282 | Task::from_reg(&g.tasks_out[self.ch.number()]) | 297 | Task::from_reg(&g.tasks_out[self.ch.number()]) |
| 283 | } | 298 | } |
| 284 | 299 | ||
| 285 | /// Returns the CLR task, for use with PPI. | 300 | /// Returns the CLR task, for use with PPI. |
| 286 | #[cfg(not(feature = "nrf51"))] | 301 | #[cfg(not(feature = "nrf51"))] |
| 287 | pub fn task_clr(&self) -> Task { | 302 | pub fn task_clr(&self) -> Task<'d> { |
| 288 | let g = regs(); | 303 | let g = regs(); |
| 289 | Task::from_reg(&g.tasks_clr[self.ch.number()]) | 304 | Task::from_reg(&g.tasks_clr[self.ch.number()]) |
| 290 | } | 305 | } |
| 291 | 306 | ||
| 292 | /// Returns the SET task, for use with PPI. | 307 | /// Returns the SET task, for use with PPI. |
| 293 | #[cfg(not(feature = "nrf51"))] | 308 | #[cfg(not(feature = "nrf51"))] |
| 294 | pub fn task_set(&self) -> Task { | 309 | pub fn task_set(&self) -> Task<'d> { |
| 295 | let g = regs(); | 310 | let g = regs(); |
| 296 | Task::from_reg(&g.tasks_set[self.ch.number()]) | 311 | Task::from_reg(&g.tasks_set[self.ch.number()]) |
| 297 | } | 312 | } |
| @@ -299,6 +314,7 @@ impl<'d, C: Channel, T: GpioPin> OutputChannel<'d, C, T> { | |||
| 299 | 314 | ||
| 300 | // ======================= | 315 | // ======================= |
| 301 | 316 | ||
| 317 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 302 | pub(crate) struct PortInputFuture<'a> { | 318 | pub(crate) struct PortInputFuture<'a> { |
| 303 | pin: PeripheralRef<'a, AnyPin>, | 319 | pin: PeripheralRef<'a, AnyPin>, |
| 304 | } | 320 | } |
| @@ -334,48 +350,58 @@ impl<'a> Future for PortInputFuture<'a> { | |||
| 334 | } | 350 | } |
| 335 | 351 | ||
| 336 | impl<'d, T: GpioPin> Input<'d, T> { | 352 | impl<'d, T: GpioPin> Input<'d, T> { |
| 353 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 337 | pub async fn wait_for_high(&mut self) { | 354 | pub async fn wait_for_high(&mut self) { |
| 338 | self.pin.wait_for_high().await | 355 | self.pin.wait_for_high().await |
| 339 | } | 356 | } |
| 340 | 357 | ||
| 358 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 341 | pub async fn wait_for_low(&mut self) { | 359 | pub async fn wait_for_low(&mut self) { |
| 342 | self.pin.wait_for_low().await | 360 | self.pin.wait_for_low().await |
| 343 | } | 361 | } |
| 344 | 362 | ||
| 363 | /// Wait for the pin to undergo a transition from low to high. | ||
| 345 | pub async fn wait_for_rising_edge(&mut self) { | 364 | pub async fn wait_for_rising_edge(&mut self) { |
| 346 | self.pin.wait_for_rising_edge().await | 365 | self.pin.wait_for_rising_edge().await |
| 347 | } | 366 | } |
| 348 | 367 | ||
| 368 | /// Wait for the pin to undergo a transition from high to low. | ||
| 349 | pub async fn wait_for_falling_edge(&mut self) { | 369 | pub async fn wait_for_falling_edge(&mut self) { |
| 350 | self.pin.wait_for_falling_edge().await | 370 | self.pin.wait_for_falling_edge().await |
| 351 | } | 371 | } |
| 352 | 372 | ||
| 373 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 353 | pub async fn wait_for_any_edge(&mut self) { | 374 | pub async fn wait_for_any_edge(&mut self) { |
| 354 | self.pin.wait_for_any_edge().await | 375 | self.pin.wait_for_any_edge().await |
| 355 | } | 376 | } |
| 356 | } | 377 | } |
| 357 | 378 | ||
| 358 | impl<'d, T: GpioPin> Flex<'d, T> { | 379 | impl<'d, T: GpioPin> Flex<'d, T> { |
| 380 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 359 | pub async fn wait_for_high(&mut self) { | 381 | pub async fn wait_for_high(&mut self) { |
| 360 | self.pin.conf().modify(|_, w| w.sense().high()); | 382 | self.pin.conf().modify(|_, w| w.sense().high()); |
| 361 | PortInputFuture::new(&mut self.pin).await | 383 | PortInputFuture::new(&mut self.pin).await |
| 362 | } | 384 | } |
| 363 | 385 | ||
| 386 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 364 | pub async fn wait_for_low(&mut self) { | 387 | pub async fn wait_for_low(&mut self) { |
| 365 | self.pin.conf().modify(|_, w| w.sense().low()); | 388 | self.pin.conf().modify(|_, w| w.sense().low()); |
| 366 | PortInputFuture::new(&mut self.pin).await | 389 | PortInputFuture::new(&mut self.pin).await |
| 367 | } | 390 | } |
| 368 | 391 | ||
| 392 | /// Wait for the pin to undergo a transition from low to high. | ||
| 369 | pub async fn wait_for_rising_edge(&mut self) { | 393 | pub async fn wait_for_rising_edge(&mut self) { |
| 370 | self.wait_for_low().await; | 394 | self.wait_for_low().await; |
| 371 | self.wait_for_high().await; | 395 | self.wait_for_high().await; |
| 372 | } | 396 | } |
| 373 | 397 | ||
| 398 | /// Wait for the pin to undergo a transition from high to low. | ||
| 374 | pub async fn wait_for_falling_edge(&mut self) { | 399 | pub async fn wait_for_falling_edge(&mut self) { |
| 375 | self.wait_for_high().await; | 400 | self.wait_for_high().await; |
| 376 | self.wait_for_low().await; | 401 | self.wait_for_low().await; |
| 377 | } | 402 | } |
| 378 | 403 | ||
| 404 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 379 | pub async fn wait_for_any_edge(&mut self) { | 405 | pub async fn wait_for_any_edge(&mut self) { |
| 380 | if self.is_high() { | 406 | if self.is_high() { |
| 381 | self.pin.conf().modify(|_, w| w.sense().low()); | 407 | self.pin.conf().modify(|_, w| w.sense().low()); |
| @@ -392,8 +418,17 @@ mod sealed { | |||
| 392 | pub trait Channel {} | 418 | pub trait Channel {} |
| 393 | } | 419 | } |
| 394 | 420 | ||
| 421 | /// GPIOTE channel trait. | ||
| 422 | /// | ||
| 423 | /// Implemented by all GPIOTE channels. | ||
| 395 | pub trait Channel: sealed::Channel + Sized { | 424 | pub trait Channel: sealed::Channel + Sized { |
| 425 | /// Get the channel number. | ||
| 396 | fn number(&self) -> usize; | 426 | fn number(&self) -> usize; |
| 427 | |||
| 428 | /// Convert this channel to a type-erased `AnyChannel`. | ||
| 429 | /// | ||
| 430 | /// This allows using several channels in situations that might require | ||
| 431 | /// them to be the same type, like putting them in an array. | ||
| 397 | fn degrade(self) -> AnyChannel { | 432 | fn degrade(self) -> AnyChannel { |
| 398 | AnyChannel { | 433 | AnyChannel { |
| 399 | number: self.number() as u8, | 434 | number: self.number() as u8, |
| @@ -401,6 +436,12 @@ pub trait Channel: sealed::Channel + Sized { | |||
| 401 | } | 436 | } |
| 402 | } | 437 | } |
| 403 | 438 | ||
| 439 | /// Type-erased channel. | ||
| 440 | /// | ||
| 441 | /// Obtained by calling `Channel::degrade`. | ||
| 442 | /// | ||
| 443 | /// This allows using several channels in situations that might require | ||
| 444 | /// them to be the same type, like putting them in an array. | ||
| 404 | pub struct AnyChannel { | 445 | pub struct AnyChannel { |
| 405 | number: u8, | 446 | number: u8, |
| 406 | } | 447 | } |
| @@ -458,7 +499,7 @@ mod eh1 { | |||
| 458 | type Error = Infallible; | 499 | type Error = Infallible; |
| 459 | } | 500 | } |
| 460 | 501 | ||
| 461 | impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::blocking::InputPin for InputChannel<'d, C, T> { | 502 | impl<'d, C: Channel, T: GpioPin> embedded_hal_1::digital::InputPin for InputChannel<'d, C, T> { |
| 462 | fn is_high(&self) -> Result<bool, Self::Error> { | 503 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 463 | Ok(self.pin.is_high()) | 504 | Ok(self.pin.is_high()) |
| 464 | } | 505 | } |
| @@ -469,72 +510,51 @@ mod eh1 { | |||
| 469 | } | 510 | } |
| 470 | } | 511 | } |
| 471 | 512 | ||
| 472 | cfg_if::cfg_if! { | 513 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] |
| 473 | if #[cfg(all(feature = "unstable-traits", feature = "nightly"))] { | 514 | mod eha { |
| 474 | use futures::FutureExt; | 515 | use super::*; |
| 475 | |||
| 476 | impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { | ||
| 477 | type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 478 | |||
| 479 | fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { | ||
| 480 | self.wait_for_high().map(Ok) | ||
| 481 | } | ||
| 482 | |||
| 483 | type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 484 | |||
| 485 | fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { | ||
| 486 | self.wait_for_low().map(Ok) | ||
| 487 | } | ||
| 488 | |||
| 489 | type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 490 | |||
| 491 | fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { | ||
| 492 | self.wait_for_rising_edge().map(Ok) | ||
| 493 | } | ||
| 494 | |||
| 495 | type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 496 | |||
| 497 | fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { | ||
| 498 | self.wait_for_falling_edge().map(Ok) | ||
| 499 | } | ||
| 500 | |||
| 501 | type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 502 | 516 | ||
| 503 | fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { | 517 | impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Input<'d, T> { |
| 504 | self.wait_for_any_edge().map(Ok) | 518 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { |
| 505 | } | 519 | Ok(self.wait_for_high().await) |
| 506 | } | 520 | } |
| 507 | 521 | ||
| 508 | impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { | 522 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { |
| 509 | type WaitForHighFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 523 | Ok(self.wait_for_low().await) |
| 510 | 524 | } | |
| 511 | fn wait_for_high<'a>(&'a mut self) -> Self::WaitForHighFuture<'a> { | ||
| 512 | self.wait_for_high().map(Ok) | ||
| 513 | } | ||
| 514 | 525 | ||
| 515 | type WaitForLowFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 526 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { |
| 527 | Ok(self.wait_for_rising_edge().await) | ||
| 528 | } | ||
| 516 | 529 | ||
| 517 | fn wait_for_low<'a>(&'a mut self) -> Self::WaitForLowFuture<'a> { | 530 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { |
| 518 | self.wait_for_low().map(Ok) | 531 | Ok(self.wait_for_falling_edge().await) |
| 519 | } | 532 | } |
| 520 | 533 | ||
| 521 | type WaitForRisingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 534 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { |
| 535 | Ok(self.wait_for_any_edge().await) | ||
| 536 | } | ||
| 537 | } | ||
| 522 | 538 | ||
| 523 | fn wait_for_rising_edge<'a>(&'a mut self) -> Self::WaitForRisingEdgeFuture<'a> { | 539 | impl<'d, T: GpioPin> embedded_hal_async::digital::Wait for Flex<'d, T> { |
| 524 | self.wait_for_rising_edge().map(Ok) | 540 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { |
| 525 | } | 541 | Ok(self.wait_for_high().await) |
| 542 | } | ||
| 526 | 543 | ||
| 527 | type WaitForFallingEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 544 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { |
| 545 | Ok(self.wait_for_low().await) | ||
| 546 | } | ||
| 528 | 547 | ||
| 529 | fn wait_for_falling_edge<'a>(&'a mut self) -> Self::WaitForFallingEdgeFuture<'a> { | 548 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { |
| 530 | self.wait_for_falling_edge().map(Ok) | 549 | Ok(self.wait_for_rising_edge().await) |
| 531 | } | 550 | } |
| 532 | 551 | ||
| 533 | type WaitForAnyEdgeFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 552 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { |
| 553 | Ok(self.wait_for_falling_edge().await) | ||
| 554 | } | ||
| 534 | 555 | ||
| 535 | fn wait_for_any_edge<'a>(&'a mut self) -> Self::WaitForAnyEdgeFuture<'a> { | 556 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { |
| 536 | self.wait_for_any_edge().map(Ok) | 557 | Ok(self.wait_for_any_edge().await) |
| 537 | } | ||
| 538 | } | 558 | } |
| 539 | } | 559 | } |
| 540 | } | 560 | } |
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs new file mode 100644 index 000000000..fea38c4c0 --- /dev/null +++ b/embassy-nrf/src/i2s.rs | |||
| @@ -0,0 +1,1194 @@ | |||
| 1 | //! Inter-IC Sound (I2S) driver. | ||
| 2 | |||
| 3 | #![macro_use] | ||
| 4 | |||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::mem::size_of; | ||
| 8 | use core::ops::{Deref, DerefMut}; | ||
| 9 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 10 | use core::task::Poll; | ||
| 11 | |||
| 12 | use embassy_hal_common::drop::OnDrop; | ||
| 13 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 14 | |||
| 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 16 | use crate::interrupt::typelevel::Interrupt; | ||
| 17 | use crate::pac::i2s::RegisterBlock; | ||
| 18 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; | ||
| 19 | use crate::{interrupt, Peripheral, EASY_DMA_SIZE}; | ||
| 20 | |||
| 21 | /// Type alias for `MultiBuffering` with 2 buffers. | ||
| 22 | pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>; | ||
| 23 | |||
| 24 | /// I2S transfer error. | ||
| 25 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 26 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 27 | #[non_exhaustive] | ||
| 28 | pub enum Error { | ||
| 29 | /// The buffer is too long. | ||
| 30 | BufferTooLong, | ||
| 31 | /// The buffer is empty. | ||
| 32 | BufferZeroLength, | ||
| 33 | /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. | ||
| 34 | BufferNotInRAM, | ||
| 35 | /// The buffer address is not aligned. | ||
| 36 | BufferMisaligned, | ||
| 37 | /// The buffer length is not a multiple of the alignment. | ||
| 38 | BufferLengthMisaligned, | ||
| 39 | } | ||
| 40 | |||
| 41 | /// I2S configuration. | ||
| 42 | #[derive(Clone)] | ||
| 43 | #[non_exhaustive] | ||
| 44 | pub struct Config { | ||
| 45 | /// Sample width | ||
| 46 | pub sample_width: SampleWidth, | ||
| 47 | /// Alignment | ||
| 48 | pub align: Align, | ||
| 49 | /// Sample format | ||
| 50 | pub format: Format, | ||
| 51 | /// Channel configuration. | ||
| 52 | pub channels: Channels, | ||
| 53 | } | ||
| 54 | |||
| 55 | impl Default for Config { | ||
| 56 | fn default() -> Self { | ||
| 57 | Self { | ||
| 58 | sample_width: SampleWidth::_16bit, | ||
| 59 | align: Align::Left, | ||
| 60 | format: Format::I2S, | ||
| 61 | channels: Channels::Stereo, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | /// I2S clock configuration. | ||
| 67 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 68 | pub struct MasterClock { | ||
| 69 | freq: MckFreq, | ||
| 70 | ratio: Ratio, | ||
| 71 | } | ||
| 72 | |||
| 73 | impl MasterClock { | ||
| 74 | /// Create a new `MasterClock`. | ||
| 75 | pub fn new(freq: MckFreq, ratio: Ratio) -> Self { | ||
| 76 | Self { freq, ratio } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | impl MasterClock { | ||
| 81 | /// Get the sample rate for this clock configuration. | ||
| 82 | pub fn sample_rate(&self) -> u32 { | ||
| 83 | self.freq.to_frequency() / self.ratio.to_divisor() | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Master clock generator frequency. | ||
| 88 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 89 | pub enum MckFreq { | ||
| 90 | /// 32 Mhz / 8 = 4000.00 kHz | ||
| 91 | _32MDiv8, | ||
| 92 | /// 32 Mhz / 10 = 3200.00 kHz | ||
| 93 | _32MDiv10, | ||
| 94 | /// 32 Mhz / 11 = 2909.09 kHz | ||
| 95 | _32MDiv11, | ||
| 96 | /// 32 Mhz / 15 = 2133.33 kHz | ||
| 97 | _32MDiv15, | ||
| 98 | /// 32 Mhz / 16 = 2000.00 kHz | ||
| 99 | _32MDiv16, | ||
| 100 | /// 32 Mhz / 21 = 1523.81 kHz | ||
| 101 | _32MDiv21, | ||
| 102 | /// 32 Mhz / 23 = 1391.30 kHz | ||
| 103 | _32MDiv23, | ||
| 104 | /// 32 Mhz / 30 = 1066.67 kHz | ||
| 105 | _32MDiv30, | ||
| 106 | /// 32 Mhz / 31 = 1032.26 kHz | ||
| 107 | _32MDiv31, | ||
| 108 | /// 32 Mhz / 32 = 1000.00 kHz | ||
| 109 | _32MDiv32, | ||
| 110 | /// 32 Mhz / 42 = 761.90 kHz | ||
| 111 | _32MDiv42, | ||
| 112 | /// 32 Mhz / 63 = 507.94 kHz | ||
| 113 | _32MDiv63, | ||
| 114 | /// 32 Mhz / 125 = 256.00 kHz | ||
| 115 | _32MDiv125, | ||
| 116 | } | ||
| 117 | |||
| 118 | impl MckFreq { | ||
| 119 | const REGISTER_VALUES: &'static [u32] = &[ | ||
| 120 | 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000, | ||
| 121 | 0x08000000, 0x06000000, 0x04100000, 0x020C0000, | ||
| 122 | ]; | ||
| 123 | |||
| 124 | const FREQUENCIES: &'static [u32] = &[ | ||
| 125 | 4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936, | ||
| 126 | 256000, | ||
| 127 | ]; | ||
| 128 | |||
| 129 | /// Return the value that needs to be written to the register. | ||
| 130 | pub fn to_register_value(&self) -> u32 { | ||
| 131 | Self::REGISTER_VALUES[usize::from(*self)] | ||
| 132 | } | ||
| 133 | |||
| 134 | /// Return the master clock frequency. | ||
| 135 | pub fn to_frequency(&self) -> u32 { | ||
| 136 | Self::FREQUENCIES[usize::from(*self)] | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | impl From<MckFreq> for usize { | ||
| 141 | fn from(variant: MckFreq) -> Self { | ||
| 142 | variant as _ | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Master clock frequency ratio | ||
| 147 | /// | ||
| 148 | /// Sample Rate = LRCK = MCK / Ratio | ||
| 149 | /// | ||
| 150 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 151 | pub enum Ratio { | ||
| 152 | /// Divide by 32 | ||
| 153 | _32x, | ||
| 154 | /// Divide by 48 | ||
| 155 | _48x, | ||
| 156 | /// Divide by 64 | ||
| 157 | _64x, | ||
| 158 | /// Divide by 96 | ||
| 159 | _96x, | ||
| 160 | /// Divide by 128 | ||
| 161 | _128x, | ||
| 162 | /// Divide by 192 | ||
| 163 | _192x, | ||
| 164 | /// Divide by 256 | ||
| 165 | _256x, | ||
| 166 | /// Divide by 384 | ||
| 167 | _384x, | ||
| 168 | /// Divide by 512 | ||
| 169 | _512x, | ||
| 170 | } | ||
| 171 | |||
| 172 | impl Ratio { | ||
| 173 | const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512]; | ||
| 174 | |||
| 175 | /// Return the value that needs to be written to the register. | ||
| 176 | pub fn to_register_value(&self) -> u8 { | ||
| 177 | usize::from(*self) as u8 | ||
| 178 | } | ||
| 179 | |||
| 180 | /// Return the divisor for this ratio | ||
| 181 | pub fn to_divisor(&self) -> u32 { | ||
| 182 | Self::RATIOS[usize::from(*self)] | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | impl From<Ratio> for usize { | ||
| 187 | fn from(variant: Ratio) -> Self { | ||
| 188 | variant as _ | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | /// Approximate sample rates. | ||
| 193 | /// | ||
| 194 | /// Those are common sample rates that can not be configured without an small error. | ||
| 195 | /// | ||
| 196 | /// For custom master clock configuration, please refer to [MasterClock]. | ||
| 197 | #[derive(Clone, Copy)] | ||
| 198 | pub enum ApproxSampleRate { | ||
| 199 | /// 11025 Hz | ||
| 200 | _11025, | ||
| 201 | /// 16000 Hz | ||
| 202 | _16000, | ||
| 203 | /// 22050 Hz | ||
| 204 | _22050, | ||
| 205 | /// 32000 Hz | ||
| 206 | _32000, | ||
| 207 | /// 44100 Hz | ||
| 208 | _44100, | ||
| 209 | /// 48000 Hz | ||
| 210 | _48000, | ||
| 211 | } | ||
| 212 | |||
| 213 | impl From<ApproxSampleRate> for MasterClock { | ||
| 214 | fn from(value: ApproxSampleRate) -> Self { | ||
| 215 | match value { | ||
| 216 | // error = 86 | ||
| 217 | ApproxSampleRate::_11025 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_192x), | ||
| 218 | // error = 127 | ||
| 219 | ApproxSampleRate::_16000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_96x), | ||
| 220 | // error = 172 | ||
| 221 | ApproxSampleRate::_22050 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_96x), | ||
| 222 | // error = 254 | ||
| 223 | ApproxSampleRate::_32000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_48x), | ||
| 224 | // error = 344 | ||
| 225 | ApproxSampleRate::_44100 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_48x), | ||
| 226 | // error = 381 | ||
| 227 | ApproxSampleRate::_48000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_32x), | ||
| 228 | } | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | impl ApproxSampleRate { | ||
| 233 | /// Get the sample rate as an integer. | ||
| 234 | pub fn sample_rate(&self) -> u32 { | ||
| 235 | MasterClock::from(*self).sample_rate() | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | /// Exact sample rates. | ||
| 240 | /// | ||
| 241 | /// Those are non standard sample rates that can be configured without error. | ||
| 242 | /// | ||
| 243 | /// For custom master clock configuration, please refer to [Mode]. | ||
| 244 | #[derive(Clone, Copy)] | ||
| 245 | pub enum ExactSampleRate { | ||
| 246 | /// 8000 Hz | ||
| 247 | _8000, | ||
| 248 | /// 10582 Hz | ||
| 249 | _10582, | ||
| 250 | /// 12500 Hz | ||
| 251 | _12500, | ||
| 252 | /// 15625 Hz | ||
| 253 | _15625, | ||
| 254 | /// 15873 Hz | ||
| 255 | _15873, | ||
| 256 | /// 25000 Hz | ||
| 257 | _25000, | ||
| 258 | /// 31250 Hz | ||
| 259 | _31250, | ||
| 260 | /// 50000 Hz | ||
| 261 | _50000, | ||
| 262 | /// 62500 Hz | ||
| 263 | _62500, | ||
| 264 | /// 100000 Hz | ||
| 265 | _100000, | ||
| 266 | /// 125000 Hz | ||
| 267 | _125000, | ||
| 268 | } | ||
| 269 | |||
| 270 | impl ExactSampleRate { | ||
| 271 | /// Get the sample rate as an integer. | ||
| 272 | pub fn sample_rate(&self) -> u32 { | ||
| 273 | MasterClock::from(*self).sample_rate() | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | impl From<ExactSampleRate> for MasterClock { | ||
| 278 | fn from(value: ExactSampleRate) -> Self { | ||
| 279 | match value { | ||
| 280 | ExactSampleRate::_8000 => MasterClock::new(MckFreq::_32MDiv125, Ratio::_32x), | ||
| 281 | ExactSampleRate::_10582 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_48x), | ||
| 282 | ExactSampleRate::_12500 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_256x), | ||
| 283 | ExactSampleRate::_15625 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_64x), | ||
| 284 | ExactSampleRate::_15873 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_32x), | ||
| 285 | ExactSampleRate::_25000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_128x), | ||
| 286 | ExactSampleRate::_31250 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_32x), | ||
| 287 | ExactSampleRate::_50000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_64x), | ||
| 288 | ExactSampleRate::_62500 => MasterClock::new(MckFreq::_32MDiv16, Ratio::_32x), | ||
| 289 | ExactSampleRate::_100000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_32x), | ||
| 290 | ExactSampleRate::_125000 => MasterClock::new(MckFreq::_32MDiv8, Ratio::_32x), | ||
| 291 | } | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | /// Sample width. | ||
| 296 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 297 | pub enum SampleWidth { | ||
| 298 | /// 8 bit samples. | ||
| 299 | _8bit, | ||
| 300 | /// 16 bit samples. | ||
| 301 | _16bit, | ||
| 302 | /// 24 bit samples. | ||
| 303 | _24bit, | ||
| 304 | } | ||
| 305 | |||
| 306 | impl From<SampleWidth> for u8 { | ||
| 307 | fn from(variant: SampleWidth) -> Self { | ||
| 308 | variant as _ | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | /// Channel used for the most significant sample value in a frame. | ||
| 313 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 314 | pub enum Align { | ||
| 315 | /// Left-align samples. | ||
| 316 | Left, | ||
| 317 | /// Right-align samples. | ||
| 318 | Right, | ||
| 319 | } | ||
| 320 | |||
| 321 | impl From<Align> for bool { | ||
| 322 | fn from(variant: Align) -> Self { | ||
| 323 | match variant { | ||
| 324 | Align::Left => false, | ||
| 325 | Align::Right => true, | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | /// Frame format. | ||
| 331 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 332 | pub enum Format { | ||
| 333 | /// I2S frame format | ||
| 334 | I2S, | ||
| 335 | /// Aligned frame format | ||
| 336 | Aligned, | ||
| 337 | } | ||
| 338 | |||
| 339 | impl From<Format> for bool { | ||
| 340 | fn from(variant: Format) -> Self { | ||
| 341 | match variant { | ||
| 342 | Format::I2S => false, | ||
| 343 | Format::Aligned => true, | ||
| 344 | } | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | /// Channels | ||
| 349 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 350 | pub enum Channels { | ||
| 351 | /// Stereo (2 channels). | ||
| 352 | Stereo, | ||
| 353 | /// Mono, left channel only. | ||
| 354 | MonoLeft, | ||
| 355 | /// Mono, right channel only. | ||
| 356 | MonoRight, | ||
| 357 | } | ||
| 358 | |||
| 359 | impl From<Channels> for u8 { | ||
| 360 | fn from(variant: Channels) -> Self { | ||
| 361 | variant as _ | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | /// Interrupt handler. | ||
| 366 | pub struct InterruptHandler<T: Instance> { | ||
| 367 | _phantom: PhantomData<T>, | ||
| 368 | } | ||
| 369 | |||
| 370 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 371 | unsafe fn on_interrupt() { | ||
| 372 | let device = Device::<T>::new(); | ||
| 373 | let s = T::state(); | ||
| 374 | |||
| 375 | if device.is_tx_ptr_updated() { | ||
| 376 | trace!("TX INT"); | ||
| 377 | s.tx_waker.wake(); | ||
| 378 | device.disable_tx_ptr_interrupt(); | ||
| 379 | } | ||
| 380 | |||
| 381 | if device.is_rx_ptr_updated() { | ||
| 382 | trace!("RX INT"); | ||
| 383 | s.rx_waker.wake(); | ||
| 384 | device.disable_rx_ptr_interrupt(); | ||
| 385 | } | ||
| 386 | |||
| 387 | if device.is_stopped() { | ||
| 388 | trace!("STOPPED INT"); | ||
| 389 | s.stop_waker.wake(); | ||
| 390 | device.disable_stopped_interrupt(); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | /// I2S driver. | ||
| 396 | pub struct I2S<'d, T: Instance> { | ||
| 397 | i2s: PeripheralRef<'d, T>, | ||
| 398 | mck: Option<PeripheralRef<'d, AnyPin>>, | ||
| 399 | sck: PeripheralRef<'d, AnyPin>, | ||
| 400 | lrck: PeripheralRef<'d, AnyPin>, | ||
| 401 | sdin: Option<PeripheralRef<'d, AnyPin>>, | ||
| 402 | sdout: Option<PeripheralRef<'d, AnyPin>>, | ||
| 403 | master_clock: Option<MasterClock>, | ||
| 404 | config: Config, | ||
| 405 | } | ||
| 406 | |||
| 407 | impl<'d, T: Instance> I2S<'d, T> { | ||
| 408 | /// Create a new I2S in master mode | ||
| 409 | pub fn new_master( | ||
| 410 | i2s: impl Peripheral<P = T> + 'd, | ||
| 411 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 412 | mck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 413 | sck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 414 | lrck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 415 | master_clock: MasterClock, | ||
| 416 | config: Config, | ||
| 417 | ) -> Self { | ||
| 418 | into_ref!(i2s, mck, sck, lrck); | ||
| 419 | Self { | ||
| 420 | i2s, | ||
| 421 | mck: Some(mck.map_into()), | ||
| 422 | sck: sck.map_into(), | ||
| 423 | lrck: lrck.map_into(), | ||
| 424 | sdin: None, | ||
| 425 | sdout: None, | ||
| 426 | master_clock: Some(master_clock), | ||
| 427 | config, | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | /// Create a new I2S in slave mode | ||
| 432 | pub fn new_slave( | ||
| 433 | i2s: impl Peripheral<P = T> + 'd, | ||
| 434 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 435 | sck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 436 | lrck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 437 | config: Config, | ||
| 438 | ) -> Self { | ||
| 439 | into_ref!(i2s, sck, lrck); | ||
| 440 | Self { | ||
| 441 | i2s, | ||
| 442 | mck: None, | ||
| 443 | sck: sck.map_into(), | ||
| 444 | lrck: lrck.map_into(), | ||
| 445 | sdin: None, | ||
| 446 | sdout: None, | ||
| 447 | master_clock: None, | ||
| 448 | config, | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | /// I2S output only | ||
| 453 | pub fn output<S: Sample, const NB: usize, const NS: usize>( | ||
| 454 | mut self, | ||
| 455 | sdout: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 456 | buffers: MultiBuffering<S, NB, NS>, | ||
| 457 | ) -> OutputStream<'d, T, S, NB, NS> { | ||
| 458 | self.sdout = Some(sdout.into_ref().map_into()); | ||
| 459 | OutputStream { | ||
| 460 | _p: self.build(), | ||
| 461 | buffers, | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | /// I2S input only | ||
| 466 | pub fn input<S: Sample, const NB: usize, const NS: usize>( | ||
| 467 | mut self, | ||
| 468 | sdin: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 469 | buffers: MultiBuffering<S, NB, NS>, | ||
| 470 | ) -> InputStream<'d, T, S, NB, NS> { | ||
| 471 | self.sdin = Some(sdin.into_ref().map_into()); | ||
| 472 | InputStream { | ||
| 473 | _p: self.build(), | ||
| 474 | buffers, | ||
| 475 | } | ||
| 476 | } | ||
| 477 | |||
| 478 | /// I2S full duplex (input and output) | ||
| 479 | pub fn full_duplex<S: Sample, const NB: usize, const NS: usize>( | ||
| 480 | mut self, | ||
| 481 | sdin: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 482 | sdout: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 483 | buffers_out: MultiBuffering<S, NB, NS>, | ||
| 484 | buffers_in: MultiBuffering<S, NB, NS>, | ||
| 485 | ) -> FullDuplexStream<'d, T, S, NB, NS> { | ||
| 486 | self.sdout = Some(sdout.into_ref().map_into()); | ||
| 487 | self.sdin = Some(sdin.into_ref().map_into()); | ||
| 488 | |||
| 489 | FullDuplexStream { | ||
| 490 | _p: self.build(), | ||
| 491 | buffers_out, | ||
| 492 | buffers_in, | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | fn build(self) -> PeripheralRef<'d, T> { | ||
| 497 | self.apply_config(); | ||
| 498 | self.select_pins(); | ||
| 499 | self.setup_interrupt(); | ||
| 500 | |||
| 501 | let device = Device::<T>::new(); | ||
| 502 | device.enable(); | ||
| 503 | |||
| 504 | self.i2s | ||
| 505 | } | ||
| 506 | |||
| 507 | fn apply_config(&self) { | ||
| 508 | let c = &T::regs().config; | ||
| 509 | match &self.master_clock { | ||
| 510 | Some(MasterClock { freq, ratio }) => { | ||
| 511 | c.mode.write(|w| w.mode().master()); | ||
| 512 | c.mcken.write(|w| w.mcken().enabled()); | ||
| 513 | c.mckfreq | ||
| 514 | .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) }); | ||
| 515 | c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) }); | ||
| 516 | } | ||
| 517 | None => { | ||
| 518 | c.mode.write(|w| w.mode().slave()); | ||
| 519 | } | ||
| 520 | }; | ||
| 521 | |||
| 522 | c.swidth | ||
| 523 | .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) }); | ||
| 524 | c.align.write(|w| w.align().bit(self.config.align.into())); | ||
| 525 | c.format.write(|w| w.format().bit(self.config.format.into())); | ||
| 526 | c.channels | ||
| 527 | .write(|w| unsafe { w.channels().bits(self.config.channels.into()) }); | ||
| 528 | } | ||
| 529 | |||
| 530 | fn select_pins(&self) { | ||
| 531 | let psel = &T::regs().psel; | ||
| 532 | |||
| 533 | if let Some(mck) = &self.mck { | ||
| 534 | psel.mck.write(|w| { | ||
| 535 | unsafe { w.bits(mck.psel_bits()) }; | ||
| 536 | w.connect().connected() | ||
| 537 | }); | ||
| 538 | } | ||
| 539 | |||
| 540 | psel.sck.write(|w| { | ||
| 541 | unsafe { w.bits(self.sck.psel_bits()) }; | ||
| 542 | w.connect().connected() | ||
| 543 | }); | ||
| 544 | |||
| 545 | psel.lrck.write(|w| { | ||
| 546 | unsafe { w.bits(self.lrck.psel_bits()) }; | ||
| 547 | w.connect().connected() | ||
| 548 | }); | ||
| 549 | |||
| 550 | if let Some(sdin) = &self.sdin { | ||
| 551 | psel.sdin.write(|w| { | ||
| 552 | unsafe { w.bits(sdin.psel_bits()) }; | ||
| 553 | w.connect().connected() | ||
| 554 | }); | ||
| 555 | } | ||
| 556 | |||
| 557 | if let Some(sdout) = &self.sdout { | ||
| 558 | psel.sdout.write(|w| { | ||
| 559 | unsafe { w.bits(sdout.psel_bits()) }; | ||
| 560 | w.connect().connected() | ||
| 561 | }); | ||
| 562 | } | ||
| 563 | } | ||
| 564 | |||
| 565 | fn setup_interrupt(&self) { | ||
| 566 | T::Interrupt::unpend(); | ||
| 567 | unsafe { T::Interrupt::enable() }; | ||
| 568 | |||
| 569 | let device = Device::<T>::new(); | ||
| 570 | device.disable_tx_ptr_interrupt(); | ||
| 571 | device.disable_rx_ptr_interrupt(); | ||
| 572 | device.disable_stopped_interrupt(); | ||
| 573 | |||
| 574 | device.reset_tx_ptr_event(); | ||
| 575 | device.reset_rx_ptr_event(); | ||
| 576 | device.reset_stopped_event(); | ||
| 577 | |||
| 578 | device.enable_tx_ptr_interrupt(); | ||
| 579 | device.enable_rx_ptr_interrupt(); | ||
| 580 | device.enable_stopped_interrupt(); | ||
| 581 | } | ||
| 582 | |||
| 583 | async fn stop() { | ||
| 584 | compiler_fence(Ordering::SeqCst); | ||
| 585 | |||
| 586 | let device = Device::<T>::new(); | ||
| 587 | device.stop(); | ||
| 588 | |||
| 589 | T::state().started.store(false, Ordering::Relaxed); | ||
| 590 | |||
| 591 | poll_fn(|cx| { | ||
| 592 | T::state().stop_waker.register(cx.waker()); | ||
| 593 | |||
| 594 | if device.is_stopped() { | ||
| 595 | trace!("STOP: Ready"); | ||
| 596 | device.reset_stopped_event(); | ||
| 597 | Poll::Ready(()) | ||
| 598 | } else { | ||
| 599 | trace!("STOP: Pending"); | ||
| 600 | Poll::Pending | ||
| 601 | } | ||
| 602 | }) | ||
| 603 | .await; | ||
| 604 | |||
| 605 | device.disable(); | ||
| 606 | } | ||
| 607 | |||
| 608 | async fn send_from_ram<S>(buffer_ptr: *const [S]) -> Result<(), Error> | ||
| 609 | where | ||
| 610 | S: Sample, | ||
| 611 | { | ||
| 612 | trace!("SEND: {}", buffer_ptr as *const S as u32); | ||
| 613 | |||
| 614 | slice_in_ram_or(buffer_ptr, Error::BufferNotInRAM)?; | ||
| 615 | |||
| 616 | compiler_fence(Ordering::SeqCst); | ||
| 617 | |||
| 618 | let device = Device::<T>::new(); | ||
| 619 | |||
| 620 | device.update_tx(buffer_ptr)?; | ||
| 621 | |||
| 622 | Self::wait_tx_ptr_update().await; | ||
| 623 | |||
| 624 | compiler_fence(Ordering::SeqCst); | ||
| 625 | |||
| 626 | Ok(()) | ||
| 627 | } | ||
| 628 | |||
| 629 | async fn wait_tx_ptr_update() { | ||
| 630 | let drop = OnDrop::new(move || { | ||
| 631 | trace!("TX DROP: Stopping"); | ||
| 632 | |||
| 633 | let device = Device::<T>::new(); | ||
| 634 | device.disable_tx_ptr_interrupt(); | ||
| 635 | device.reset_tx_ptr_event(); | ||
| 636 | device.disable_tx(); | ||
| 637 | |||
| 638 | // TX is stopped almost instantly, spinning is fine. | ||
| 639 | while !device.is_tx_ptr_updated() {} | ||
| 640 | |||
| 641 | trace!("TX DROP: Stopped"); | ||
| 642 | }); | ||
| 643 | |||
| 644 | poll_fn(|cx| { | ||
| 645 | T::state().tx_waker.register(cx.waker()); | ||
| 646 | |||
| 647 | let device = Device::<T>::new(); | ||
| 648 | if device.is_tx_ptr_updated() { | ||
| 649 | trace!("TX POLL: Ready"); | ||
| 650 | device.reset_tx_ptr_event(); | ||
| 651 | device.enable_tx_ptr_interrupt(); | ||
| 652 | Poll::Ready(()) | ||
| 653 | } else { | ||
| 654 | trace!("TX POLL: Pending"); | ||
| 655 | Poll::Pending | ||
| 656 | } | ||
| 657 | }) | ||
| 658 | .await; | ||
| 659 | |||
| 660 | drop.defuse(); | ||
| 661 | } | ||
| 662 | |||
| 663 | async fn receive_from_ram<S>(buffer_ptr: *mut [S]) -> Result<(), Error> | ||
| 664 | where | ||
| 665 | S: Sample, | ||
| 666 | { | ||
| 667 | trace!("RECEIVE: {}", buffer_ptr as *const S as u32); | ||
| 668 | |||
| 669 | // NOTE: RAM slice check for rx is not necessary, as a mutable | ||
| 670 | // slice can only be built from data located in RAM. | ||
| 671 | |||
| 672 | compiler_fence(Ordering::SeqCst); | ||
| 673 | |||
| 674 | let device = Device::<T>::new(); | ||
| 675 | |||
| 676 | device.update_rx(buffer_ptr)?; | ||
| 677 | |||
| 678 | Self::wait_rx_ptr_update().await; | ||
| 679 | |||
| 680 | compiler_fence(Ordering::SeqCst); | ||
| 681 | |||
| 682 | Ok(()) | ||
| 683 | } | ||
| 684 | |||
| 685 | async fn wait_rx_ptr_update() { | ||
| 686 | let drop = OnDrop::new(move || { | ||
| 687 | trace!("RX DROP: Stopping"); | ||
| 688 | |||
| 689 | let device = Device::<T>::new(); | ||
| 690 | device.disable_rx_ptr_interrupt(); | ||
| 691 | device.reset_rx_ptr_event(); | ||
| 692 | device.disable_rx(); | ||
| 693 | |||
| 694 | // TX is stopped almost instantly, spinning is fine. | ||
| 695 | while !device.is_rx_ptr_updated() {} | ||
| 696 | |||
| 697 | trace!("RX DROP: Stopped"); | ||
| 698 | }); | ||
| 699 | |||
| 700 | poll_fn(|cx| { | ||
| 701 | T::state().rx_waker.register(cx.waker()); | ||
| 702 | |||
| 703 | let device = Device::<T>::new(); | ||
| 704 | if device.is_rx_ptr_updated() { | ||
| 705 | trace!("RX POLL: Ready"); | ||
| 706 | device.reset_rx_ptr_event(); | ||
| 707 | device.enable_rx_ptr_interrupt(); | ||
| 708 | Poll::Ready(()) | ||
| 709 | } else { | ||
| 710 | trace!("RX POLL: Pending"); | ||
| 711 | Poll::Pending | ||
| 712 | } | ||
| 713 | }) | ||
| 714 | .await; | ||
| 715 | |||
| 716 | drop.defuse(); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | /// I2S output | ||
| 721 | pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { | ||
| 722 | _p: PeripheralRef<'d, T>, | ||
| 723 | buffers: MultiBuffering<S, NB, NS>, | ||
| 724 | } | ||
| 725 | |||
| 726 | impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> { | ||
| 727 | /// Get a mutable reference to the current buffer. | ||
| 728 | pub fn buffer(&mut self) -> &mut [S] { | ||
| 729 | self.buffers.get_mut() | ||
| 730 | } | ||
| 731 | |||
| 732 | /// Prepare the initial buffer and start the I2S transfer. | ||
| 733 | pub async fn start(&mut self) -> Result<(), Error> | ||
| 734 | where | ||
| 735 | S: Sample, | ||
| 736 | { | ||
| 737 | let device = Device::<T>::new(); | ||
| 738 | |||
| 739 | let s = T::state(); | ||
| 740 | if s.started.load(Ordering::Relaxed) { | ||
| 741 | self.stop().await; | ||
| 742 | } | ||
| 743 | |||
| 744 | device.enable(); | ||
| 745 | device.enable_tx(); | ||
| 746 | |||
| 747 | device.update_tx(self.buffers.switch())?; | ||
| 748 | |||
| 749 | s.started.store(true, Ordering::Relaxed); | ||
| 750 | |||
| 751 | device.start(); | ||
| 752 | |||
| 753 | I2S::<T>::wait_tx_ptr_update().await; | ||
| 754 | |||
| 755 | Ok(()) | ||
| 756 | } | ||
| 757 | |||
| 758 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 759 | #[inline(always)] | ||
| 760 | pub async fn stop(&self) { | ||
| 761 | I2S::<T>::stop().await | ||
| 762 | } | ||
| 763 | |||
| 764 | /// Sends the current buffer for transmission in the DMA. | ||
| 765 | /// Switches to use the next available buffer. | ||
| 766 | pub async fn send(&mut self) -> Result<(), Error> | ||
| 767 | where | ||
| 768 | S: Sample, | ||
| 769 | { | ||
| 770 | I2S::<T>::send_from_ram(self.buffers.switch()).await | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | /// I2S input | ||
| 775 | pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { | ||
| 776 | _p: PeripheralRef<'d, T>, | ||
| 777 | buffers: MultiBuffering<S, NB, NS>, | ||
| 778 | } | ||
| 779 | |||
| 780 | impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> { | ||
| 781 | /// Get a mutable reference to the current buffer. | ||
| 782 | pub fn buffer(&mut self) -> &mut [S] { | ||
| 783 | self.buffers.get_mut() | ||
| 784 | } | ||
| 785 | |||
| 786 | /// Prepare the initial buffer and start the I2S transfer. | ||
| 787 | pub async fn start(&mut self) -> Result<(), Error> | ||
| 788 | where | ||
| 789 | S: Sample, | ||
| 790 | { | ||
| 791 | let device = Device::<T>::new(); | ||
| 792 | |||
| 793 | let s = T::state(); | ||
| 794 | if s.started.load(Ordering::Relaxed) { | ||
| 795 | self.stop().await; | ||
| 796 | } | ||
| 797 | |||
| 798 | device.enable(); | ||
| 799 | device.enable_rx(); | ||
| 800 | |||
| 801 | device.update_rx(self.buffers.switch())?; | ||
| 802 | |||
| 803 | s.started.store(true, Ordering::Relaxed); | ||
| 804 | |||
| 805 | device.start(); | ||
| 806 | |||
| 807 | I2S::<T>::wait_rx_ptr_update().await; | ||
| 808 | |||
| 809 | Ok(()) | ||
| 810 | } | ||
| 811 | |||
| 812 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 813 | #[inline(always)] | ||
| 814 | pub async fn stop(&self) { | ||
| 815 | I2S::<T>::stop().await | ||
| 816 | } | ||
| 817 | |||
| 818 | /// Sets the current buffer for reception from the DMA. | ||
| 819 | /// Switches to use the next available buffer. | ||
| 820 | #[allow(unused_mut)] | ||
| 821 | pub async fn receive(&mut self) -> Result<(), Error> | ||
| 822 | where | ||
| 823 | S: Sample, | ||
| 824 | { | ||
| 825 | I2S::<T>::receive_from_ram(self.buffers.switch_mut()).await | ||
| 826 | } | ||
| 827 | } | ||
| 828 | |||
| 829 | /// I2S full duplex stream (input & output) | ||
| 830 | pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { | ||
| 831 | _p: PeripheralRef<'d, T>, | ||
| 832 | buffers_out: MultiBuffering<S, NB, NS>, | ||
| 833 | buffers_in: MultiBuffering<S, NB, NS>, | ||
| 834 | } | ||
| 835 | |||
| 836 | impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> { | ||
| 837 | /// Get the current output and input buffers. | ||
| 838 | pub fn buffers(&mut self) -> (&mut [S], &[S]) { | ||
| 839 | (self.buffers_out.get_mut(), self.buffers_in.get()) | ||
| 840 | } | ||
| 841 | |||
| 842 | /// Prepare the initial buffers and start the I2S transfer. | ||
| 843 | pub async fn start(&mut self) -> Result<(), Error> | ||
| 844 | where | ||
| 845 | S: Sample, | ||
| 846 | { | ||
| 847 | let device = Device::<T>::new(); | ||
| 848 | |||
| 849 | let s = T::state(); | ||
| 850 | if s.started.load(Ordering::Relaxed) { | ||
| 851 | self.stop().await; | ||
| 852 | } | ||
| 853 | |||
| 854 | device.enable(); | ||
| 855 | device.enable_tx(); | ||
| 856 | device.enable_rx(); | ||
| 857 | |||
| 858 | device.update_tx(self.buffers_out.switch())?; | ||
| 859 | device.update_rx(self.buffers_in.switch_mut())?; | ||
| 860 | |||
| 861 | s.started.store(true, Ordering::Relaxed); | ||
| 862 | |||
| 863 | device.start(); | ||
| 864 | |||
| 865 | I2S::<T>::wait_tx_ptr_update().await; | ||
| 866 | I2S::<T>::wait_rx_ptr_update().await; | ||
| 867 | |||
| 868 | Ok(()) | ||
| 869 | } | ||
| 870 | |||
| 871 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 872 | #[inline(always)] | ||
| 873 | pub async fn stop(&self) { | ||
| 874 | I2S::<T>::stop().await | ||
| 875 | } | ||
| 876 | |||
| 877 | /// Sets the current buffers for output and input for transmission/reception from the DMA. | ||
| 878 | /// Switch to use the next available buffers for output/input. | ||
| 879 | pub async fn send_and_receive(&mut self) -> Result<(), Error> | ||
| 880 | where | ||
| 881 | S: Sample, | ||
| 882 | { | ||
| 883 | I2S::<T>::send_from_ram(self.buffers_out.switch()).await?; | ||
| 884 | I2S::<T>::receive_from_ram(self.buffers_in.switch_mut()).await?; | ||
| 885 | Ok(()) | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | /// Helper encapsulating common I2S device operations. | ||
| 890 | struct Device<T>(&'static RegisterBlock, PhantomData<T>); | ||
| 891 | |||
| 892 | impl<T: Instance> Device<T> { | ||
| 893 | fn new() -> Self { | ||
| 894 | Self(T::regs(), PhantomData) | ||
| 895 | } | ||
| 896 | |||
| 897 | #[inline(always)] | ||
| 898 | pub fn enable(&self) { | ||
| 899 | trace!("ENABLED"); | ||
| 900 | self.0.enable.write(|w| w.enable().enabled()); | ||
| 901 | } | ||
| 902 | |||
| 903 | #[inline(always)] | ||
| 904 | pub fn disable(&self) { | ||
| 905 | trace!("DISABLED"); | ||
| 906 | self.0.enable.write(|w| w.enable().disabled()); | ||
| 907 | } | ||
| 908 | |||
| 909 | #[inline(always)] | ||
| 910 | fn enable_tx(&self) { | ||
| 911 | trace!("TX ENABLED"); | ||
| 912 | self.0.config.txen.write(|w| w.txen().enabled()); | ||
| 913 | } | ||
| 914 | |||
| 915 | #[inline(always)] | ||
| 916 | fn disable_tx(&self) { | ||
| 917 | trace!("TX DISABLED"); | ||
| 918 | self.0.config.txen.write(|w| w.txen().disabled()); | ||
| 919 | } | ||
| 920 | |||
| 921 | #[inline(always)] | ||
| 922 | fn enable_rx(&self) { | ||
| 923 | trace!("RX ENABLED"); | ||
| 924 | self.0.config.rxen.write(|w| w.rxen().enabled()); | ||
| 925 | } | ||
| 926 | |||
| 927 | #[inline(always)] | ||
| 928 | fn disable_rx(&self) { | ||
| 929 | trace!("RX DISABLED"); | ||
| 930 | self.0.config.rxen.write(|w| w.rxen().disabled()); | ||
| 931 | } | ||
| 932 | |||
| 933 | #[inline(always)] | ||
| 934 | fn start(&self) { | ||
| 935 | trace!("START"); | ||
| 936 | self.0.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 937 | } | ||
| 938 | |||
| 939 | #[inline(always)] | ||
| 940 | fn stop(&self) { | ||
| 941 | self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 942 | } | ||
| 943 | |||
| 944 | #[inline(always)] | ||
| 945 | fn is_stopped(&self) -> bool { | ||
| 946 | self.0.events_stopped.read().bits() != 0 | ||
| 947 | } | ||
| 948 | |||
| 949 | #[inline(always)] | ||
| 950 | fn reset_stopped_event(&self) { | ||
| 951 | trace!("STOPPED EVENT: Reset"); | ||
| 952 | self.0.events_stopped.reset(); | ||
| 953 | } | ||
| 954 | |||
| 955 | #[inline(always)] | ||
| 956 | fn disable_stopped_interrupt(&self) { | ||
| 957 | trace!("STOPPED INTERRUPT: Disabled"); | ||
| 958 | self.0.intenclr.write(|w| w.stopped().clear()); | ||
| 959 | } | ||
| 960 | |||
| 961 | #[inline(always)] | ||
| 962 | fn enable_stopped_interrupt(&self) { | ||
| 963 | trace!("STOPPED INTERRUPT: Enabled"); | ||
| 964 | self.0.intenset.write(|w| w.stopped().set()); | ||
| 965 | } | ||
| 966 | |||
| 967 | #[inline(always)] | ||
| 968 | fn reset_tx_ptr_event(&self) { | ||
| 969 | trace!("TX PTR EVENT: Reset"); | ||
| 970 | self.0.events_txptrupd.reset(); | ||
| 971 | } | ||
| 972 | |||
| 973 | #[inline(always)] | ||
| 974 | fn reset_rx_ptr_event(&self) { | ||
| 975 | trace!("RX PTR EVENT: Reset"); | ||
| 976 | self.0.events_rxptrupd.reset(); | ||
| 977 | } | ||
| 978 | |||
| 979 | #[inline(always)] | ||
| 980 | fn disable_tx_ptr_interrupt(&self) { | ||
| 981 | trace!("TX PTR INTERRUPT: Disabled"); | ||
| 982 | self.0.intenclr.write(|w| w.txptrupd().clear()); | ||
| 983 | } | ||
| 984 | |||
| 985 | #[inline(always)] | ||
| 986 | fn disable_rx_ptr_interrupt(&self) { | ||
| 987 | trace!("RX PTR INTERRUPT: Disabled"); | ||
| 988 | self.0.intenclr.write(|w| w.rxptrupd().clear()); | ||
| 989 | } | ||
| 990 | |||
| 991 | #[inline(always)] | ||
| 992 | fn enable_tx_ptr_interrupt(&self) { | ||
| 993 | trace!("TX PTR INTERRUPT: Enabled"); | ||
| 994 | self.0.intenset.write(|w| w.txptrupd().set()); | ||
| 995 | } | ||
| 996 | |||
| 997 | #[inline(always)] | ||
| 998 | fn enable_rx_ptr_interrupt(&self) { | ||
| 999 | trace!("RX PTR INTERRUPT: Enabled"); | ||
| 1000 | self.0.intenset.write(|w| w.rxptrupd().set()); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | #[inline(always)] | ||
| 1004 | fn is_tx_ptr_updated(&self) -> bool { | ||
| 1005 | self.0.events_txptrupd.read().bits() != 0 | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | #[inline(always)] | ||
| 1009 | fn is_rx_ptr_updated(&self) -> bool { | ||
| 1010 | self.0.events_rxptrupd.read().bits() != 0 | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | #[inline] | ||
| 1014 | fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { | ||
| 1015 | let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; | ||
| 1016 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||
| 1017 | self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||
| 1018 | Ok(()) | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | #[inline] | ||
| 1022 | fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { | ||
| 1023 | let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; | ||
| 1024 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||
| 1025 | self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||
| 1026 | Ok(()) | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | fn validated_dma_parts<S>(buffer_ptr: *const [S]) -> Result<(u32, u32), Error> { | ||
| 1030 | let (ptr, len) = slice_ptr_parts(buffer_ptr); | ||
| 1031 | let ptr = ptr as u32; | ||
| 1032 | let bytes_len = len * size_of::<S>(); | ||
| 1033 | let maxcnt = (bytes_len / size_of::<u32>()) as u32; | ||
| 1034 | |||
| 1035 | trace!("PTR={}, MAXCNT={}", ptr, maxcnt); | ||
| 1036 | |||
| 1037 | if ptr % 4 != 0 { | ||
| 1038 | Err(Error::BufferMisaligned) | ||
| 1039 | } else if bytes_len % 4 != 0 { | ||
| 1040 | Err(Error::BufferLengthMisaligned) | ||
| 1041 | } else if maxcnt as usize > EASY_DMA_SIZE { | ||
| 1042 | Err(Error::BufferTooLong) | ||
| 1043 | } else { | ||
| 1044 | Ok((ptr, maxcnt)) | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /// Sample details | ||
| 1050 | pub trait Sample: Sized + Copy + Default { | ||
| 1051 | /// Width of this sample type. | ||
| 1052 | const WIDTH: usize; | ||
| 1053 | |||
| 1054 | /// Scale of this sample. | ||
| 1055 | const SCALE: Self; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | impl Sample for i8 { | ||
| 1059 | const WIDTH: usize = 8; | ||
| 1060 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | impl Sample for i16 { | ||
| 1064 | const WIDTH: usize = 16; | ||
| 1065 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | impl Sample for i32 { | ||
| 1069 | const WIDTH: usize = 24; | ||
| 1070 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | /// A 4-bytes aligned buffer. Needed for DMA access. | ||
| 1074 | #[derive(Clone, Copy)] | ||
| 1075 | #[repr(align(4))] | ||
| 1076 | pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); | ||
| 1077 | |||
| 1078 | impl<T: Sample, const N: usize> AlignedBuffer<T, N> { | ||
| 1079 | /// Create a new `AlignedBuffer`. | ||
| 1080 | pub fn new(array: [T; N]) -> Self { | ||
| 1081 | Self(array) | ||
| 1082 | } | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> { | ||
| 1086 | fn default() -> Self { | ||
| 1087 | Self([T::default(); N]) | ||
| 1088 | } | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | impl<T: Sample, const N: usize> Deref for AlignedBuffer<T, N> { | ||
| 1092 | type Target = [T]; | ||
| 1093 | fn deref(&self) -> &Self::Target { | ||
| 1094 | self.0.as_slice() | ||
| 1095 | } | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> { | ||
| 1099 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
| 1100 | self.0.as_mut_slice() | ||
| 1101 | } | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | /// Set of multiple buffers, for multi-buffering transfers. | ||
| 1105 | pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> { | ||
| 1106 | buffers: [AlignedBuffer<S, NS>; NB], | ||
| 1107 | index: usize, | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> { | ||
| 1111 | /// Create a new `MultiBuffering`. | ||
| 1112 | pub fn new() -> Self { | ||
| 1113 | assert!(NB > 1); | ||
| 1114 | Self { | ||
| 1115 | buffers: [AlignedBuffer::<S, NS>::default(); NB], | ||
| 1116 | index: 0, | ||
| 1117 | } | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | fn get(&self) -> &[S] { | ||
| 1121 | &self.buffers[self.index] | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | fn get_mut(&mut self) -> &mut [S] { | ||
| 1125 | &mut self.buffers[self.index] | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | /// Advance to use the next buffer and return a non mutable pointer to the previous one. | ||
| 1129 | fn switch(&mut self) -> *const [S] { | ||
| 1130 | let prev_index = self.index; | ||
| 1131 | self.index = (self.index + 1) % NB; | ||
| 1132 | self.buffers[prev_index].deref() as *const [S] | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | /// Advance to use the next buffer and return a mutable pointer to the previous one. | ||
| 1136 | fn switch_mut(&mut self) -> *mut [S] { | ||
| 1137 | let prev_index = self.index; | ||
| 1138 | self.index = (self.index + 1) % NB; | ||
| 1139 | self.buffers[prev_index].deref_mut() as *mut [S] | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | pub(crate) mod sealed { | ||
| 1144 | use core::sync::atomic::AtomicBool; | ||
| 1145 | |||
| 1146 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 1147 | |||
| 1148 | /// Peripheral static state | ||
| 1149 | pub struct State { | ||
| 1150 | pub started: AtomicBool, | ||
| 1151 | pub rx_waker: AtomicWaker, | ||
| 1152 | pub tx_waker: AtomicWaker, | ||
| 1153 | pub stop_waker: AtomicWaker, | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | impl State { | ||
| 1157 | pub const fn new() -> Self { | ||
| 1158 | Self { | ||
| 1159 | started: AtomicBool::new(false), | ||
| 1160 | rx_waker: AtomicWaker::new(), | ||
| 1161 | tx_waker: AtomicWaker::new(), | ||
| 1162 | stop_waker: AtomicWaker::new(), | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | pub trait Instance { | ||
| 1168 | fn regs() -> &'static crate::pac::i2s::RegisterBlock; | ||
| 1169 | fn state() -> &'static State; | ||
| 1170 | } | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | /// I2S peripheral instance. | ||
| 1174 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 1175 | /// Interrupt for this peripheral. | ||
| 1176 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | macro_rules! impl_i2s { | ||
| 1180 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 1181 | impl crate::i2s::sealed::Instance for peripherals::$type { | ||
| 1182 | fn regs() -> &'static crate::pac::i2s::RegisterBlock { | ||
| 1183 | unsafe { &*pac::$pac_type::ptr() } | ||
| 1184 | } | ||
| 1185 | fn state() -> &'static crate::i2s::sealed::State { | ||
| 1186 | static STATE: crate::i2s::sealed::State = crate::i2s::sealed::State::new(); | ||
| 1187 | &STATE | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | impl crate::i2s::Instance for peripherals::$type { | ||
| 1191 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 1192 | } | ||
| 1193 | }; | ||
| 1194 | } | ||
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 205891954..d23759f9d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -1,49 +1,7 @@ | |||
| 1 | //! # Embassy nRF HAL | ||
| 2 | //! | ||
| 3 | //! HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. | ||
| 4 | //! | ||
| 5 | //! The Embassy nRF HAL targets the Nordic Semiconductor nRF family of hardware. The HAL implements both blocking and async APIs | ||
| 6 | //! for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to | ||
| 7 | //! complete operations in low power mod and handling interrupts, so that applications can focus on more important matters. | ||
| 8 | //! | ||
| 9 | //! ## EasyDMA considerations | ||
| 10 | //! | ||
| 11 | //! On nRF chips, peripherals can use the so called EasyDMA feature to offload the task of interacting | ||
| 12 | //! with peripherals. It takes care of sending/receiving data over a variety of bus protocols (TWI/I2C, UART, SPI). | ||
| 13 | //! However, EasyDMA requires the buffers used to transmit and receive data to reside in RAM. Unfortunately, Rust | ||
| 14 | //! slices will not always do so. The following example using the SPI peripheral shows a common situation where this might happen: | ||
| 15 | //! | ||
| 16 | //! ```no_run | ||
| 17 | //! // As we pass a slice to the function whose contents will not ever change, | ||
| 18 | //! // the compiler writes it into the flash and thus the pointer to it will | ||
| 19 | //! // reference static memory. Since EasyDMA requires slices to reside in RAM, | ||
| 20 | //! // this function call will fail. | ||
| 21 | //! let result = spim.write_from_ram(&[1, 2, 3]); | ||
| 22 | //! assert_eq!(result, Err(Error::DMABufferNotInDataMemory)); | ||
| 23 | //! | ||
| 24 | //! // The data is still static and located in flash. However, since we are assigning | ||
| 25 | //! // it to a variable, the compiler will load it into memory. Passing a reference to the | ||
| 26 | //! // variable will yield a pointer that references dynamic memory, thus making EasyDMA happy. | ||
| 27 | //! // This function call succeeds. | ||
| 28 | //! let data = [1, 2, 3]; | ||
| 29 | //! let result = spim.write_from_ram(&data); | ||
| 30 | //! assert!(result.is_ok()); | ||
| 31 | //! ``` | ||
| 32 | //! | ||
| 33 | //! Each peripheral struct which uses EasyDMA ([`Spim`](spim::Spim), [`Uarte`](uarte::Uarte), [`Twim`](twim::Twim)) has two variants of their mutating functions: | ||
| 34 | //! - Functions with the suffix (e.g. [`write_from_ram`](spim::Spim::write_from_ram), [`transfer_from_ram`](spim::Spim::transfer_from_ram)) will return an error if the passed slice does not reside in RAM. | ||
| 35 | //! - Functions without the suffix (e.g. [`write`](spim::Spim::write), [`transfer`](spim::Spim::transfer)) will check whether the data is in RAM and copy it into memory prior to transmission. | ||
| 36 | //! | ||
| 37 | //! Since copying incurs a overhead, you are given the option to choose from `_from_ram` variants which will | ||
| 38 | //! fail and notify you, or the more convenient versions without the suffix which are potentially a little bit | ||
| 39 | //! more inefficient. Be aware that this overhead is not only in terms of instruction count but also in terms of memory usage | ||
| 40 | //! as the methods without the suffix will be allocating a statically sized buffer (up to 512 bytes for the nRF52840). | ||
| 41 | //! | ||
| 42 | //! Note that the methods that read data like [`read`](spim::Spim::read) and [`transfer_in_place`](spim::Spim::transfer_in_place) do not have the corresponding `_from_ram` variants as | ||
| 43 | //! mutable slices always reside in RAM. | ||
| 44 | |||
| 45 | #![no_std] | 1 | #![no_std] |
| 46 | #![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] | 2 | #![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] |
| 3 | #![doc = include_str!("../README.md")] | ||
| 4 | #![warn(missing_docs)] | ||
| 47 | 5 | ||
| 48 | #[cfg(not(any( | 6 | #[cfg(not(any( |
| 49 | feature = "nrf51", | 7 | feature = "nrf51", |
| @@ -62,6 +20,12 @@ | |||
| 62 | )))] | 20 | )))] |
| 63 | compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840"); | 21 | compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840"); |
| 64 | 22 | ||
| 23 | #[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))] | ||
| 24 | compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips."); | ||
| 25 | |||
| 26 | #[cfg(all(feature = "nfc-pins-as-gpio", not(any(feature = "_nrf52", feature = "_nrf5340-app"))))] | ||
| 27 | compile_error!("feature `nfc-pins-as-gpio` is only valid for nRF52, or nRF53's application core."); | ||
| 28 | |||
| 65 | // This mod MUST go first, so that the others see its macros. | 29 | // This mod MUST go first, so that the others see its macros. |
| 66 | pub(crate) mod fmt; | 30 | pub(crate) mod fmt; |
| 67 | pub(crate) mod util; | 31 | pub(crate) mod util; |
| @@ -69,29 +33,41 @@ pub(crate) mod util; | |||
| 69 | #[cfg(feature = "_time-driver")] | 33 | #[cfg(feature = "_time-driver")] |
| 70 | mod time_driver; | 34 | mod time_driver; |
| 71 | 35 | ||
| 72 | #[cfg(feature = "nightly")] | ||
| 73 | pub mod buffered_uarte; | 36 | pub mod buffered_uarte; |
| 74 | pub mod gpio; | 37 | pub mod gpio; |
| 75 | #[cfg(feature = "gpiote")] | 38 | #[cfg(feature = "gpiote")] |
| 76 | pub mod gpiote; | 39 | pub mod gpiote; |
| 77 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 40 | #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] |
| 41 | pub mod i2s; | ||
| 78 | pub mod nvmc; | 42 | pub mod nvmc; |
| 43 | #[cfg(any( | ||
| 44 | feature = "nrf52810", | ||
| 45 | feature = "nrf52811", | ||
| 46 | feature = "nrf52832", | ||
| 47 | feature = "nrf52833", | ||
| 48 | feature = "nrf52840", | ||
| 49 | feature = "_nrf5340-app", | ||
| 50 | feature = "_nrf9160" | ||
| 51 | ))] | ||
| 52 | pub mod pdm; | ||
| 79 | pub mod ppi; | 53 | pub mod ppi; |
| 80 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] | 54 | #[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))] |
| 81 | pub mod pwm; | 55 | pub mod pwm; |
| 82 | #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340")))] | 56 | #[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] |
| 83 | pub mod qdec; | 57 | pub mod qdec; |
| 84 | #[cfg(feature = "nrf52840")] | 58 | #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] |
| 85 | pub mod qspi; | 59 | pub mod qspi; |
| 86 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 60 | #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] |
| 87 | pub mod rng; | 61 | pub mod rng; |
| 88 | #[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] | 62 | #[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))] |
| 89 | pub mod saadc; | 63 | pub mod saadc; |
| 90 | pub mod spim; | 64 | pub mod spim; |
| 65 | pub mod spis; | ||
| 91 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | 66 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] |
| 92 | pub mod temp; | 67 | pub mod temp; |
| 93 | pub mod timer; | 68 | pub mod timer; |
| 94 | pub mod twim; | 69 | pub mod twim; |
| 70 | pub mod twis; | ||
| 95 | pub mod uarte; | 71 | pub mod uarte; |
| 96 | #[cfg(any( | 72 | #[cfg(any( |
| 97 | feature = "_nrf5340-app", | 73 | feature = "_nrf5340-app", |
| @@ -103,14 +79,6 @@ pub mod uarte; | |||
| 103 | pub mod usb; | 79 | pub mod usb; |
| 104 | #[cfg(not(feature = "_nrf5340"))] | 80 | #[cfg(not(feature = "_nrf5340"))] |
| 105 | pub mod wdt; | 81 | pub mod wdt; |
| 106 | #[cfg(any( | ||
| 107 | feature = "nrf52810", | ||
| 108 | feature = "nrf52811", | ||
| 109 | feature = "nrf52832", | ||
| 110 | feature = "nrf52833", | ||
| 111 | feature = "nrf52840", | ||
| 112 | ))] | ||
| 113 | pub mod pdm; | ||
| 114 | 82 | ||
| 115 | // This mod MUST go last, so that it sees all the `impl_foo!` macros | 83 | // This mod MUST go last, so that it sees all the `impl_foo!` macros |
| 116 | #[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] | 84 | #[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] |
| @@ -125,15 +93,32 @@ pub mod pdm; | |||
| 125 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] | 93 | #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] |
| 126 | mod chip; | 94 | mod chip; |
| 127 | 95 | ||
| 128 | pub use chip::EASY_DMA_SIZE; | 96 | /// Macro to bind interrupts to handlers. |
| 97 | /// | ||
| 98 | /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) | ||
| 99 | /// and implements the right [`Binding`]s for it. You can pass this struct to drivers to | ||
| 100 | /// prove at compile-time that the right interrupts have been bound. | ||
| 101 | // developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`. | ||
| 102 | #[macro_export] | ||
| 103 | macro_rules! bind_interrupts { | ||
| 104 | ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { | ||
| 105 | $vis struct $name; | ||
| 129 | 106 | ||
| 130 | pub mod interrupt { | 107 | $( |
| 131 | //! nRF interrupts for cortex-m devices. | 108 | #[allow(non_snake_case)] |
| 132 | pub use cortex_m::interrupt::{CriticalSection, Mutex}; | 109 | #[no_mangle] |
| 133 | pub use embassy_cortex_m::interrupt::*; | 110 | unsafe extern "C" fn $irq() { |
| 111 | $( | ||
| 112 | <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); | ||
| 113 | )* | ||
| 114 | } | ||
| 134 | 115 | ||
| 135 | pub use crate::chip::irqs::*; | 116 | $( |
| 136 | } | 117 | unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} |
| 118 | )* | ||
| 119 | )* | ||
| 120 | }; | ||
| 121 | } | ||
| 137 | 122 | ||
| 138 | // Reexports | 123 | // Reexports |
| 139 | 124 | ||
| @@ -141,11 +126,12 @@ pub mod interrupt { | |||
| 141 | pub use chip::pac; | 126 | pub use chip::pac; |
| 142 | #[cfg(not(feature = "unstable-pac"))] | 127 | #[cfg(not(feature = "unstable-pac"))] |
| 143 | pub(crate) use chip::pac; | 128 | pub(crate) use chip::pac; |
| 144 | pub use chip::{peripherals, Peripherals}; | 129 | pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; |
| 145 | pub use embassy_cortex_m::executor; | ||
| 146 | pub use embassy_cortex_m::interrupt::_export::interrupt; | ||
| 147 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; | 130 | pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; |
| 148 | 131 | ||
| 132 | pub use crate::chip::interrupt; | ||
| 133 | pub use crate::pac::NVIC_PRIO_BITS; | ||
| 134 | |||
| 149 | pub mod config { | 135 | pub mod config { |
| 150 | //! Configuration options used when initializing the HAL. | 136 | //! Configuration options used when initializing the HAL. |
| 151 | 137 | ||
| @@ -174,6 +160,47 @@ pub mod config { | |||
| 174 | ExternalFullSwing, | 160 | ExternalFullSwing, |
| 175 | } | 161 | } |
| 176 | 162 | ||
| 163 | /// SWD access port protection setting. | ||
| 164 | #[non_exhaustive] | ||
| 165 | pub enum Debug { | ||
| 166 | /// Debugging is allowed (APPROTECT is disabled). Default. | ||
| 167 | Allowed, | ||
| 168 | /// Debugging is not allowed (APPROTECT is enabled). | ||
| 169 | Disallowed, | ||
| 170 | /// APPROTECT is not configured (neither to enable it or disable it). | ||
| 171 | /// This can be useful if you're already doing it by other means and | ||
| 172 | /// you don't want embassy-nrf to touch UICR. | ||
| 173 | NotConfigured, | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Settings for enabling the built in DCDC converters. | ||
| 177 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | ||
| 178 | pub struct DcdcConfig { | ||
| 179 | /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used. | ||
| 180 | #[cfg(feature = "nrf52840")] | ||
| 181 | pub reg0: bool, | ||
| 182 | /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used. | ||
| 183 | pub reg1: bool, | ||
| 184 | } | ||
| 185 | |||
| 186 | /// Settings for enabling the built in DCDC converters. | ||
| 187 | #[cfg(feature = "_nrf5340-app")] | ||
| 188 | pub struct DcdcConfig { | ||
| 189 | /// Config for the high voltage stage, if disabled LDO will be used. | ||
| 190 | pub regh: bool, | ||
| 191 | /// Config for the main rail, if disabled LDO will be used. | ||
| 192 | pub regmain: bool, | ||
| 193 | /// Config for the radio rail, if disabled LDO will be used. | ||
| 194 | pub regradio: bool, | ||
| 195 | } | ||
| 196 | |||
| 197 | /// Settings for enabling the built in DCDC converter. | ||
| 198 | #[cfg(feature = "_nrf9160")] | ||
| 199 | pub struct DcdcConfig { | ||
| 200 | /// Config for the main rail, if disabled LDO will be used. | ||
| 201 | pub regmain: bool, | ||
| 202 | } | ||
| 203 | |||
| 177 | /// Configuration for peripherals. Default configuration should work on any nRF chip. | 204 | /// Configuration for peripherals. Default configuration should work on any nRF chip. |
| 178 | #[non_exhaustive] | 205 | #[non_exhaustive] |
| 179 | pub struct Config { | 206 | pub struct Config { |
| @@ -181,12 +208,17 @@ pub mod config { | |||
| 181 | pub hfclk_source: HfclkSource, | 208 | pub hfclk_source: HfclkSource, |
| 182 | /// Low frequency clock source. | 209 | /// Low frequency clock source. |
| 183 | pub lfclk_source: LfclkSource, | 210 | pub lfclk_source: LfclkSource, |
| 211 | #[cfg(not(feature = "_nrf5340-net"))] | ||
| 212 | /// DCDC configuration. | ||
| 213 | pub dcdc: DcdcConfig, | ||
| 184 | /// GPIOTE interrupt priority. Should be lower priority than softdevice if used. | 214 | /// GPIOTE interrupt priority. Should be lower priority than softdevice if used. |
| 185 | #[cfg(feature = "gpiote")] | 215 | #[cfg(feature = "gpiote")] |
| 186 | pub gpiote_interrupt_priority: crate::interrupt::Priority, | 216 | pub gpiote_interrupt_priority: crate::interrupt::Priority, |
| 187 | /// Time driver interrupt priority. Should be lower priority than softdevice if used. | 217 | /// Time driver interrupt priority. Should be lower priority than softdevice if used. |
| 188 | #[cfg(feature = "_time-driver")] | 218 | #[cfg(feature = "_time-driver")] |
| 189 | pub time_interrupt_priority: crate::interrupt::Priority, | 219 | pub time_interrupt_priority: crate::interrupt::Priority, |
| 220 | /// Enable or disable the debug port. | ||
| 221 | pub debug: Debug, | ||
| 190 | } | 222 | } |
| 191 | 223 | ||
| 192 | impl Default for Config { | 224 | impl Default for Config { |
| @@ -197,21 +229,218 @@ pub mod config { | |||
| 197 | // xtals if they know they have them. | 229 | // xtals if they know they have them. |
| 198 | hfclk_source: HfclkSource::Internal, | 230 | hfclk_source: HfclkSource::Internal, |
| 199 | lfclk_source: LfclkSource::InternalRC, | 231 | lfclk_source: LfclkSource::InternalRC, |
| 232 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | ||
| 233 | dcdc: DcdcConfig { | ||
| 234 | #[cfg(feature = "nrf52840")] | ||
| 235 | reg0: false, | ||
| 236 | reg1: false, | ||
| 237 | }, | ||
| 238 | #[cfg(feature = "_nrf5340-app")] | ||
| 239 | dcdc: DcdcConfig { | ||
| 240 | regh: false, | ||
| 241 | regmain: false, | ||
| 242 | regradio: false, | ||
| 243 | }, | ||
| 244 | #[cfg(feature = "_nrf9160")] | ||
| 245 | dcdc: DcdcConfig { regmain: false }, | ||
| 200 | #[cfg(feature = "gpiote")] | 246 | #[cfg(feature = "gpiote")] |
| 201 | gpiote_interrupt_priority: crate::interrupt::Priority::P0, | 247 | gpiote_interrupt_priority: crate::interrupt::Priority::P0, |
| 202 | #[cfg(feature = "_time-driver")] | 248 | #[cfg(feature = "_time-driver")] |
| 203 | time_interrupt_priority: crate::interrupt::Priority::P0, | 249 | time_interrupt_priority: crate::interrupt::Priority::P0, |
| 250 | |||
| 251 | // In NS mode, default to NotConfigured, assuming the S firmware will do it. | ||
| 252 | #[cfg(feature = "_ns")] | ||
| 253 | debug: Debug::NotConfigured, | ||
| 254 | #[cfg(not(feature = "_ns"))] | ||
| 255 | debug: Debug::Allowed, | ||
| 204 | } | 256 | } |
| 205 | } | 257 | } |
| 206 | } | 258 | } |
| 207 | } | 259 | } |
| 208 | 260 | ||
| 261 | #[cfg(feature = "_nrf9160")] | ||
| 262 | #[allow(unused)] | ||
| 263 | mod consts { | ||
| 264 | pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; | ||
| 265 | pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF802C as *mut u32; | ||
| 266 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | ||
| 267 | } | ||
| 268 | |||
| 269 | #[cfg(feature = "_nrf5340-app")] | ||
| 270 | #[allow(unused)] | ||
| 271 | mod consts { | ||
| 272 | pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; | ||
| 273 | pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF801C as *mut u32; | ||
| 274 | pub const UICR_NFCPINS: *mut u32 = 0x00FF8028 as *mut u32; | ||
| 275 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | ||
| 276 | pub const APPROTECT_DISABLED: u32 = 0x50FA50FA; | ||
| 277 | } | ||
| 278 | |||
| 279 | #[cfg(feature = "_nrf5340-net")] | ||
| 280 | #[allow(unused)] | ||
| 281 | mod consts { | ||
| 282 | pub const UICR_APPROTECT: *mut u32 = 0x01FF8000 as *mut u32; | ||
| 283 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | ||
| 284 | pub const APPROTECT_DISABLED: u32 = 0x50FA50FA; | ||
| 285 | } | ||
| 286 | |||
| 287 | #[cfg(feature = "_nrf52")] | ||
| 288 | #[allow(unused)] | ||
| 289 | mod consts { | ||
| 290 | pub const UICR_PSELRESET1: *mut u32 = 0x10001200 as *mut u32; | ||
| 291 | pub const UICR_PSELRESET2: *mut u32 = 0x10001204 as *mut u32; | ||
| 292 | pub const UICR_NFCPINS: *mut u32 = 0x1000120C as *mut u32; | ||
| 293 | pub const UICR_APPROTECT: *mut u32 = 0x10001208 as *mut u32; | ||
| 294 | pub const APPROTECT_ENABLED: u32 = 0x0000_0000; | ||
| 295 | pub const APPROTECT_DISABLED: u32 = 0x0000_005a; | ||
| 296 | } | ||
| 297 | |||
| 298 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 299 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 300 | enum WriteResult { | ||
| 301 | /// Word was written successfully, needs reset. | ||
| 302 | Written, | ||
| 303 | /// Word was already set to the value we wanted to write, nothing was done. | ||
| 304 | Noop, | ||
| 305 | /// Word is already set to something else, we couldn't write the desired value. | ||
| 306 | Failed, | ||
| 307 | } | ||
| 308 | |||
| 309 | unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { | ||
| 310 | uicr_write_masked(address, value, 0xFFFF_FFFF) | ||
| 311 | } | ||
| 312 | |||
| 313 | unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { | ||
| 314 | let curr_val = address.read_volatile(); | ||
| 315 | if curr_val & mask == value & mask { | ||
| 316 | return WriteResult::Noop; | ||
| 317 | } | ||
| 318 | |||
| 319 | // We can only change `1` bits to `0` bits. | ||
| 320 | if curr_val & value & mask != value & mask { | ||
| 321 | return WriteResult::Failed; | ||
| 322 | } | ||
| 323 | |||
| 324 | let nvmc = &*pac::NVMC::ptr(); | ||
| 325 | nvmc.config.write(|w| w.wen().wen()); | ||
| 326 | while nvmc.ready.read().ready().is_busy() {} | ||
| 327 | address.write_volatile(value | !mask); | ||
| 328 | while nvmc.ready.read().ready().is_busy() {} | ||
| 329 | nvmc.config.reset(); | ||
| 330 | while nvmc.ready.read().ready().is_busy() {} | ||
| 331 | |||
| 332 | WriteResult::Written | ||
| 333 | } | ||
| 334 | |||
| 209 | /// Initialize peripherals with the provided configuration. This should only be called once at startup. | 335 | /// Initialize peripherals with the provided configuration. This should only be called once at startup. |
| 210 | pub fn init(config: config::Config) -> Peripherals { | 336 | pub fn init(config: config::Config) -> Peripherals { |
| 211 | // Do this first, so that it panics if user is calling `init` a second time | 337 | // Do this first, so that it panics if user is calling `init` a second time |
| 212 | // before doing anything important. | 338 | // before doing anything important. |
| 213 | let peripherals = Peripherals::take(); | 339 | let peripherals = Peripherals::take(); |
| 214 | 340 | ||
| 341 | let mut needs_reset = false; | ||
| 342 | |||
| 343 | // Setup debug protection. | ||
| 344 | match config.debug { | ||
| 345 | config::Debug::Allowed => { | ||
| 346 | #[cfg(feature = "_nrf52")] | ||
| 347 | unsafe { | ||
| 348 | let variant = (0x1000_0104 as *mut u32).read_volatile(); | ||
| 349 | // Get the letter for the build code (b'A' .. b'F') | ||
| 350 | let build_code = (variant >> 8) as u8; | ||
| 351 | |||
| 352 | if build_code >= b'F' { | ||
| 353 | // Chips with build code F and higher (revision 3 and higher) have an | ||
| 354 | // improved APPROTECT ("hardware and software controlled access port protection") | ||
| 355 | // which needs explicit action by the firmware to keep it unlocked | ||
| 356 | |||
| 357 | // UICR.APPROTECT = SwDisabled | ||
| 358 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | ||
| 359 | needs_reset |= res == WriteResult::Written; | ||
| 360 | // APPROTECT.DISABLE = SwDisabled | ||
| 361 | (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED); | ||
| 362 | } else { | ||
| 363 | // nothing to do on older chips, debug is allowed by default. | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | #[cfg(feature = "_nrf5340")] | ||
| 368 | unsafe { | ||
| 369 | let p = &*pac::CTRLAP::ptr(); | ||
| 370 | |||
| 371 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | ||
| 372 | needs_reset |= res == WriteResult::Written; | ||
| 373 | p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | ||
| 374 | |||
| 375 | #[cfg(feature = "_nrf5340-app")] | ||
| 376 | { | ||
| 377 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); | ||
| 378 | needs_reset |= res == WriteResult::Written; | ||
| 379 | p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | // nothing to do on the nrf9160, debug is allowed by default. | ||
| 384 | } | ||
| 385 | config::Debug::Disallowed => unsafe { | ||
| 386 | // UICR.APPROTECT = Enabled | ||
| 387 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); | ||
| 388 | needs_reset |= res == WriteResult::Written; | ||
| 389 | #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))] | ||
| 390 | { | ||
| 391 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); | ||
| 392 | needs_reset |= res == WriteResult::Written; | ||
| 393 | } | ||
| 394 | }, | ||
| 395 | config::Debug::NotConfigured => {} | ||
| 396 | } | ||
| 397 | |||
| 398 | #[cfg(feature = "_nrf52")] | ||
| 399 | unsafe { | ||
| 400 | let value = if cfg!(feature = "reset-pin-as-gpio") { | ||
| 401 | !0 | ||
| 402 | } else { | ||
| 403 | chip::RESET_PIN | ||
| 404 | }; | ||
| 405 | let res1 = uicr_write(consts::UICR_PSELRESET1, value); | ||
| 406 | let res2 = uicr_write(consts::UICR_PSELRESET2, value); | ||
| 407 | needs_reset |= res1 == WriteResult::Written || res2 == WriteResult::Written; | ||
| 408 | if res1 == WriteResult::Failed || res2 == WriteResult::Failed { | ||
| 409 | #[cfg(not(feature = "reset-pin-as-gpio"))] | ||
| 410 | warn!( | ||
| 411 | "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\ | ||
| 412 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 413 | To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." | ||
| 414 | ); | ||
| 415 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 416 | warn!( | ||
| 417 | "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\ | ||
| 418 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 419 | To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." | ||
| 420 | ); | ||
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | #[cfg(any(feature = "_nrf52", feature = "_nrf5340-app"))] | ||
| 425 | unsafe { | ||
| 426 | let value = if cfg!(feature = "nfc-pins-as-gpio") { 0 } else { 1 }; | ||
| 427 | let res = uicr_write_masked(consts::UICR_NFCPINS, value, 1); | ||
| 428 | needs_reset |= res == WriteResult::Written; | ||
| 429 | if res == WriteResult::Failed { | ||
| 430 | // with nfc-pins-as-gpio, this can never fail because we're writing all zero bits. | ||
| 431 | #[cfg(not(feature = "nfc-pins-as-gpio"))] | ||
| 432 | warn!( | ||
| 433 | "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\ | ||
| 434 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 435 | To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." | ||
| 436 | ); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | if needs_reset { | ||
| 441 | cortex_m::peripheral::SCB::sys_reset(); | ||
| 442 | } | ||
| 443 | |||
| 215 | let r = unsafe { &*pac::CLOCK::ptr() }; | 444 | let r = unsafe { &*pac::CLOCK::ptr() }; |
| 216 | 445 | ||
| 217 | // Start HFCLK. | 446 | // Start HFCLK. |
| @@ -259,6 +488,41 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 259 | r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); | 488 | r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); |
| 260 | while r.events_lfclkstarted.read().bits() == 0 {} | 489 | while r.events_lfclkstarted.read().bits() == 0 {} |
| 261 | 490 | ||
| 491 | #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] | ||
| 492 | { | ||
| 493 | // Setup DCDCs. | ||
| 494 | let pwr = unsafe { &*pac::POWER::ptr() }; | ||
| 495 | #[cfg(feature = "nrf52840")] | ||
| 496 | if config.dcdc.reg0 { | ||
| 497 | pwr.dcdcen0.write(|w| w.dcdcen().set_bit()); | ||
| 498 | } | ||
| 499 | if config.dcdc.reg1 { | ||
| 500 | pwr.dcdcen.write(|w| w.dcdcen().set_bit()); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | #[cfg(feature = "_nrf9160")] | ||
| 504 | { | ||
| 505 | // Setup DCDC. | ||
| 506 | let reg = unsafe { &*pac::REGULATORS::ptr() }; | ||
| 507 | if config.dcdc.regmain { | ||
| 508 | reg.dcdcen.write(|w| w.dcdcen().set_bit()); | ||
| 509 | } | ||
| 510 | } | ||
| 511 | #[cfg(feature = "_nrf5340-app")] | ||
| 512 | { | ||
| 513 | // Setup DCDC. | ||
| 514 | let reg = unsafe { &*pac::REGULATORS::ptr() }; | ||
| 515 | if config.dcdc.regh { | ||
| 516 | reg.vregh.dcdcen.write(|w| w.dcdcen().set_bit()); | ||
| 517 | } | ||
| 518 | if config.dcdc.regmain { | ||
| 519 | reg.vregmain.dcdcen.write(|w| w.dcdcen().set_bit()); | ||
| 520 | } | ||
| 521 | if config.dcdc.regradio { | ||
| 522 | reg.vregradio.dcdcen.write(|w| w.dcdcen().set_bit()); | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 262 | // Init GPIOTE | 526 | // Init GPIOTE |
| 263 | #[cfg(feature = "gpiote")] | 527 | #[cfg(feature = "gpiote")] |
| 264 | gpiote::init(config.gpiote_interrupt_priority); | 528 | gpiote::init(config.gpiote_interrupt_priority); |
| @@ -267,5 +531,12 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 267 | #[cfg(feature = "_time-driver")] | 531 | #[cfg(feature = "_time-driver")] |
| 268 | time_driver::init(config.time_interrupt_priority); | 532 | time_driver::init(config.time_interrupt_priority); |
| 269 | 533 | ||
| 534 | // Disable UARTE (enabled by default for some reason) | ||
| 535 | #[cfg(feature = "_nrf9160")] | ||
| 536 | unsafe { | ||
| 537 | (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); | ||
| 538 | (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); | ||
| 539 | } | ||
| 540 | |||
| 270 | peripherals | 541 | peripherals |
| 271 | } | 542 | } |
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index 6f66f7a78..91a5a272f 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! Non-Volatile Memory Controller (NVMC) module. | 1 | //! Non-Volatile Memory Controller (NVMC, AKA internal flash) driver. |
| 2 | 2 | ||
| 3 | use core::{ptr, slice}; | 3 | use core::{ptr, slice}; |
| 4 | 4 | ||
| @@ -10,8 +10,12 @@ use embedded_storage::nor_flash::{ | |||
| 10 | use crate::peripherals::NVMC; | 10 | use crate::peripherals::NVMC; |
| 11 | use crate::{pac, Peripheral}; | 11 | use crate::{pac, Peripheral}; |
| 12 | 12 | ||
| 13 | #[cfg(not(feature = "_nrf5340-net"))] | ||
| 13 | /// Erase size of NVMC flash in bytes. | 14 | /// Erase size of NVMC flash in bytes. |
| 14 | pub const PAGE_SIZE: usize = 4096; | 15 | pub const PAGE_SIZE: usize = 4096; |
| 16 | #[cfg(feature = "_nrf5340-net")] | ||
| 17 | /// Erase size of NVMC flash in bytes. | ||
| 18 | pub const PAGE_SIZE: usize = 2048; | ||
| 15 | 19 | ||
| 16 | /// Size of NVMC flash in bytes. | 20 | /// Size of NVMC flash in bytes. |
| 17 | pub const FLASH_SIZE: usize = crate::chip::FLASH_SIZE; | 21 | pub const FLASH_SIZE: usize = crate::chip::FLASH_SIZE; |
| @@ -20,7 +24,7 @@ pub const FLASH_SIZE: usize = crate::chip::FLASH_SIZE; | |||
| 20 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 24 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 25 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 22 | pub enum Error { | 26 | pub enum Error { |
| 23 | /// Opration using a location not in flash. | 27 | /// Operation using a location not in flash. |
| 24 | OutOfBounds, | 28 | OutOfBounds, |
| 25 | /// Unaligned operation or using unaligned buffers. | 29 | /// Unaligned operation or using unaligned buffers. |
| 26 | Unaligned, | 30 | Unaligned, |
| @@ -55,6 +59,51 @@ impl<'d> Nvmc<'d> { | |||
| 55 | let p = Self::regs(); | 59 | let p = Self::regs(); |
| 56 | while p.ready.read().ready().is_busy() {} | 60 | while p.ready.read().ready().is_busy() {} |
| 57 | } | 61 | } |
| 62 | |||
| 63 | #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] | ||
| 64 | fn wait_ready_write(&mut self) { | ||
| 65 | self.wait_ready(); | ||
| 66 | } | ||
| 67 | |||
| 68 | #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] | ||
| 69 | fn wait_ready_write(&mut self) { | ||
| 70 | let p = Self::regs(); | ||
| 71 | while p.readynext.read().readynext().is_busy() {} | ||
| 72 | } | ||
| 73 | |||
| 74 | #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] | ||
| 75 | fn erase_page(&mut self, page_addr: u32) { | ||
| 76 | Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) }); | ||
| 77 | } | ||
| 78 | |||
| 79 | #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] | ||
| 80 | fn erase_page(&mut self, page_addr: u32) { | ||
| 81 | let first_page_word = page_addr as *mut u32; | ||
| 82 | unsafe { | ||
| 83 | first_page_word.write_volatile(0xFFFF_FFFF); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | fn enable_erase(&self) { | ||
| 88 | #[cfg(not(feature = "_ns"))] | ||
| 89 | Self::regs().config.write(|w| w.wen().een()); | ||
| 90 | #[cfg(feature = "_ns")] | ||
| 91 | Self::regs().configns.write(|w| w.wen().een()); | ||
| 92 | } | ||
| 93 | |||
| 94 | fn enable_read(&self) { | ||
| 95 | #[cfg(not(feature = "_ns"))] | ||
| 96 | Self::regs().config.write(|w| w.wen().ren()); | ||
| 97 | #[cfg(feature = "_ns")] | ||
| 98 | Self::regs().configns.write(|w| w.wen().ren()); | ||
| 99 | } | ||
| 100 | |||
| 101 | fn enable_write(&self) { | ||
| 102 | #[cfg(not(feature = "_ns"))] | ||
| 103 | Self::regs().config.write(|w| w.wen().wen()); | ||
| 104 | #[cfg(feature = "_ns")] | ||
| 105 | Self::regs().configns.write(|w| w.wen().wen()); | ||
| 106 | } | ||
| 58 | } | 107 | } |
| 59 | 108 | ||
| 60 | impl<'d> MultiwriteNorFlash for Nvmc<'d> {} | 109 | impl<'d> MultiwriteNorFlash for Nvmc<'d> {} |
| @@ -93,17 +142,15 @@ impl<'d> NorFlash for Nvmc<'d> { | |||
| 93 | return Err(Error::Unaligned); | 142 | return Err(Error::Unaligned); |
| 94 | } | 143 | } |
| 95 | 144 | ||
| 96 | let p = Self::regs(); | 145 | self.enable_erase(); |
| 97 | |||
| 98 | p.config.write(|w| w.wen().een()); | ||
| 99 | self.wait_ready(); | 146 | self.wait_ready(); |
| 100 | 147 | ||
| 101 | for page in (from..to).step_by(PAGE_SIZE) { | 148 | for page_addr in (from..to).step_by(PAGE_SIZE) { |
| 102 | p.erasepage().write(|w| unsafe { w.bits(page) }); | 149 | self.erase_page(page_addr); |
| 103 | self.wait_ready(); | 150 | self.wait_ready(); |
| 104 | } | 151 | } |
| 105 | 152 | ||
| 106 | p.config.reset(); | 153 | self.enable_read(); |
| 107 | self.wait_ready(); | 154 | self.wait_ready(); |
| 108 | 155 | ||
| 109 | Ok(()) | 156 | Ok(()) |
| @@ -117,9 +164,7 @@ impl<'d> NorFlash for Nvmc<'d> { | |||
| 117 | return Err(Error::Unaligned); | 164 | return Err(Error::Unaligned); |
| 118 | } | 165 | } |
| 119 | 166 | ||
| 120 | let p = Self::regs(); | 167 | self.enable_write(); |
| 121 | |||
| 122 | p.config.write(|w| w.wen().wen()); | ||
| 123 | self.wait_ready(); | 168 | self.wait_ready(); |
| 124 | 169 | ||
| 125 | unsafe { | 170 | unsafe { |
| @@ -129,11 +174,11 @@ impl<'d> NorFlash for Nvmc<'d> { | |||
| 129 | for i in 0..words { | 174 | for i in 0..words { |
| 130 | let w = ptr::read_unaligned(p_src.add(i)); | 175 | let w = ptr::read_unaligned(p_src.add(i)); |
| 131 | ptr::write_volatile(p_dst.add(i), w); | 176 | ptr::write_volatile(p_dst.add(i), w); |
| 132 | self.wait_ready(); | 177 | self.wait_ready_write(); |
| 133 | } | 178 | } |
| 134 | } | 179 | } |
| 135 | 180 | ||
| 136 | p.config.reset(); | 181 | self.enable_read(); |
| 137 | self.wait_ready(); | 182 | self.wait_ready(); |
| 138 | 183 | ||
| 139 | Ok(()) | 184 | Ok(()) |
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index c2c54fba9..1fc717fd1 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs | |||
| @@ -1,66 +1,71 @@ | |||
| 1 | //! Pulse Density Modulation (PDM) mirophone driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 5 | use core::marker::PhantomData; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 7 | use core::task::Poll; |
| 5 | 8 | ||
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 7 | use embassy_hal_common::drop::OnDrop; | 9 | use embassy_hal_common::drop::OnDrop; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use futures::future::poll_fn; | 11 | use futures::future::poll_fn; |
| 10 | use pac::{pdm, PDM}; | ||
| 11 | use pdm::mode::{EDGE_A, OPERATION_A}; | ||
| 12 | pub use pdm::pdmclkctrl::FREQ_A as Frequency; | ||
| 13 | pub use pdm::ratio::RATIO_A as Ratio; | ||
| 14 | use fixed::types::I7F1; | 12 | use fixed::types::I7F1; |
| 15 | 13 | ||
| 16 | use crate::interrupt::InterruptExt; | 14 | use crate::chip::EASY_DMA_SIZE; |
| 17 | use crate::gpio::Pin as GpioPin; | 15 | use crate::gpio::sealed::Pin; |
| 18 | use crate::{interrupt, pac, peripherals, Peripheral}; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 17 | use crate::interrupt::typelevel::Interrupt; | ||
| 18 | use crate::{interrupt, Peripheral}; | ||
| 19 | use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; | ||
| 20 | pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; | ||
| 21 | pub use crate::pac::pdm::ratio::RATIO_A as Ratio; | ||
| 22 | |||
| 23 | /// Interrupt handler. | ||
| 24 | pub struct InterruptHandler<T: Instance> { | ||
| 25 | _phantom: PhantomData<T>, | ||
| 26 | } | ||
| 19 | 27 | ||
| 20 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 28 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 29 | unsafe fn on_interrupt() { |
| 22 | #[non_exhaustive] | 30 | let r = T::regs(); |
| 23 | pub enum Error {} | 31 | |
| 32 | if r.events_end.read().bits() != 0 { | ||
| 33 | r.intenclr.write(|w| w.end().clear()); | ||
| 34 | } | ||
| 24 | 35 | ||
| 25 | /// One-shot and continuous PDM. | 36 | if r.events_started.read().bits() != 0 { |
| 26 | pub struct Pdm<'d> { | 37 | r.intenclr.write(|w| w.started().clear()); |
| 27 | _p: PeripheralRef<'d, peripherals::PDM>, | 38 | } |
| 39 | |||
| 40 | if r.events_stopped.read().bits() != 0 { | ||
| 41 | r.intenclr.write(|w| w.stopped().clear()); | ||
| 42 | } | ||
| 43 | |||
| 44 | T::state().waker.wake(); | ||
| 45 | } | ||
| 28 | } | 46 | } |
| 29 | 47 | ||
| 30 | static WAKER: AtomicWaker = AtomicWaker::new(); | 48 | /// PDM microphone interface |
| 49 | pub struct Pdm<'d, T: Instance> { | ||
| 50 | _peri: PeripheralRef<'d, T>, | ||
| 51 | } | ||
| 31 | 52 | ||
| 32 | /// Used to configure the PDM peripheral. | 53 | /// PDM error. |
| 33 | /// | 54 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 34 | /// See the `Default` impl for suitable default values. | 55 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 35 | #[non_exhaustive] | 56 | #[non_exhaustive] |
| 36 | pub struct Config { | 57 | pub enum Error { |
| 37 | /// Clock frequency | 58 | /// Buffer is too long. |
| 38 | pub frequency: Frequency, | 59 | BufferTooLong, |
| 39 | /// Clock ratio | 60 | /// Buffer is empty |
| 40 | pub ratio: Ratio, | 61 | BufferZeroLength, |
| 41 | /// Channels | 62 | /// PDM is not running |
| 42 | pub channels: Channels, | 63 | NotRunning, |
| 43 | /// Edge to sample on | 64 | /// PDM is already running |
| 44 | pub left_edge: Edge, | 65 | AlreadyRunning, |
| 45 | /// Gain left in dB | ||
| 46 | pub gain_left: I7F1, | ||
| 47 | /// Gain right in dB | ||
| 48 | pub gain_right: I7F1, | ||
| 49 | } | 66 | } |
| 50 | 67 | ||
| 51 | impl Default for Config { | 68 | static DUMMY_BUFFER: [i16; 1] = [0; 1]; |
| 52 | /// Default configuration for single channel sampling. | ||
| 53 | fn default() -> Self { | ||
| 54 | Self { | ||
| 55 | frequency: Frequency::DEFAULT, | ||
| 56 | ratio: Ratio::RATIO80, | ||
| 57 | channels: Channels::Stereo, | ||
| 58 | left_edge: Edge::FallingEdge, | ||
| 59 | gain_left: I7F1::ZERO, | ||
| 60 | gain_right: I7F1::ZERO, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | 69 | ||
| 65 | /// The state of a continuously running sampler. While it reflects | 70 | /// The state of a continuously running sampler. While it reflects |
| 66 | /// the progress of a sampler, it also signals what should be done | 71 | /// the progress of a sampler, it also signals what should be done |
| @@ -68,69 +73,66 @@ impl Default for Config { | |||
| 68 | /// can then tear down its infrastructure. | 73 | /// can then tear down its infrastructure. |
| 69 | #[derive(PartialEq)] | 74 | #[derive(PartialEq)] |
| 70 | pub enum SamplerState { | 75 | pub enum SamplerState { |
| 76 | /// The sampler processed the samples and is ready for more. | ||
| 71 | Sampled, | 77 | Sampled, |
| 78 | /// The sampler is done processing samples. | ||
| 72 | Stopped, | 79 | Stopped, |
| 73 | } | 80 | } |
| 74 | 81 | ||
| 75 | impl<'d> Pdm<'d> { | 82 | impl<'d, T: Instance> Pdm<'d, T> { |
| 83 | /// Create PDM driver | ||
| 76 | pub fn new( | 84 | pub fn new( |
| 77 | pdm: impl Peripheral<P = peripherals::PDM> + 'd, | 85 | pdm: impl Peripheral<P = T> + 'd, |
| 78 | irq: impl Peripheral<P = interrupt::PDM> + 'd, | 86 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 79 | data: impl Peripheral<P = impl GpioPin> + 'd, | 87 | clk: impl Peripheral<P = impl GpioPin> + 'd, |
| 80 | clock: impl Peripheral<P = impl GpioPin> + 'd, | 88 | din: impl Peripheral<P = impl GpioPin> + 'd, |
| 89 | config: Config, | ||
| 90 | ) -> Self { | ||
| 91 | into_ref!(pdm, clk, din); | ||
| 92 | Self::new_inner(pdm, clk.map_into(), din.map_into(), config) | ||
| 93 | } | ||
| 94 | |||
| 95 | fn new_inner( | ||
| 96 | pdm: PeripheralRef<'d, T>, | ||
| 97 | clk: PeripheralRef<'d, AnyPin>, | ||
| 98 | din: PeripheralRef<'d, AnyPin>, | ||
| 81 | config: Config, | 99 | config: Config, |
| 82 | ) -> Self { | 100 | ) -> Self { |
| 83 | into_ref!(pdm, irq, data, clock); | 101 | into_ref!(pdm); |
| 84 | 102 | ||
| 85 | let r = unsafe { &*PDM::ptr() }; | 103 | let r = T::regs(); |
| 86 | 104 | ||
| 87 | let Config { frequency, ratio, channels, left_edge, gain_left, gain_right } = config; | 105 | // setup gpio pins |
| 106 | din.conf().write(|w| w.input().set_bit()); | ||
| 107 | r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); | ||
| 108 | clk.set_low(); | ||
| 109 | clk.conf().write(|w| w.dir().output()); | ||
| 110 | r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); | ||
| 88 | 111 | ||
| 89 | // Configure channels | 112 | // configure |
| 90 | r.enable.write(|w| w.enable().enabled()); | 113 | r.pdmclkctrl.write(|w| w.freq().variant(config.frequency)); |
| 91 | r.pdmclkctrl.write(|w| w.freq().variant(frequency)); | 114 | r.ratio.write(|w| w.ratio().variant(config.ratio)); |
| 92 | r.ratio.write(|w| w.ratio().variant(ratio)); | ||
| 93 | r.mode.write(|w| { | 115 | r.mode.write(|w| { |
| 94 | w.operation().variant(channels.into()); | 116 | w.operation().variant(config.operation_mode.into()); |
| 95 | w.edge().variant(left_edge.into()); | 117 | w.edge().variant(config.edge.into()); |
| 96 | w | 118 | w |
| 97 | }); | 119 | }); |
| 98 | 120 | ||
| 99 | Self::_set_gain(r, gain_left, gain_right); | 121 | Self::_set_gain(r, config.gain_left, config.gain_right); |
| 100 | |||
| 101 | r.psel.din.write(|w| unsafe { w.bits(data.psel_bits()) }); | ||
| 102 | r.psel.clk.write(|w| unsafe { w.bits(clock.psel_bits()) }); | ||
| 103 | 122 | ||
| 104 | // Disable all events interrupts | 123 | // Disable all events interrupts |
| 105 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | 124 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); |
| 106 | 125 | ||
| 107 | irq.set_handler(Self::on_interrupt); | 126 | // IRQ |
| 108 | irq.unpend(); | 127 | T::Interrupt::unpend(); |
| 109 | irq.enable(); | 128 | unsafe { T::Interrupt::enable() }; |
| 110 | |||
| 111 | Self { _p: pdm } | ||
| 112 | } | ||
| 113 | |||
| 114 | fn on_interrupt(_ctx: *mut ()) { | ||
| 115 | let r = Self::regs(); | ||
| 116 | |||
| 117 | if r.events_end.read().bits() != 0 { | ||
| 118 | r.intenclr.write(|w| w.end().clear()); | ||
| 119 | WAKER.wake(); | ||
| 120 | } | ||
| 121 | 129 | ||
| 122 | if r.events_started.read().bits() != 0 { | 130 | r.enable.write(|w| w.enable().set_bit()); |
| 123 | r.intenclr.write(|w| w.started().clear()); | ||
| 124 | WAKER.wake(); | ||
| 125 | } | ||
| 126 | 131 | ||
| 127 | if r.events_stopped.read().bits() != 0 { | 132 | Self { _peri: pdm } |
| 128 | r.intenclr.write(|w| w.stopped().clear()); | ||
| 129 | WAKER.wake(); | ||
| 130 | } | ||
| 131 | } | 133 | } |
| 132 | 134 | ||
| 133 | fn _set_gain(r: &pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { | 135 | fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { |
| 134 | let gain_left = gain_left.saturating_add(I7F1::from_bits(40)).saturating_to_num::<u8>().clamp(0, 0x50); | 136 | let gain_left = gain_left.saturating_add(I7F1::from_bits(40)).saturating_to_num::<u8>().clamp(0, 0x50); |
| 135 | let gain_right = gain_right.saturating_add(I7F1::from_bits(40)).saturating_to_num::<u8>().clamp(0, 0x50); | 137 | let gain_right = gain_right.saturating_add(I7F1::from_bits(40)).saturating_to_num::<u8>().clamp(0, 0x50); |
| 136 | 138 | ||
| @@ -138,81 +140,111 @@ impl<'d> Pdm<'d> { | |||
| 138 | r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); | 140 | r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); |
| 139 | } | 141 | } |
| 140 | 142 | ||
| 143 | /// Adjust the gain of the PDM microphone on the fly | ||
| 141 | pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) { | 144 | pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) { |
| 142 | Self::_set_gain(Self::regs(), gain_left, gain_right) | 145 | Self::_set_gain(T::regs(), gain_left, gain_right) |
| 143 | } | 146 | } |
| 144 | 147 | ||
| 145 | fn regs() -> &'static pdm::RegisterBlock { | 148 | /// Start sampling microphon data into a dummy buffer |
| 146 | unsafe { &*PDM::ptr() } | 149 | /// Usefull to start the microphon and keep it active between recording samples |
| 150 | pub async fn start(&mut self) { | ||
| 151 | let r = T::regs(); | ||
| 152 | |||
| 153 | // start dummy sampling because microphon needs some setup time | ||
| 154 | r.sample | ||
| 155 | .ptr | ||
| 156 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); | ||
| 157 | r.sample | ||
| 158 | .maxcnt | ||
| 159 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||
| 160 | |||
| 161 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 147 | } | 162 | } |
| 148 | 163 | ||
| 149 | /// One shot sampling. If the PDM is configured for multiple channels, the samples will be interleaved. | 164 | /// Stop sampling microphon data inta a dummy buffer |
| 150 | /// The first samples from the PDM peripheral and microphone usually contain garbage data, so the discard parameter sets the number of complete buffers to discard before returning. | 165 | pub async fn stop(&mut self) { |
| 151 | pub async fn sample<const N: usize>(&mut self, mut discard: usize, buf: &mut [i16; N]) { | 166 | let r = T::regs(); |
| 152 | let r = Self::regs(); | 167 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); |
| 168 | r.events_started.reset(); | ||
| 169 | } | ||
| 153 | 170 | ||
| 154 | // Set up the DMA | 171 | /// Sample data into the given buffer. |
| 155 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(buf.as_mut_ptr() as u32) }); | 172 | pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { |
| 156 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) }); | 173 | if buffer.len() == 0 { |
| 174 | return Err(Error::BufferZeroLength); | ||
| 175 | } | ||
| 176 | if buffer.len() > EASY_DMA_SIZE { | ||
| 177 | return Err(Error::BufferTooLong); | ||
| 178 | } | ||
| 157 | 179 | ||
| 158 | // Reset and enable the events | 180 | let r = T::regs(); |
| 159 | r.events_end.reset(); | ||
| 160 | r.events_stopped.reset(); | ||
| 161 | r.intenset.write(|w| { | ||
| 162 | w.end().set(); | ||
| 163 | w.stopped().set(); | ||
| 164 | w | ||
| 165 | }); | ||
| 166 | 181 | ||
| 167 | // Don't reorder the start event before the previous writes. Hopefully self | 182 | if r.events_started.read().bits() == 0 { |
| 168 | // wouldn't happen anyway. | 183 | return Err(Error::NotRunning); |
| 169 | compiler_fence(Ordering::SeqCst); | 184 | } |
| 170 | 185 | ||
| 171 | r.tasks_start.write(|w| w.tasks_start().set_bit()); | 186 | let drop = OnDrop::new(move || { |
| 187 | r.intenclr.write(|w| w.end().clear()); | ||
| 188 | r.events_stopped.reset(); | ||
| 172 | 189 | ||
| 173 | let ondrop = OnDrop::new(|| { | 190 | // reset to dummy buffer |
| 174 | r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | 191 | r.sample |
| 175 | // N.B. It would be better if this were async, but Drop only support sync code. | 192 | .ptr |
| 176 | while r.events_stopped.read().bits() != 0 {} | 193 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); |
| 194 | r.sample | ||
| 195 | .maxcnt | ||
| 196 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||
| 197 | |||
| 198 | while r.events_stopped.read().bits() == 0 {} | ||
| 177 | }); | 199 | }); |
| 178 | 200 | ||
| 179 | // Wait for 'end' event. | 201 | // setup user buffer |
| 180 | poll_fn(|cx| { | 202 | let ptr = buffer.as_ptr(); |
| 181 | let r = Self::regs(); | 203 | let len = buffer.len(); |
| 204 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); | ||
| 205 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); | ||
| 182 | 206 | ||
| 183 | WAKER.register(cx.waker()); | 207 | // wait till the current sample is finished and the user buffer sample is started |
| 208 | Self::wait_for_sample().await; | ||
| 184 | 209 | ||
| 185 | if r.events_end.read().bits() != 0 { | 210 | // reset the buffer back to the dummy buffer |
| 186 | compiler_fence(Ordering::SeqCst); | 211 | r.sample |
| 187 | // END means the whole buffer has been received. | 212 | .ptr |
| 188 | r.events_end.reset(); | 213 | .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); |
| 189 | r.intenset.write(|w| w.end().set()); | 214 | r.sample |
| 215 | .maxcnt | ||
| 216 | .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); | ||
| 190 | 217 | ||
| 191 | if discard > 0 { | 218 | // wait till the user buffer is sampled |
| 192 | discard -= 1; | 219 | Self::wait_for_sample().await; |
| 193 | } else { | 220 | |
| 194 | // Note that the beginning of the buffer might be overwritten before the task fully stops :( | 221 | drop.defuse(); |
| 195 | r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | 222 | |
| 196 | } | 223 | Ok(()) |
| 197 | } | 224 | } |
| 198 | if r.events_stopped.read().bits() != 0 { | 225 | |
| 226 | async fn wait_for_sample() { | ||
| 227 | let r = T::regs(); | ||
| 228 | |||
| 229 | r.events_end.reset(); | ||
| 230 | r.intenset.write(|w| w.end().set()); | ||
| 231 | |||
| 232 | compiler_fence(Ordering::SeqCst); | ||
| 233 | |||
| 234 | poll_fn(|cx| { | ||
| 235 | T::state().waker.register(cx.waker()); | ||
| 236 | if r.events_end.read().bits() != 0 { | ||
| 199 | return Poll::Ready(()); | 237 | return Poll::Ready(()); |
| 200 | } | 238 | } |
| 201 | |||
| 202 | Poll::Pending | 239 | Poll::Pending |
| 203 | }) | 240 | }) |
| 204 | .await; | 241 | .await; |
| 205 | ondrop.defuse(); | 242 | |
| 243 | compiler_fence(Ordering::SeqCst); | ||
| 206 | } | 244 | } |
| 207 | 245 | ||
| 208 | /// Continuous sampling with double buffers. | 246 | /// Continuous sampling with double buffers. |
| 209 | /// | 247 | /// |
| 210 | /// A TIMER and two PPI peripherals are passed in so that precise sampling | ||
| 211 | /// can be attained. The sampling interval is expressed by selecting a | ||
| 212 | /// timer clock frequency to use along with a counter threshold to be reached. | ||
| 213 | /// For example, 1KHz can be achieved using a frequency of 1MHz and a counter | ||
| 214 | /// threshold of 1000. | ||
| 215 | /// | ||
| 216 | /// A sampler closure is provided that receives the buffer of samples, noting | 248 | /// A sampler closure is provided that receives the buffer of samples, noting |
| 217 | /// that the size of this buffer can be less than the original buffer's size. | 249 | /// that the size of this buffer can be less than the original buffer's size. |
| 218 | /// A command is return from the closure that indicates whether the sampling | 250 | /// A command is return from the closure that indicates whether the sampling |
| @@ -226,10 +258,14 @@ impl<'d> Pdm<'d> { | |||
| 226 | &mut self, | 258 | &mut self, |
| 227 | bufs: &mut [[i16; N]; 2], | 259 | bufs: &mut [[i16; N]; 2], |
| 228 | mut sampler: S, | 260 | mut sampler: S, |
| 229 | ) where | 261 | ) -> Result<(), Error> where |
| 230 | S: FnMut(&[i16; N]) -> SamplerState, | 262 | S: FnMut(&[i16; N]) -> SamplerState, |
| 231 | { | 263 | { |
| 232 | let r = Self::regs(); | 264 | let r = T::regs(); |
| 265 | |||
| 266 | if r.events_started.read().bits() != 0 { | ||
| 267 | return Err(Error::AlreadyRunning); | ||
| 268 | } | ||
| 233 | 269 | ||
| 234 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) }); | 270 | r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) }); |
| 235 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) }); | 271 | r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) }); |
| @@ -255,7 +291,7 @@ impl<'d> Pdm<'d> { | |||
| 255 | 291 | ||
| 256 | let mut done = false; | 292 | let mut done = false; |
| 257 | 293 | ||
| 258 | let ondrop = OnDrop::new(|| { | 294 | let drop = OnDrop::new(|| { |
| 259 | r.tasks_stop.write(|w| w.tasks_stop().set_bit()); | 295 | r.tasks_stop.write(|w| w.tasks_stop().set_bit()); |
| 260 | // N.B. It would be better if this were async, but Drop only support sync code. | 296 | // N.B. It would be better if this were async, but Drop only support sync code. |
| 261 | while r.events_stopped.read().bits() != 0 {} | 297 | while r.events_stopped.read().bits() != 0 {} |
| @@ -263,9 +299,9 @@ impl<'d> Pdm<'d> { | |||
| 263 | 299 | ||
| 264 | // Wait for events and complete when the sampler indicates it has had enough. | 300 | // Wait for events and complete when the sampler indicates it has had enough. |
| 265 | poll_fn(|cx| { | 301 | poll_fn(|cx| { |
| 266 | let r = Self::regs(); | 302 | let r = T::regs(); |
| 267 | 303 | ||
| 268 | WAKER.register(cx.waker()); | 304 | T::state().waker.register(cx.waker()); |
| 269 | 305 | ||
| 270 | if r.events_end.read().bits() != 0 { | 306 | if r.events_end.read().bits() != 0 { |
| 271 | compiler_fence(Ordering::SeqCst); | 307 | compiler_fence(Ordering::SeqCst); |
| @@ -301,43 +337,130 @@ impl<'d> Pdm<'d> { | |||
| 301 | Poll::Pending | 337 | Poll::Pending |
| 302 | }) | 338 | }) |
| 303 | .await; | 339 | .await; |
| 304 | ondrop.defuse(); | 340 | drop.defuse(); |
| 341 | Ok(()) | ||
| 305 | } | 342 | } |
| 306 | } | 343 | } |
| 307 | 344 | ||
| 308 | impl<'d> Drop for Pdm<'d> { | 345 | /// PDM microphone driver Config |
| 309 | fn drop(&mut self) { | 346 | pub struct Config { |
| 310 | let r = Self::regs(); | 347 | /// Use stero or mono operation |
| 311 | r.enable.write(|w| w.enable().disabled()); | 348 | pub operation_mode: OperationMode, |
| 349 | /// On which edge the left channel should be samples | ||
| 350 | pub edge: Edge, | ||
| 351 | /// Clock frequency | ||
| 352 | pub frequency: Frequency, | ||
| 353 | /// Clock ratio | ||
| 354 | pub ratio: Ratio, | ||
| 355 | /// Gain left in dB | ||
| 356 | pub gain_left: I7F1, | ||
| 357 | /// Gain right in dB | ||
| 358 | pub gain_right: I7F1, | ||
| 359 | } | ||
| 360 | |||
| 361 | impl Default for Config { | ||
| 362 | fn default() -> Self { | ||
| 363 | Self { | ||
| 364 | operation_mode: OperationMode::Mono, | ||
| 365 | edge: Edge::LeftFalling, | ||
| 366 | frequency: Frequency::DEFAULT, | ||
| 367 | ratio: Ratio::RATIO80, | ||
| 368 | gain_left: I7F1::ZERO, | ||
| 369 | gain_right: I7F1::ZERO, | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | /// PDM operation mode. | ||
| 375 | #[derive(PartialEq)] | ||
| 376 | pub enum OperationMode { | ||
| 377 | /// Mono (1 channel) | ||
| 378 | Mono, | ||
| 379 | /// Stereo (2 channels) | ||
| 380 | Stereo, | ||
| 381 | } | ||
| 382 | |||
| 383 | impl From<OperationMode> for OPERATION_A { | ||
| 384 | fn from(mode: OperationMode) -> Self { | ||
| 385 | match mode { | ||
| 386 | OperationMode::Mono => OPERATION_A::MONO, | ||
| 387 | OperationMode::Stereo => OPERATION_A::STEREO, | ||
| 388 | } | ||
| 312 | } | 389 | } |
| 313 | } | 390 | } |
| 314 | 391 | ||
| 315 | #[derive(Clone, Copy, PartialEq)] | 392 | /// PDM edge polarity |
| 393 | #[derive(PartialEq)] | ||
| 316 | pub enum Edge { | 394 | pub enum Edge { |
| 317 | FallingEdge, | 395 | /// Left edge is rising |
| 318 | RisingEdge, | 396 | LeftRising, |
| 397 | /// Left edge is falling | ||
| 398 | LeftFalling, | ||
| 319 | } | 399 | } |
| 320 | 400 | ||
| 321 | impl From<Edge> for EDGE_A { | 401 | impl From<Edge> for EDGE_A { |
| 322 | fn from(edge: Edge) -> Self { | 402 | fn from(edge: Edge) -> Self { |
| 323 | match edge { | 403 | match edge { |
| 324 | Edge::FallingEdge => EDGE_A::LEFTFALLING, | 404 | Edge::LeftRising => EDGE_A::LEFT_RISING, |
| 325 | Edge::RisingEdge => EDGE_A::LEFTRISING, | 405 | Edge::LeftFalling => EDGE_A::LEFT_FALLING, |
| 326 | } | 406 | } |
| 327 | } | 407 | } |
| 328 | } | 408 | } |
| 329 | 409 | ||
| 330 | #[derive(Clone, Copy, PartialEq)] | 410 | impl<'d, T: Instance> Drop for Pdm<'d, T> { |
| 331 | pub enum Channels { | 411 | fn drop(&mut self) { |
| 332 | Stereo, | 412 | let r = T::regs(); |
| 333 | Mono, | 413 | |
| 414 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 415 | |||
| 416 | r.enable.write(|w| w.enable().disabled()); | ||
| 417 | |||
| 418 | r.psel.din.reset(); | ||
| 419 | r.psel.clk.reset(); | ||
| 420 | } | ||
| 334 | } | 421 | } |
| 335 | 422 | ||
| 336 | impl From<Channels> for OPERATION_A { | 423 | pub(crate) mod sealed { |
| 337 | fn from(ch: Channels) -> Self { | 424 | use embassy_sync::waitqueue::AtomicWaker; |
| 338 | match ch { | 425 | |
| 339 | Channels::Stereo => OPERATION_A::STEREO, | 426 | /// Peripheral static state |
| 340 | Channels::Mono => OPERATION_A::MONO, | 427 | pub struct State { |
| 428 | pub waker: AtomicWaker, | ||
| 429 | } | ||
| 430 | |||
| 431 | impl State { | ||
| 432 | pub const fn new() -> Self { | ||
| 433 | Self { | ||
| 434 | waker: AtomicWaker::new(), | ||
| 435 | } | ||
| 341 | } | 436 | } |
| 342 | } | 437 | } |
| 438 | |||
| 439 | pub trait Instance { | ||
| 440 | fn regs() -> &'static crate::pac::pdm::RegisterBlock; | ||
| 441 | fn state() -> &'static State; | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | /// PDM peripheral instance. | ||
| 446 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 447 | /// Interrupt for this peripheral. | ||
| 448 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 449 | } | ||
| 450 | |||
| 451 | macro_rules! impl_pdm { | ||
| 452 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 453 | impl crate::pdm::sealed::Instance for peripherals::$type { | ||
| 454 | fn regs() -> &'static crate::pac::pdm::RegisterBlock { | ||
| 455 | unsafe { &*pac::$pac_type::ptr() } | ||
| 456 | } | ||
| 457 | fn state() -> &'static crate::pdm::sealed::State { | ||
| 458 | static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); | ||
| 459 | &STATE | ||
| 460 | } | ||
| 461 | } | ||
| 462 | impl crate::pdm::Instance for peripherals::$type { | ||
| 463 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 464 | } | ||
| 465 | }; | ||
| 343 | } \ No newline at end of file | 466 | } \ No newline at end of file |
diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index de856c0ca..40ccb2f09 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs | |||
| @@ -6,18 +6,20 @@ use crate::{pac, Peripheral}; | |||
| 6 | const DPPI_ENABLE_BIT: u32 = 0x8000_0000; | 6 | const DPPI_ENABLE_BIT: u32 = 0x8000_0000; |
| 7 | const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; | 7 | const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; |
| 8 | 8 | ||
| 9 | fn regs() -> &'static pac::dppic::RegisterBlock { | 9 | pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock { |
| 10 | unsafe { &*pac::DPPIC::ptr() } | 10 | unsafe { &*pac::DPPIC::ptr() } |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { | 13 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { |
| 14 | pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self { | 14 | /// Configure PPI channel to trigger `task` on `event`. |
| 15 | pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self { | ||
| 15 | Ppi::new_many_to_many(ch, [event], [task]) | 16 | Ppi::new_many_to_many(ch, [event], [task]) |
| 16 | } | 17 | } |
| 17 | } | 18 | } |
| 18 | 19 | ||
| 19 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { | 20 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { |
| 20 | pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { | 21 | /// Configure PPI channel to trigger both `task1` and `task2` on `event`. |
| 22 | pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { | ||
| 21 | Ppi::new_many_to_many(ch, [event], [task1, task2]) | 23 | Ppi::new_many_to_many(ch, [event], [task1, task2]) |
| 22 | } | 24 | } |
| 23 | } | 25 | } |
| @@ -25,10 +27,11 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { | |||
| 25 | impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usize> | 27 | impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usize> |
| 26 | Ppi<'d, C, EVENT_COUNT, TASK_COUNT> | 28 | Ppi<'d, C, EVENT_COUNT, TASK_COUNT> |
| 27 | { | 29 | { |
| 30 | /// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires. | ||
| 28 | pub fn new_many_to_many( | 31 | pub fn new_many_to_many( |
| 29 | ch: impl Peripheral<P = C> + 'd, | 32 | ch: impl Peripheral<P = C> + 'd, |
| 30 | events: [Event; EVENT_COUNT], | 33 | events: [Event<'d>; EVENT_COUNT], |
| 31 | tasks: [Task; TASK_COUNT], | 34 | tasks: [Task<'d>; TASK_COUNT], |
| 32 | ) -> Self { | 35 | ) -> Self { |
| 33 | into_ref!(ch); | 36 | into_ref!(ch); |
| 34 | 37 | ||
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 8f5ed14cd..ff6593bd5 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | //! HAL interface for the PPI and DPPI peripheral. | 3 | //! Programmable Peripheral Interconnect (PPI/DPPI) driver. |
| 4 | //! | 4 | //! |
| 5 | //! The (Distributed) Programmable Peripheral Interconnect interface allows for an autonomous interoperability | 5 | //! The (Distributed) Programmable Peripheral Interconnect interface allows for an autonomous interoperability |
| 6 | //! between peripherals through their events and tasks. There are fixed PPI channels and fully | 6 | //! between peripherals through their events and tasks. There are fixed PPI channels and fully |
| @@ -15,24 +15,107 @@ | |||
| 15 | //! many tasks and events, but any single task or event can only be coupled with one channel. | 15 | //! many tasks and events, but any single task or event can only be coupled with one channel. |
| 16 | //! | 16 | //! |
| 17 | 17 | ||
| 18 | use core::marker::PhantomData; | ||
| 18 | use core::ptr::NonNull; | 19 | use core::ptr::NonNull; |
| 19 | 20 | ||
| 20 | use embassy_hal_common::{impl_peripheral, PeripheralRef}; | 21 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 21 | 22 | ||
| 22 | use crate::{peripherals, Peripheral}; | 23 | use crate::{peripherals, Peripheral}; |
| 23 | 24 | ||
| 24 | #[cfg(feature = "_dppi")] | 25 | #[cfg_attr(feature = "_dppi", path = "dppi.rs")] |
| 25 | mod dppi; | 26 | #[cfg_attr(feature = "_ppi", path = "ppi.rs")] |
| 26 | #[cfg(feature = "_ppi")] | 27 | mod _version; |
| 27 | mod ppi; | 28 | pub(crate) use _version::*; |
| 28 | 29 | ||
| 29 | /// An instance of the Programmable peripheral interconnect on nRF devices. | 30 | /// PPI channel driver. |
| 30 | pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { | 31 | pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { |
| 31 | ch: PeripheralRef<'d, C>, | 32 | ch: PeripheralRef<'d, C>, |
| 32 | #[cfg(feature = "_dppi")] | 33 | #[cfg(feature = "_dppi")] |
| 33 | events: [Event; EVENT_COUNT], | 34 | events: [Event<'d>; EVENT_COUNT], |
| 34 | #[cfg(feature = "_dppi")] | 35 | #[cfg(feature = "_dppi")] |
| 35 | tasks: [Task; TASK_COUNT], | 36 | tasks: [Task<'d>; TASK_COUNT], |
| 37 | } | ||
| 38 | |||
| 39 | /// PPI channel group driver. | ||
| 40 | pub struct PpiGroup<'d, G: Group> { | ||
| 41 | g: PeripheralRef<'d, G>, | ||
| 42 | } | ||
| 43 | |||
| 44 | impl<'d, G: Group> PpiGroup<'d, G> { | ||
| 45 | /// Create a new PPI group driver. | ||
| 46 | /// | ||
| 47 | /// The group is initialized as containing no channels. | ||
| 48 | pub fn new(g: impl Peripheral<P = G> + 'd) -> Self { | ||
| 49 | into_ref!(g); | ||
| 50 | |||
| 51 | let r = regs(); | ||
| 52 | let n = g.number(); | ||
| 53 | r.chg[n].write(|w| unsafe { w.bits(0) }); | ||
| 54 | |||
| 55 | Self { g } | ||
| 56 | } | ||
| 57 | |||
| 58 | /// Add a PPI channel to this group. | ||
| 59 | /// | ||
| 60 | /// If the channel is already in the group, this is a no-op. | ||
| 61 | pub fn add_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>( | ||
| 62 | &mut self, | ||
| 63 | ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, | ||
| 64 | ) { | ||
| 65 | let r = regs(); | ||
| 66 | let ng = self.g.number(); | ||
| 67 | let nc = ch.ch.number(); | ||
| 68 | r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) }); | ||
| 69 | } | ||
| 70 | |||
| 71 | /// Remove a PPI channel from this group. | ||
| 72 | /// | ||
| 73 | /// If the channel is already not in the group, this is a no-op. | ||
| 74 | pub fn remove_channel<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize>( | ||
| 75 | &mut self, | ||
| 76 | ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, | ||
| 77 | ) { | ||
| 78 | let r = regs(); | ||
| 79 | let ng = self.g.number(); | ||
| 80 | let nc = ch.ch.number(); | ||
| 81 | r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) }); | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Enable all the channels in this group. | ||
| 85 | pub fn enable_all(&mut self) { | ||
| 86 | let n = self.g.number(); | ||
| 87 | regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) }); | ||
| 88 | } | ||
| 89 | |||
| 90 | /// Disable all the channels in this group. | ||
| 91 | pub fn disable_all(&mut self) { | ||
| 92 | let n = self.g.number(); | ||
| 93 | regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) }); | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Get a reference to the "enable all" task. | ||
| 97 | /// | ||
| 98 | /// When triggered, it will enable all the channels in this group. | ||
| 99 | pub fn task_enable_all(&self) -> Task<'d> { | ||
| 100 | let n = self.g.number(); | ||
| 101 | Task::from_reg(®s().tasks_chg[n].en) | ||
| 102 | } | ||
| 103 | |||
| 104 | /// Get a reference to the "disable all" task. | ||
| 105 | /// | ||
| 106 | /// When triggered, it will disable all the channels in this group. | ||
| 107 | pub fn task_disable_all(&self) -> Task<'d> { | ||
| 108 | let n = self.g.number(); | ||
| 109 | Task::from_reg(®s().tasks_chg[n].dis) | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | impl<'d, G: Group> Drop for PpiGroup<'d, G> { | ||
| 114 | fn drop(&mut self) { | ||
| 115 | let r = regs(); | ||
| 116 | let n = self.g.number(); | ||
| 117 | r.chg[n].write(|w| unsafe { w.bits(0) }); | ||
| 118 | } | ||
| 36 | } | 119 | } |
| 37 | 120 | ||
| 38 | #[cfg(feature = "_dppi")] | 121 | #[cfg(feature = "_dppi")] |
| @@ -43,20 +126,28 @@ const REGISTER_DPPI_CONFIG_OFFSET: usize = 0x80 / core::mem::size_of::<u32>(); | |||
| 43 | /// When a task is subscribed to a PPI channel, it will run when the channel is triggered by | 126 | /// When a task is subscribed to a PPI channel, it will run when the channel is triggered by |
| 44 | /// a published event. | 127 | /// a published event. |
| 45 | #[derive(PartialEq, Eq, Clone, Copy)] | 128 | #[derive(PartialEq, Eq, Clone, Copy)] |
| 46 | pub struct Task(NonNull<u32>); | 129 | pub struct Task<'d>(NonNull<u32>, PhantomData<&'d ()>); |
| 47 | 130 | ||
| 48 | impl Task { | 131 | impl<'d> Task<'d> { |
| 49 | /// Create a new `Task` from a task register pointer | 132 | /// Create a new `Task` from a task register pointer |
| 50 | /// | 133 | /// |
| 51 | /// # Safety | 134 | /// # Safety |
| 52 | /// | 135 | /// |
| 53 | /// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral. | 136 | /// `ptr` must be a pointer to a valid `TASKS_*` register from an nRF peripheral. |
| 54 | pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { | 137 | pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { |
| 55 | Self(ptr) | 138 | Self(ptr, PhantomData) |
| 139 | } | ||
| 140 | |||
| 141 | /// Triggers this task. | ||
| 142 | pub fn trigger(&mut self) { | ||
| 143 | unsafe { self.0.as_ptr().write_volatile(1) }; | ||
| 56 | } | 144 | } |
| 57 | 145 | ||
| 58 | pub(crate) fn from_reg<T>(reg: &T) -> Self { | 146 | pub(crate) fn from_reg<T>(reg: &T) -> Self { |
| 59 | Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) | 147 | Self( |
| 148 | unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, | ||
| 149 | PhantomData, | ||
| 150 | ) | ||
| 60 | } | 151 | } |
| 61 | 152 | ||
| 62 | /// Address of subscription register for this task. | 153 | /// Address of subscription register for this task. |
| @@ -69,26 +160,39 @@ impl Task { | |||
| 69 | /// # Safety | 160 | /// # Safety |
| 70 | /// | 161 | /// |
| 71 | /// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. | 162 | /// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. |
| 72 | unsafe impl Send for Task {} | 163 | unsafe impl Send for Task<'_> {} |
| 73 | 164 | ||
| 74 | /// Represents an event that a peripheral can publish. | 165 | /// Represents an event that a peripheral can publish. |
| 75 | /// | 166 | /// |
| 76 | /// An event can be set to publish on a PPI channel when the event happens. | 167 | /// An event can be set to publish on a PPI channel when the event happens. |
| 77 | #[derive(PartialEq, Eq, Clone, Copy)] | 168 | #[derive(PartialEq, Eq, Clone, Copy)] |
| 78 | pub struct Event(NonNull<u32>); | 169 | pub struct Event<'d>(NonNull<u32>, PhantomData<&'d ()>); |
| 79 | 170 | ||
| 80 | impl Event { | 171 | impl<'d> Event<'d> { |
| 81 | /// Create a new `Event` from an event register pointer | 172 | /// Create a new `Event` from an event register pointer |
| 82 | /// | 173 | /// |
| 83 | /// # Safety | 174 | /// # Safety |
| 84 | /// | 175 | /// |
| 85 | /// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral. | 176 | /// `ptr` must be a pointer to a valid `EVENTS_*` register from an nRF peripheral. |
| 86 | pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { | 177 | pub unsafe fn new_unchecked(ptr: NonNull<u32>) -> Self { |
| 87 | Self(ptr) | 178 | Self(ptr, PhantomData) |
| 88 | } | 179 | } |
| 89 | 180 | ||
| 90 | pub(crate) fn from_reg<T>(reg: &T) -> Self { | 181 | pub(crate) fn from_reg<T>(reg: &'d T) -> Self { |
| 91 | Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) | 182 | Self( |
| 183 | unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, | ||
| 184 | PhantomData, | ||
| 185 | ) | ||
| 186 | } | ||
| 187 | |||
| 188 | /// Describes whether this Event is currently in a triggered state. | ||
| 189 | pub fn is_triggered(&self) -> bool { | ||
| 190 | unsafe { self.0.as_ptr().read_volatile() == 1 } | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Clear the current register's triggered state, reverting it to 0. | ||
| 194 | pub fn clear(&mut self) { | ||
| 195 | unsafe { self.0.as_ptr().write_volatile(0) }; | ||
| 92 | } | 196 | } |
| 93 | 197 | ||
| 94 | /// Address of publish register for this event. | 198 | /// Address of publish register for this event. |
| @@ -101,7 +205,7 @@ impl Event { | |||
| 101 | /// # Safety | 205 | /// # Safety |
| 102 | /// | 206 | /// |
| 103 | /// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. | 207 | /// NonNull is not send, but this event is only allowed to point at registers and those exist in any context on the same core. |
| 104 | unsafe impl Send for Event {} | 208 | unsafe impl Send for Event<'_> {} |
| 105 | 209 | ||
| 106 | // ====================== | 210 | // ====================== |
| 107 | // traits | 211 | // traits |
| @@ -112,7 +216,7 @@ pub(crate) mod sealed { | |||
| 112 | } | 216 | } |
| 113 | 217 | ||
| 114 | /// Interface for PPI channels. | 218 | /// Interface for PPI channels. |
| 115 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized { | 219 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static { |
| 116 | /// Returns the number of the channel | 220 | /// Returns the number of the channel |
| 117 | fn number(&self) -> usize; | 221 | fn number(&self) -> usize; |
| 118 | } | 222 | } |
| @@ -130,7 +234,7 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> { | |||
| 130 | } | 234 | } |
| 131 | 235 | ||
| 132 | /// Interface for a group of PPI channels. | 236 | /// Interface for a group of PPI channels. |
| 133 | pub trait Group: sealed::Group + Sized { | 237 | pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static { |
| 134 | /// Returns the number of the group. | 238 | /// Returns the number of the group. |
| 135 | fn number(&self) -> usize; | 239 | fn number(&self) -> usize; |
| 136 | /// Convert into a type erased group. | 240 | /// Convert into a type erased group. |
| @@ -248,6 +352,12 @@ macro_rules! impl_group { | |||
| 248 | $number | 352 | $number |
| 249 | } | 353 | } |
| 250 | } | 354 | } |
| 355 | |||
| 356 | impl From<peripherals::$type> for crate::ppi::AnyGroup { | ||
| 357 | fn from(val: peripherals::$type) -> Self { | ||
| 358 | crate::ppi::Group::degrade(val) | ||
| 359 | } | ||
| 360 | } | ||
| 251 | }; | 361 | }; |
| 252 | } | 362 | } |
| 253 | 363 | ||
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 19abc4e18..1fe898625 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs | |||
| @@ -3,18 +3,18 @@ use embassy_hal_common::into_ref; | |||
| 3 | use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; | 3 | use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task}; |
| 4 | use crate::{pac, Peripheral}; | 4 | use crate::{pac, Peripheral}; |
| 5 | 5 | ||
| 6 | impl Task { | 6 | impl<'d> Task<'d> { |
| 7 | fn reg_val(&self) -> u32 { | 7 | fn reg_val(&self) -> u32 { |
| 8 | self.0.as_ptr() as _ | 8 | self.0.as_ptr() as _ |
| 9 | } | 9 | } |
| 10 | } | 10 | } |
| 11 | impl Event { | 11 | impl<'d> Event<'d> { |
| 12 | fn reg_val(&self) -> u32 { | 12 | fn reg_val(&self) -> u32 { |
| 13 | self.0.as_ptr() as _ | 13 | self.0.as_ptr() as _ |
| 14 | } | 14 | } |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | fn regs() -> &'static pac::ppi::RegisterBlock { | 17 | pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock { |
| 18 | unsafe { &*pac::PPI::ptr() } | 18 | unsafe { &*pac::PPI::ptr() } |
| 19 | } | 19 | } |
| 20 | 20 | ||
| @@ -34,7 +34,7 @@ impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> { | |||
| 34 | 34 | ||
| 35 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { | 35 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { |
| 36 | /// Configure PPI channel to trigger `task` on `event`. | 36 | /// Configure PPI channel to trigger `task` on `event`. |
| 37 | pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event, task: Task) -> Self { | 37 | pub fn new_one_to_one(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task: Task<'d>) -> Self { |
| 38 | into_ref!(ch); | 38 | into_ref!(ch); |
| 39 | 39 | ||
| 40 | let r = regs(); | 40 | let r = regs(); |
| @@ -48,8 +48,8 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { | |||
| 48 | 48 | ||
| 49 | #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task | 49 | #[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task |
| 50 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { | 50 | impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { |
| 51 | /// Configure PPI channel to trigger `task1` and `task2` on `event`. | 51 | /// Configure PPI channel to trigger both `task1` and `task2` on `event`. |
| 52 | pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event, task1: Task, task2: Task) -> Self { | 52 | pub fn new_one_to_two(ch: impl Peripheral<P = C> + 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { |
| 53 | into_ref!(ch); | 53 | into_ref!(ch); |
| 54 | 54 | ||
| 55 | let r = regs(); | 55 | let r = regs(); |
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 5f750a91e..c8c81fa01 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Pulse Width Modulation (PWM) driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 5 | use core::sync::atomic::{compiler_fence, Ordering}; |
| @@ -6,10 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | |||
| 6 | 8 | ||
| 7 | use crate::gpio::sealed::Pin as _; | 9 | use crate::gpio::sealed::Pin as _; |
| 8 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; | 10 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; |
| 9 | use crate::interrupt::Interrupt; | ||
| 10 | use crate::ppi::{Event, Task}; | 11 | use crate::ppi::{Event, Task}; |
| 11 | use crate::util::slice_in_ram_or; | 12 | use crate::util::slice_in_ram_or; |
| 12 | use crate::{pac, Peripheral}; | 13 | use crate::{interrupt, pac, Peripheral}; |
| 13 | 14 | ||
| 14 | /// SimplePwm is the traditional pwm interface you're probably used to, allowing | 15 | /// SimplePwm is the traditional pwm interface you're probably used to, allowing |
| 15 | /// to simply set a duty cycle across up to four channels. | 16 | /// to simply set a duty cycle across up to four channels. |
| @@ -32,6 +33,7 @@ pub struct SequencePwm<'d, T: Instance> { | |||
| 32 | ch3: Option<PeripheralRef<'d, AnyPin>>, | 33 | ch3: Option<PeripheralRef<'d, AnyPin>>, |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 36 | /// PWM error | ||
| 35 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 37 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 36 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 38 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 37 | #[non_exhaustive] | 39 | #[non_exhaustive] |
| @@ -41,7 +43,7 @@ pub enum Error { | |||
| 41 | /// Min Sequence count is 1 | 43 | /// Min Sequence count is 1 |
| 42 | SequenceTimesAtLeastOne, | 44 | SequenceTimesAtLeastOne, |
| 43 | /// EasyDMA can only read from data memory, read only buffers in flash will fail. | 45 | /// EasyDMA can only read from data memory, read only buffers in flash will fail. |
| 44 | DMABufferNotInDataMemory, | 46 | BufferNotInRAM, |
| 45 | } | 47 | } |
| 46 | 48 | ||
| 47 | const MAX_SEQUENCE_LEN: usize = 32767; | 49 | const MAX_SEQUENCE_LEN: usize = 32767; |
| @@ -179,7 +181,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 179 | 181 | ||
| 180 | /// Returns reference to `Stopped` event endpoint for PPI. | 182 | /// Returns reference to `Stopped` event endpoint for PPI. |
| 181 | #[inline(always)] | 183 | #[inline(always)] |
| 182 | pub fn event_stopped(&self) -> Event { | 184 | pub fn event_stopped(&self) -> Event<'d> { |
| 183 | let r = T::regs(); | 185 | let r = T::regs(); |
| 184 | 186 | ||
| 185 | Event::from_reg(&r.events_stopped) | 187 | Event::from_reg(&r.events_stopped) |
| @@ -187,7 +189,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 187 | 189 | ||
| 188 | /// Returns reference to `LoopsDone` event endpoint for PPI. | 190 | /// Returns reference to `LoopsDone` event endpoint for PPI. |
| 189 | #[inline(always)] | 191 | #[inline(always)] |
| 190 | pub fn event_loops_done(&self) -> Event { | 192 | pub fn event_loops_done(&self) -> Event<'d> { |
| 191 | let r = T::regs(); | 193 | let r = T::regs(); |
| 192 | 194 | ||
| 193 | Event::from_reg(&r.events_loopsdone) | 195 | Event::from_reg(&r.events_loopsdone) |
| @@ -195,7 +197,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 195 | 197 | ||
| 196 | /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. | 198 | /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. |
| 197 | #[inline(always)] | 199 | #[inline(always)] |
| 198 | pub fn event_pwm_period_end(&self) -> Event { | 200 | pub fn event_pwm_period_end(&self) -> Event<'d> { |
| 199 | let r = T::regs(); | 201 | let r = T::regs(); |
| 200 | 202 | ||
| 201 | Event::from_reg(&r.events_pwmperiodend) | 203 | Event::from_reg(&r.events_pwmperiodend) |
| @@ -203,7 +205,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 203 | 205 | ||
| 204 | /// Returns reference to `Seq0 End` event endpoint for PPI. | 206 | /// Returns reference to `Seq0 End` event endpoint for PPI. |
| 205 | #[inline(always)] | 207 | #[inline(always)] |
| 206 | pub fn event_seq_end(&self) -> Event { | 208 | pub fn event_seq_end(&self) -> Event<'d> { |
| 207 | let r = T::regs(); | 209 | let r = T::regs(); |
| 208 | 210 | ||
| 209 | Event::from_reg(&r.events_seqend[0]) | 211 | Event::from_reg(&r.events_seqend[0]) |
| @@ -211,7 +213,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 211 | 213 | ||
| 212 | /// Returns reference to `Seq1 End` event endpoint for PPI. | 214 | /// Returns reference to `Seq1 End` event endpoint for PPI. |
| 213 | #[inline(always)] | 215 | #[inline(always)] |
| 214 | pub fn event_seq1_end(&self) -> Event { | 216 | pub fn event_seq1_end(&self) -> Event<'d> { |
| 215 | let r = T::regs(); | 217 | let r = T::regs(); |
| 216 | 218 | ||
| 217 | Event::from_reg(&r.events_seqend[1]) | 219 | Event::from_reg(&r.events_seqend[1]) |
| @@ -219,7 +221,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 219 | 221 | ||
| 220 | /// Returns reference to `Seq0 Started` event endpoint for PPI. | 222 | /// Returns reference to `Seq0 Started` event endpoint for PPI. |
| 221 | #[inline(always)] | 223 | #[inline(always)] |
| 222 | pub fn event_seq0_started(&self) -> Event { | 224 | pub fn event_seq0_started(&self) -> Event<'d> { |
| 223 | let r = T::regs(); | 225 | let r = T::regs(); |
| 224 | 226 | ||
| 225 | Event::from_reg(&r.events_seqstarted[0]) | 227 | Event::from_reg(&r.events_seqstarted[0]) |
| @@ -227,7 +229,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 227 | 229 | ||
| 228 | /// Returns reference to `Seq1 Started` event endpoint for PPI. | 230 | /// Returns reference to `Seq1 Started` event endpoint for PPI. |
| 229 | #[inline(always)] | 231 | #[inline(always)] |
| 230 | pub fn event_seq1_started(&self) -> Event { | 232 | pub fn event_seq1_started(&self) -> Event<'d> { |
| 231 | let r = T::regs(); | 233 | let r = T::regs(); |
| 232 | 234 | ||
| 233 | Event::from_reg(&r.events_seqstarted[1]) | 235 | Event::from_reg(&r.events_seqstarted[1]) |
| @@ -238,7 +240,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 238 | /// | 240 | /// |
| 239 | /// Interacting with the sequence while it runs puts it in an unknown state | 241 | /// Interacting with the sequence while it runs puts it in an unknown state |
| 240 | #[inline(always)] | 242 | #[inline(always)] |
| 241 | pub unsafe fn task_start_seq0(&self) -> Task { | 243 | pub unsafe fn task_start_seq0(&self) -> Task<'d> { |
| 242 | let r = T::regs(); | 244 | let r = T::regs(); |
| 243 | 245 | ||
| 244 | Task::from_reg(&r.tasks_seqstart[0]) | 246 | Task::from_reg(&r.tasks_seqstart[0]) |
| @@ -249,7 +251,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 249 | /// | 251 | /// |
| 250 | /// Interacting with the sequence while it runs puts it in an unknown state | 252 | /// Interacting with the sequence while it runs puts it in an unknown state |
| 251 | #[inline(always)] | 253 | #[inline(always)] |
| 252 | pub unsafe fn task_start_seq1(&self) -> Task { | 254 | pub unsafe fn task_start_seq1(&self) -> Task<'d> { |
| 253 | let r = T::regs(); | 255 | let r = T::regs(); |
| 254 | 256 | ||
| 255 | Task::from_reg(&r.tasks_seqstart[1]) | 257 | Task::from_reg(&r.tasks_seqstart[1]) |
| @@ -260,7 +262,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 260 | /// | 262 | /// |
| 261 | /// Interacting with the sequence while it runs puts it in an unknown state | 263 | /// Interacting with the sequence while it runs puts it in an unknown state |
| 262 | #[inline(always)] | 264 | #[inline(always)] |
| 263 | pub unsafe fn task_next_step(&self) -> Task { | 265 | pub unsafe fn task_next_step(&self) -> Task<'d> { |
| 264 | let r = T::regs(); | 266 | let r = T::regs(); |
| 265 | 267 | ||
| 266 | Task::from_reg(&r.tasks_nextstep) | 268 | Task::from_reg(&r.tasks_nextstep) |
| @@ -271,7 +273,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { | |||
| 271 | /// | 273 | /// |
| 272 | /// Interacting with the sequence while it runs puts it in an unknown state | 274 | /// Interacting with the sequence while it runs puts it in an unknown state |
| 273 | #[inline(always)] | 275 | #[inline(always)] |
| 274 | pub unsafe fn task_stop(&self) -> Task { | 276 | pub unsafe fn task_stop(&self) -> Task<'d> { |
| 275 | let r = T::regs(); | 277 | let r = T::regs(); |
| 276 | 278 | ||
| 277 | Task::from_reg(&r.tasks_stop) | 279 | Task::from_reg(&r.tasks_stop) |
| @@ -358,6 +360,7 @@ pub struct Sequence<'s> { | |||
| 358 | } | 360 | } |
| 359 | 361 | ||
| 360 | impl<'s> Sequence<'s> { | 362 | impl<'s> Sequence<'s> { |
| 363 | /// Create a new `Sequence` | ||
| 361 | pub fn new(words: &'s [u16], config: SequenceConfig) -> Self { | 364 | pub fn new(words: &'s [u16], config: SequenceConfig) -> Self { |
| 362 | Self { words, config } | 365 | Self { words, config } |
| 363 | } | 366 | } |
| @@ -367,7 +370,7 @@ impl<'s> Sequence<'s> { | |||
| 367 | /// Takes at one sequence along with its configuration. | 370 | /// Takes at one sequence along with its configuration. |
| 368 | #[non_exhaustive] | 371 | #[non_exhaustive] |
| 369 | pub struct SingleSequencer<'d, 's, T: Instance> { | 372 | pub struct SingleSequencer<'d, 's, T: Instance> { |
| 370 | pub sequencer: Sequencer<'d, 's, T>, | 373 | sequencer: Sequencer<'d, 's, T>, |
| 371 | } | 374 | } |
| 372 | 375 | ||
| 373 | impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { | 376 | impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { |
| @@ -428,8 +431,8 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { | |||
| 428 | let sequence0 = &self.sequence0; | 431 | let sequence0 = &self.sequence0; |
| 429 | let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0); | 432 | let alt_sequence = self.sequence1.as_ref().unwrap_or(&self.sequence0); |
| 430 | 433 | ||
| 431 | slice_in_ram_or(sequence0.words, Error::DMABufferNotInDataMemory)?; | 434 | slice_in_ram_or(sequence0.words, Error::BufferNotInRAM)?; |
| 432 | slice_in_ram_or(alt_sequence.words, Error::DMABufferNotInDataMemory)?; | 435 | slice_in_ram_or(alt_sequence.words, Error::BufferNotInRAM)?; |
| 433 | 436 | ||
| 434 | if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN { | 437 | if sequence0.words.len() > MAX_SEQUENCE_LEN || alt_sequence.words.len() > MAX_SEQUENCE_LEN { |
| 435 | return Err(Error::SequenceTooLong); | 438 | return Err(Error::SequenceTooLong); |
| @@ -536,13 +539,21 @@ pub enum SequenceMode { | |||
| 536 | /// PWM Base clock is system clock (16MHz) divided by prescaler | 539 | /// PWM Base clock is system clock (16MHz) divided by prescaler |
| 537 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 540 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 538 | pub enum Prescaler { | 541 | pub enum Prescaler { |
| 542 | /// Divide by 1 | ||
| 539 | Div1, | 543 | Div1, |
| 544 | /// Divide by 2 | ||
| 540 | Div2, | 545 | Div2, |
| 546 | /// Divide by 4 | ||
| 541 | Div4, | 547 | Div4, |
| 548 | /// Divide by 8 | ||
| 542 | Div8, | 549 | Div8, |
| 550 | /// Divide by 16 | ||
| 543 | Div16, | 551 | Div16, |
| 552 | /// Divide by 32 | ||
| 544 | Div32, | 553 | Div32, |
| 554 | /// Divide by 64 | ||
| 545 | Div64, | 555 | Div64, |
| 556 | /// Divide by 128 | ||
| 546 | Div128, | 557 | Div128, |
| 547 | } | 558 | } |
| 548 | 559 | ||
| @@ -828,8 +839,10 @@ pub(crate) mod sealed { | |||
| 828 | } | 839 | } |
| 829 | } | 840 | } |
| 830 | 841 | ||
| 842 | /// PWM peripheral instance. | ||
| 831 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 843 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 832 | type Interrupt: Interrupt; | 844 | /// Interrupt for this peripheral. |
| 845 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 833 | } | 846 | } |
| 834 | 847 | ||
| 835 | macro_rules! impl_pwm { | 848 | macro_rules! impl_pwm { |
| @@ -840,7 +853,7 @@ macro_rules! impl_pwm { | |||
| 840 | } | 853 | } |
| 841 | } | 854 | } |
| 842 | impl crate::pwm::Instance for peripherals::$type { | 855 | impl crate::pwm::Instance for peripherals::$type { |
| 843 | type Interrupt = crate::interrupt::$irq; | 856 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 844 | } | 857 | } |
| 845 | }; | 858 | }; |
| 846 | } | 859 | } |
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 762e09715..8bac87d37 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs | |||
| @@ -1,28 +1,35 @@ | |||
| 1 | //! Quadrature decoder interface | 1 | //! Quadrature decoder (QDEC) driver. |
| 2 | 2 | ||
| 3 | #![macro_use] | ||
| 4 | |||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | 7 | use core::task::Poll; |
| 4 | 8 | ||
| 5 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 6 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 7 | use futures::future::poll_fn; | ||
| 8 | 10 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 11 | use crate::gpio::sealed::Pin as _; |
| 10 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 12 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 11 | use crate::interrupt::InterruptExt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::peripherals::QDEC; | 14 | use crate::{interrupt, Peripheral}; |
| 13 | use crate::{interrupt, pac, Peripheral}; | ||
| 14 | 15 | ||
| 15 | /// Quadrature decoder | 16 | /// Quadrature decoder driver. |
| 16 | pub struct Qdec<'d> { | 17 | pub struct Qdec<'d, T: Instance> { |
| 17 | _p: PeripheralRef<'d, QDEC>, | 18 | _p: PeripheralRef<'d, T>, |
| 18 | } | 19 | } |
| 19 | 20 | ||
| 21 | /// QDEC config | ||
| 20 | #[non_exhaustive] | 22 | #[non_exhaustive] |
| 21 | pub struct Config { | 23 | pub struct Config { |
| 24 | /// Number of samples | ||
| 22 | pub num_samples: NumSamples, | 25 | pub num_samples: NumSamples, |
| 26 | /// Sample period | ||
| 23 | pub period: SamplePeriod, | 27 | pub period: SamplePeriod, |
| 28 | /// Set LED output pin polarity | ||
| 24 | pub led_polarity: LedPolarity, | 29 | pub led_polarity: LedPolarity, |
| 30 | /// Enable/disable input debounce filters | ||
| 25 | pub debounce: bool, | 31 | pub debounce: bool, |
| 32 | /// Time period the LED is switched ON prior to sampling (0..511 us). | ||
| 26 | pub led_pre_usecs: u16, | 33 | pub led_pre_usecs: u16, |
| 27 | } | 34 | } |
| 28 | 35 | ||
| @@ -38,42 +45,52 @@ impl Default for Config { | |||
| 38 | } | 45 | } |
| 39 | } | 46 | } |
| 40 | 47 | ||
| 41 | static WAKER: AtomicWaker = AtomicWaker::new(); | 48 | /// Interrupt handler. |
| 49 | pub struct InterruptHandler<T: Instance> { | ||
| 50 | _phantom: PhantomData<T>, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 54 | unsafe fn on_interrupt() { | ||
| 55 | T::regs().intenclr.write(|w| w.reportrdy().clear()); | ||
| 56 | T::state().waker.wake(); | ||
| 57 | } | ||
| 58 | } | ||
| 42 | 59 | ||
| 43 | impl<'d> Qdec<'d> { | 60 | impl<'d, T: Instance> Qdec<'d, T> { |
| 61 | /// Create a new QDEC. | ||
| 44 | pub fn new( | 62 | pub fn new( |
| 45 | qdec: impl Peripheral<P = QDEC> + 'd, | 63 | qdec: impl Peripheral<P = T> + 'd, |
| 46 | irq: impl Peripheral<P = interrupt::QDEC> + 'd, | 64 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 47 | a: impl Peripheral<P = impl GpioPin> + 'd, | 65 | a: impl Peripheral<P = impl GpioPin> + 'd, |
| 48 | b: impl Peripheral<P = impl GpioPin> + 'd, | 66 | b: impl Peripheral<P = impl GpioPin> + 'd, |
| 49 | config: Config, | 67 | config: Config, |
| 50 | ) -> Self { | 68 | ) -> Self { |
| 51 | into_ref!(a, b); | 69 | into_ref!(qdec, a, b); |
| 52 | Self::new_inner(qdec, irq, a.map_into(), b.map_into(), None, config) | 70 | Self::new_inner(qdec, a.map_into(), b.map_into(), None, config) |
| 53 | } | 71 | } |
| 54 | 72 | ||
| 73 | /// Create a new QDEC, with a pin for LED output. | ||
| 55 | pub fn new_with_led( | 74 | pub fn new_with_led( |
| 56 | qdec: impl Peripheral<P = QDEC> + 'd, | 75 | qdec: impl Peripheral<P = T> + 'd, |
| 57 | irq: impl Peripheral<P = interrupt::QDEC> + 'd, | 76 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 58 | a: impl Peripheral<P = impl GpioPin> + 'd, | 77 | a: impl Peripheral<P = impl GpioPin> + 'd, |
| 59 | b: impl Peripheral<P = impl GpioPin> + 'd, | 78 | b: impl Peripheral<P = impl GpioPin> + 'd, |
| 60 | led: impl Peripheral<P = impl GpioPin> + 'd, | 79 | led: impl Peripheral<P = impl GpioPin> + 'd, |
| 61 | config: Config, | 80 | config: Config, |
| 62 | ) -> Self { | 81 | ) -> Self { |
| 63 | into_ref!(a, b, led); | 82 | into_ref!(qdec, a, b, led); |
| 64 | Self::new_inner(qdec, irq, a.map_into(), b.map_into(), Some(led.map_into()), config) | 83 | Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config) |
| 65 | } | 84 | } |
| 66 | 85 | ||
| 67 | fn new_inner( | 86 | fn new_inner( |
| 68 | p: impl Peripheral<P = QDEC> + 'd, | 87 | p: PeripheralRef<'d, T>, |
| 69 | irq: impl Peripheral<P = interrupt::QDEC> + 'd, | ||
| 70 | a: PeripheralRef<'d, AnyPin>, | 88 | a: PeripheralRef<'d, AnyPin>, |
| 71 | b: PeripheralRef<'d, AnyPin>, | 89 | b: PeripheralRef<'d, AnyPin>, |
| 72 | led: Option<PeripheralRef<'d, AnyPin>>, | 90 | led: Option<PeripheralRef<'d, AnyPin>>, |
| 73 | config: Config, | 91 | config: Config, |
| 74 | ) -> Self { | 92 | ) -> Self { |
| 75 | into_ref!(p, irq); | 93 | let r = T::regs(); |
| 76 | let r = Self::regs(); | ||
| 77 | 94 | ||
| 78 | // Select pins. | 95 | // Select pins. |
| 79 | a.conf().write(|w| w.input().connect().pull().pullup()); | 96 | a.conf().write(|w| w.input().connect().pull().pullup()); |
| @@ -116,20 +133,15 @@ impl<'d> Qdec<'d> { | |||
| 116 | SamplePeriod::_131ms => w.sampleper()._131ms(), | 133 | SamplePeriod::_131ms => w.sampleper()._131ms(), |
| 117 | }); | 134 | }); |
| 118 | 135 | ||
| 136 | T::Interrupt::unpend(); | ||
| 137 | unsafe { T::Interrupt::enable() }; | ||
| 138 | |||
| 119 | // Enable peripheral | 139 | // Enable peripheral |
| 120 | r.enable.write(|w| w.enable().set_bit()); | 140 | r.enable.write(|w| w.enable().set_bit()); |
| 121 | 141 | ||
| 122 | // Start sampling | 142 | // Start sampling |
| 123 | unsafe { r.tasks_start.write(|w| w.bits(1)) }; | 143 | unsafe { r.tasks_start.write(|w| w.bits(1)) }; |
| 124 | 144 | ||
| 125 | irq.disable(); | ||
| 126 | irq.set_handler(|_| { | ||
| 127 | let r = Self::regs(); | ||
| 128 | r.intenclr.write(|w| w.reportrdy().clear()); | ||
| 129 | WAKER.wake(); | ||
| 130 | }); | ||
| 131 | irq.enable(); | ||
| 132 | |||
| 133 | Self { _p: p } | 145 | Self { _p: p } |
| 134 | } | 146 | } |
| 135 | 147 | ||
| @@ -141,18 +153,27 @@ impl<'d> Qdec<'d> { | |||
| 141 | /// # Example | 153 | /// # Example |
| 142 | /// | 154 | /// |
| 143 | /// ```no_run | 155 | /// ```no_run |
| 144 | /// let irq = interrupt::take!(QDEC); | 156 | /// use embassy_nrf::qdec::{self, Qdec}; |
| 157 | /// use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 158 | /// | ||
| 159 | /// bind_interrupts!(struct Irqs { | ||
| 160 | /// QDEC => qdec::InterruptHandler<peripherals::QDEC>; | ||
| 161 | /// }); | ||
| 162 | /// | ||
| 163 | /// # async { | ||
| 164 | /// # let p: embassy_nrf::Peripherals = todo!(); | ||
| 145 | /// let config = qdec::Config::default(); | 165 | /// let config = qdec::Config::default(); |
| 146 | /// let mut q = Qdec::new(p.QDEC, p.P0_31, p.P0_30, config); | 166 | /// let mut q = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config); |
| 147 | /// let delta = q.read().await; | 167 | /// let delta = q.read().await; |
| 168 | /// # }; | ||
| 148 | /// ``` | 169 | /// ``` |
| 149 | pub async fn read(&mut self) -> i16 { | 170 | pub async fn read(&mut self) -> i16 { |
| 150 | let t = Self::regs(); | 171 | let t = T::regs(); |
| 151 | t.intenset.write(|w| w.reportrdy().set()); | 172 | t.intenset.write(|w| w.reportrdy().set()); |
| 152 | unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; | 173 | unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; |
| 153 | 174 | ||
| 154 | let value = poll_fn(|cx| { | 175 | let value = poll_fn(|cx| { |
| 155 | WAKER.register(cx.waker()); | 176 | T::state().waker.register(cx.waker()); |
| 156 | if t.events_reportrdy.read().bits() == 0 { | 177 | if t.events_reportrdy.read().bits() == 0 { |
| 157 | return Poll::Pending; | 178 | return Poll::Pending; |
| 158 | } else { | 179 | } else { |
| @@ -164,42 +185,108 @@ impl<'d> Qdec<'d> { | |||
| 164 | .await; | 185 | .await; |
| 165 | value | 186 | value |
| 166 | } | 187 | } |
| 167 | |||
| 168 | fn regs() -> &'static pac::qdec::RegisterBlock { | ||
| 169 | unsafe { &*pac::QDEC::ptr() } | ||
| 170 | } | ||
| 171 | } | 188 | } |
| 172 | 189 | ||
| 190 | /// Sample period | ||
| 173 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 191 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 174 | pub enum SamplePeriod { | 192 | pub enum SamplePeriod { |
| 193 | /// 128 us | ||
| 175 | _128us, | 194 | _128us, |
| 195 | /// 256 us | ||
| 176 | _256us, | 196 | _256us, |
| 197 | /// 512 us | ||
| 177 | _512us, | 198 | _512us, |
| 199 | /// 1024 us | ||
| 178 | _1024us, | 200 | _1024us, |
| 201 | /// 2048 us | ||
| 179 | _2048us, | 202 | _2048us, |
| 203 | /// 4096 us | ||
| 180 | _4096us, | 204 | _4096us, |
| 205 | /// 8192 us | ||
| 181 | _8192us, | 206 | _8192us, |
| 207 | /// 16384 us | ||
| 182 | _16384us, | 208 | _16384us, |
| 209 | /// 32 ms | ||
| 183 | _32ms, | 210 | _32ms, |
| 211 | /// 65 ms | ||
| 184 | _65ms, | 212 | _65ms, |
| 213 | /// 131 ms | ||
| 185 | _131ms, | 214 | _131ms, |
| 186 | } | 215 | } |
| 187 | 216 | ||
| 217 | /// Number of samples taken. | ||
| 188 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 218 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 189 | pub enum NumSamples { | 219 | pub enum NumSamples { |
| 220 | /// 10 samples | ||
| 190 | _10smpl, | 221 | _10smpl, |
| 222 | /// 40 samples | ||
| 191 | _40smpl, | 223 | _40smpl, |
| 224 | /// 80 samples | ||
| 192 | _80smpl, | 225 | _80smpl, |
| 226 | /// 120 samples | ||
| 193 | _120smpl, | 227 | _120smpl, |
| 228 | /// 160 samples | ||
| 194 | _160smpl, | 229 | _160smpl, |
| 230 | /// 200 samples | ||
| 195 | _200smpl, | 231 | _200smpl, |
| 232 | /// 240 samples | ||
| 196 | _240smpl, | 233 | _240smpl, |
| 234 | /// 280 samples | ||
| 197 | _280smpl, | 235 | _280smpl, |
| 236 | /// 1 sample | ||
| 198 | _1smpl, | 237 | _1smpl, |
| 199 | } | 238 | } |
| 200 | 239 | ||
| 240 | /// LED polarity | ||
| 201 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 241 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 202 | pub enum LedPolarity { | 242 | pub enum LedPolarity { |
| 243 | /// Active high (a high output turns on the LED). | ||
| 203 | ActiveHigh, | 244 | ActiveHigh, |
| 245 | /// Active low (a low output turns on the LED). | ||
| 204 | ActiveLow, | 246 | ActiveLow, |
| 205 | } | 247 | } |
| 248 | |||
| 249 | pub(crate) mod sealed { | ||
| 250 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 251 | |||
| 252 | /// Peripheral static state | ||
| 253 | pub struct State { | ||
| 254 | pub waker: AtomicWaker, | ||
| 255 | } | ||
| 256 | |||
| 257 | impl State { | ||
| 258 | pub const fn new() -> Self { | ||
| 259 | Self { | ||
| 260 | waker: AtomicWaker::new(), | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | pub trait Instance { | ||
| 266 | fn regs() -> &'static crate::pac::qdec::RegisterBlock; | ||
| 267 | fn state() -> &'static State; | ||
| 268 | } | ||
| 269 | } | ||
| 270 | |||
| 271 | /// qdec peripheral instance. | ||
| 272 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 273 | /// Interrupt for this peripheral. | ||
| 274 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 275 | } | ||
| 276 | |||
| 277 | macro_rules! impl_qdec { | ||
| 278 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 279 | impl crate::qdec::sealed::Instance for peripherals::$type { | ||
| 280 | fn regs() -> &'static crate::pac::qdec::RegisterBlock { | ||
| 281 | unsafe { &*pac::$pac_type::ptr() } | ||
| 282 | } | ||
| 283 | fn state() -> &'static crate::qdec::sealed::State { | ||
| 284 | static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new(); | ||
| 285 | &STATE | ||
| 286 | } | ||
| 287 | } | ||
| 288 | impl crate::qdec::Instance for peripherals::$type { | ||
| 289 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 290 | } | ||
| 291 | }; | ||
| 292 | } | ||
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index c97cb1656..baefc7967 100644 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs | |||
| @@ -1,20 +1,25 @@ | |||
| 1 | //! Quad Serial Peripheral Interface (QSPI) flash driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 3 | use core::ptr; | 7 | use core::ptr; |
| 4 | use core::task::Poll; | 8 | use core::task::Poll; |
| 5 | 9 | ||
| 6 | use embassy_hal_common::drop::DropBomb; | 10 | use embassy_hal_common::drop::OnDrop; |
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | 11 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 8 | use futures::future::poll_fn; | 12 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; |
| 9 | 13 | ||
| 10 | use crate::gpio::{self, Pin as GpioPin}; | 14 | use crate::gpio::{self, Pin as GpioPin}; |
| 11 | use crate::interrupt::{Interrupt, InterruptExt}; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 12 | pub use crate::pac::qspi::ifconfig0::{ | 16 | pub use crate::pac::qspi::ifconfig0::{ |
| 13 | ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, | 17 | ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, |
| 14 | }; | 18 | }; |
| 15 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; | 19 | pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; |
| 16 | use crate::{pac, Peripheral}; | 20 | use crate::{interrupt, Peripheral}; |
| 17 | 21 | ||
| 22 | /// Deep power-down config. | ||
| 18 | pub struct DeepPowerDownConfig { | 23 | pub struct DeepPowerDownConfig { |
| 19 | /// Time required for entering DPM, in units of 16us | 24 | /// Time required for entering DPM, in units of 16us |
| 20 | pub enter_time: u16, | 25 | pub enter_time: u16, |
| @@ -22,38 +27,65 @@ pub struct DeepPowerDownConfig { | |||
| 22 | pub exit_time: u16, | 27 | pub exit_time: u16, |
| 23 | } | 28 | } |
| 24 | 29 | ||
| 30 | /// QSPI bus frequency. | ||
| 25 | pub enum Frequency { | 31 | pub enum Frequency { |
| 32 | /// 32 Mhz | ||
| 26 | M32 = 0, | 33 | M32 = 0, |
| 34 | /// 16 Mhz | ||
| 27 | M16 = 1, | 35 | M16 = 1, |
| 36 | /// 10.7 Mhz | ||
| 28 | M10_7 = 2, | 37 | M10_7 = 2, |
| 38 | /// 8 Mhz | ||
| 29 | M8 = 3, | 39 | M8 = 3, |
| 40 | /// 6.4 Mhz | ||
| 30 | M6_4 = 4, | 41 | M6_4 = 4, |
| 42 | /// 5.3 Mhz | ||
| 31 | M5_3 = 5, | 43 | M5_3 = 5, |
| 44 | /// 4.6 Mhz | ||
| 32 | M4_6 = 6, | 45 | M4_6 = 6, |
| 46 | /// 4 Mhz | ||
| 33 | M4 = 7, | 47 | M4 = 7, |
| 48 | /// 3.6 Mhz | ||
| 34 | M3_6 = 8, | 49 | M3_6 = 8, |
| 50 | /// 3.2 Mhz | ||
| 35 | M3_2 = 9, | 51 | M3_2 = 9, |
| 52 | /// 2.9 Mhz | ||
| 36 | M2_9 = 10, | 53 | M2_9 = 10, |
| 54 | /// 2.7 Mhz | ||
| 37 | M2_7 = 11, | 55 | M2_7 = 11, |
| 56 | /// 2.5 Mhz | ||
| 38 | M2_5 = 12, | 57 | M2_5 = 12, |
| 58 | /// 2.3 Mhz | ||
| 39 | M2_3 = 13, | 59 | M2_3 = 13, |
| 60 | /// 2.1 Mhz | ||
| 40 | M2_1 = 14, | 61 | M2_1 = 14, |
| 62 | /// 2 Mhz | ||
| 41 | M2 = 15, | 63 | M2 = 15, |
| 42 | } | 64 | } |
| 43 | 65 | ||
| 66 | /// QSPI config. | ||
| 44 | #[non_exhaustive] | 67 | #[non_exhaustive] |
| 45 | pub struct Config { | 68 | pub struct Config { |
| 69 | /// XIP offset. | ||
| 46 | pub xip_offset: u32, | 70 | pub xip_offset: u32, |
| 71 | /// Opcode used for read operations. | ||
| 47 | pub read_opcode: ReadOpcode, | 72 | pub read_opcode: ReadOpcode, |
| 73 | /// Opcode used for write operations. | ||
| 48 | pub write_opcode: WriteOpcode, | 74 | pub write_opcode: WriteOpcode, |
| 75 | /// Page size for write operations. | ||
| 49 | pub write_page_size: WritePageSize, | 76 | pub write_page_size: WritePageSize, |
| 77 | /// Configuration for deep power down. If None, deep power down is disabled. | ||
| 50 | pub deep_power_down: Option<DeepPowerDownConfig>, | 78 | pub deep_power_down: Option<DeepPowerDownConfig>, |
| 79 | /// QSPI bus frequency. | ||
| 51 | pub frequency: Frequency, | 80 | pub frequency: Frequency, |
| 52 | /// Value is specified in number of 16 MHz periods (62.5 ns) | 81 | /// Value is specified in number of 16 MHz periods (62.5 ns) |
| 53 | pub sck_delay: u8, | 82 | pub sck_delay: u8, |
| 54 | /// Whether data is captured on the clock rising edge and data is output on a falling edge (MODE0) or vice-versa (MODE3) | 83 | /// Whether data is captured on the clock rising edge and data is output on a falling edge (MODE0) or vice-versa (MODE3) |
| 55 | pub spi_mode: SpiMode, | 84 | pub spi_mode: SpiMode, |
| 85 | /// Addressing mode (24-bit or 32-bit) | ||
| 56 | pub address_mode: AddressMode, | 86 | pub address_mode: AddressMode, |
| 87 | /// Flash memory capacity in bytes. This is the value reported by the `embedded-storage` traits. | ||
| 88 | pub capacity: u32, | ||
| 57 | } | 89 | } |
| 58 | 90 | ||
| 59 | impl Default for Config { | 91 | impl Default for Config { |
| @@ -68,27 +100,50 @@ impl Default for Config { | |||
| 68 | sck_delay: 80, | 100 | sck_delay: 80, |
| 69 | spi_mode: SpiMode::MODE0, | 101 | spi_mode: SpiMode::MODE0, |
| 70 | address_mode: AddressMode::_24BIT, | 102 | address_mode: AddressMode::_24BIT, |
| 103 | capacity: 0, | ||
| 71 | } | 104 | } |
| 72 | } | 105 | } |
| 73 | } | 106 | } |
| 74 | 107 | ||
| 108 | /// Error | ||
| 75 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 109 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 76 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 110 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 77 | #[non_exhaustive] | 111 | #[non_exhaustive] |
| 78 | pub enum Error { | 112 | pub enum Error { |
| 113 | /// Operation address was out of bounds. | ||
| 79 | OutOfBounds, | 114 | OutOfBounds, |
| 80 | // TODO add "not in data memory" error and check for it | 115 | // TODO add "not in data memory" error and check for it |
| 81 | } | 116 | } |
| 82 | 117 | ||
| 83 | pub struct Qspi<'d, T: Instance, const FLASH_SIZE: usize> { | 118 | /// Interrupt handler. |
| 84 | irq: PeripheralRef<'d, T::Interrupt>, | 119 | pub struct InterruptHandler<T: Instance> { |
| 120 | _phantom: PhantomData<T>, | ||
| 121 | } | ||
| 122 | |||
| 123 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 124 | unsafe fn on_interrupt() { | ||
| 125 | let r = T::regs(); | ||
| 126 | let s = T::state(); | ||
| 127 | |||
| 128 | if r.events_ready.read().bits() != 0 { | ||
| 129 | s.waker.wake(); | ||
| 130 | r.intenclr.write(|w| w.ready().clear()); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | /// QSPI flash driver. | ||
| 136 | pub struct Qspi<'d, T: Instance> { | ||
| 137 | _peri: PeripheralRef<'d, T>, | ||
| 85 | dpm_enabled: bool, | 138 | dpm_enabled: bool, |
| 139 | capacity: u32, | ||
| 86 | } | 140 | } |
| 87 | 141 | ||
| 88 | impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | 142 | impl<'d, T: Instance> Qspi<'d, T> { |
| 143 | /// Create a new QSPI driver. | ||
| 89 | pub fn new( | 144 | pub fn new( |
| 90 | _qspi: impl Peripheral<P = T> + 'd, | 145 | qspi: impl Peripheral<P = T> + 'd, |
| 91 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 146 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 92 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 147 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 93 | csn: impl Peripheral<P = impl GpioPin> + 'd, | 148 | csn: impl Peripheral<P = impl GpioPin> + 'd, |
| 94 | io0: impl Peripheral<P = impl GpioPin> + 'd, | 149 | io0: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -96,30 +151,31 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 96 | io2: impl Peripheral<P = impl GpioPin> + 'd, | 151 | io2: impl Peripheral<P = impl GpioPin> + 'd, |
| 97 | io3: impl Peripheral<P = impl GpioPin> + 'd, | 152 | io3: impl Peripheral<P = impl GpioPin> + 'd, |
| 98 | config: Config, | 153 | config: Config, |
| 99 | ) -> Qspi<'d, T, FLASH_SIZE> { | 154 | ) -> Self { |
| 100 | into_ref!(irq, sck, csn, io0, io1, io2, io3); | 155 | into_ref!(qspi, sck, csn, io0, io1, io2, io3); |
| 101 | 156 | ||
| 102 | let r = T::regs(); | 157 | let r = T::regs(); |
| 103 | 158 | ||
| 104 | sck.set_high(); | 159 | macro_rules! config_pin { |
| 105 | csn.set_high(); | 160 | ($pin:ident) => { |
| 106 | io0.set_high(); | 161 | $pin.set_high(); |
| 107 | io1.set_high(); | 162 | $pin.conf().write(|w| { |
| 108 | io2.set_high(); | 163 | w.dir().output(); |
| 109 | io3.set_high(); | 164 | w.drive().h0h1(); |
| 110 | sck.conf().write(|w| w.dir().output().drive().h0h1()); | 165 | #[cfg(feature = "_nrf5340-s")] |
| 111 | csn.conf().write(|w| w.dir().output().drive().h0h1()); | 166 | w.mcusel().peripheral(); |
| 112 | io0.conf().write(|w| w.dir().output().drive().h0h1()); | 167 | w |
| 113 | io1.conf().write(|w| w.dir().output().drive().h0h1()); | 168 | }); |
| 114 | io2.conf().write(|w| w.dir().output().drive().h0h1()); | 169 | r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) }); |
| 115 | io3.conf().write(|w| w.dir().output().drive().h0h1()); | 170 | }; |
| 116 | 171 | } | |
| 117 | r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); | 172 | |
| 118 | r.psel.csn.write(|w| unsafe { w.bits(csn.psel_bits()) }); | 173 | config_pin!(sck); |
| 119 | r.psel.io0.write(|w| unsafe { w.bits(io0.psel_bits()) }); | 174 | config_pin!(csn); |
| 120 | r.psel.io1.write(|w| unsafe { w.bits(io1.psel_bits()) }); | 175 | config_pin!(io0); |
| 121 | r.psel.io2.write(|w| unsafe { w.bits(io2.psel_bits()) }); | 176 | config_pin!(io1); |
| 122 | r.psel.io3.write(|w| unsafe { w.bits(io3.psel_bits()) }); | 177 | config_pin!(io2); |
| 178 | config_pin!(io3); | ||
| 123 | 179 | ||
| 124 | r.ifconfig0.write(|w| { | 180 | r.ifconfig0.write(|w| { |
| 125 | w.addrmode().variant(config.address_mode); | 181 | w.addrmode().variant(config.address_mode); |
| @@ -151,16 +207,16 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 151 | w | 207 | w |
| 152 | }); | 208 | }); |
| 153 | 209 | ||
| 154 | irq.set_handler(Self::on_interrupt); | 210 | T::Interrupt::unpend(); |
| 155 | irq.unpend(); | 211 | unsafe { T::Interrupt::enable() }; |
| 156 | irq.enable(); | ||
| 157 | 212 | ||
| 158 | // Enable it | 213 | // Enable it |
| 159 | r.enable.write(|w| w.enable().enabled()); | 214 | r.enable.write(|w| w.enable().enabled()); |
| 160 | 215 | ||
| 161 | let mut res = Self { | 216 | let res = Self { |
| 217 | _peri: qspi, | ||
| 162 | dpm_enabled: config.deep_power_down.is_some(), | 218 | dpm_enabled: config.deep_power_down.is_some(), |
| 163 | irq, | 219 | capacity: config.capacity, |
| 164 | }; | 220 | }; |
| 165 | 221 | ||
| 166 | r.events_ready.reset(); | 222 | r.events_ready.reset(); |
| @@ -168,23 +224,14 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 168 | 224 | ||
| 169 | r.tasks_activate.write(|w| w.tasks_activate().bit(true)); | 225 | r.tasks_activate.write(|w| w.tasks_activate().bit(true)); |
| 170 | 226 | ||
| 171 | res.blocking_wait_ready(); | 227 | Self::blocking_wait_ready(); |
| 172 | 228 | ||
| 173 | res | 229 | res |
| 174 | } | 230 | } |
| 175 | 231 | ||
| 176 | fn on_interrupt(_: *mut ()) { | 232 | /// Do a custom QSPI instruction. |
| 177 | let r = T::regs(); | ||
| 178 | let s = T::state(); | ||
| 179 | |||
| 180 | if r.events_ready.read().bits() != 0 { | ||
| 181 | s.ready_waker.wake(); | ||
| 182 | r.intenclr.write(|w| w.ready().clear()); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { | 233 | pub async fn custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { |
| 187 | let bomb = DropBomb::new(); | 234 | let ondrop = OnDrop::new(Self::blocking_wait_ready); |
| 188 | 235 | ||
| 189 | let len = core::cmp::max(req.len(), resp.len()) as u8; | 236 | let len = core::cmp::max(req.len(), resp.len()) as u8; |
| 190 | self.custom_instruction_start(opcode, req, len)?; | 237 | self.custom_instruction_start(opcode, req, len)?; |
| @@ -193,16 +240,17 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 193 | 240 | ||
| 194 | self.custom_instruction_finish(resp)?; | 241 | self.custom_instruction_finish(resp)?; |
| 195 | 242 | ||
| 196 | bomb.defuse(); | 243 | ondrop.defuse(); |
| 197 | 244 | ||
| 198 | Ok(()) | 245 | Ok(()) |
| 199 | } | 246 | } |
| 200 | 247 | ||
| 248 | /// Do a custom QSPI instruction, blocking version. | ||
| 201 | pub fn blocking_custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { | 249 | pub fn blocking_custom_instruction(&mut self, opcode: u8, req: &[u8], resp: &mut [u8]) -> Result<(), Error> { |
| 202 | let len = core::cmp::max(req.len(), resp.len()) as u8; | 250 | let len = core::cmp::max(req.len(), resp.len()) as u8; |
| 203 | self.custom_instruction_start(opcode, req, len)?; | 251 | self.custom_instruction_start(opcode, req, len)?; |
| 204 | 252 | ||
| 205 | self.blocking_wait_ready(); | 253 | Self::blocking_wait_ready(); |
| 206 | 254 | ||
| 207 | self.custom_instruction_finish(resp)?; | 255 | self.custom_instruction_finish(resp)?; |
| 208 | 256 | ||
| @@ -269,7 +317,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 269 | poll_fn(move |cx| { | 317 | poll_fn(move |cx| { |
| 270 | let r = T::regs(); | 318 | let r = T::regs(); |
| 271 | let s = T::state(); | 319 | let s = T::state(); |
| 272 | s.ready_waker.register(cx.waker()); | 320 | s.waker.register(cx.waker()); |
| 273 | if r.events_ready.read().bits() != 0 { | 321 | if r.events_ready.read().bits() != 0 { |
| 274 | return Poll::Ready(()); | 322 | return Poll::Ready(()); |
| 275 | } | 323 | } |
| @@ -278,7 +326,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 278 | .await | 326 | .await |
| 279 | } | 327 | } |
| 280 | 328 | ||
| 281 | fn blocking_wait_ready(&mut self) { | 329 | fn blocking_wait_ready() { |
| 282 | loop { | 330 | loop { |
| 283 | let r = T::regs(); | 331 | let r = T::regs(); |
| 284 | if r.events_ready.read().bits() != 0 { | 332 | if r.events_ready.read().bits() != 0 { |
| @@ -287,17 +335,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 287 | } | 335 | } |
| 288 | } | 336 | } |
| 289 | 337 | ||
| 290 | fn start_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { | 338 | fn start_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { |
| 339 | // TODO: Return these as errors instead. | ||
| 291 | assert_eq!(data.as_ptr() as u32 % 4, 0); | 340 | assert_eq!(data.as_ptr() as u32 % 4, 0); |
| 292 | assert_eq!(data.len() as u32 % 4, 0); | 341 | assert_eq!(data.len() as u32 % 4, 0); |
| 293 | assert_eq!(address as u32 % 4, 0); | 342 | assert_eq!(address % 4, 0); |
| 294 | if address > FLASH_SIZE { | ||
| 295 | return Err(Error::OutOfBounds); | ||
| 296 | } | ||
| 297 | 343 | ||
| 298 | let r = T::regs(); | 344 | let r = T::regs(); |
| 299 | 345 | ||
| 300 | r.read.src.write(|w| unsafe { w.src().bits(address as u32) }); | 346 | r.read.src.write(|w| unsafe { w.src().bits(address) }); |
| 301 | r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); | 347 | r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); |
| 302 | r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | 348 | r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); |
| 303 | 349 | ||
| @@ -308,18 +354,15 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 308 | Ok(()) | 354 | Ok(()) |
| 309 | } | 355 | } |
| 310 | 356 | ||
| 311 | fn start_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { | 357 | fn start_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { |
| 358 | // TODO: Return these as errors instead. | ||
| 312 | assert_eq!(data.as_ptr() as u32 % 4, 0); | 359 | assert_eq!(data.as_ptr() as u32 % 4, 0); |
| 313 | assert_eq!(data.len() as u32 % 4, 0); | 360 | assert_eq!(data.len() as u32 % 4, 0); |
| 314 | assert_eq!(address as u32 % 4, 0); | 361 | assert_eq!(address % 4, 0); |
| 315 | |||
| 316 | if address > FLASH_SIZE { | ||
| 317 | return Err(Error::OutOfBounds); | ||
| 318 | } | ||
| 319 | 362 | ||
| 320 | let r = T::regs(); | 363 | let r = T::regs(); |
| 321 | r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); | 364 | r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); |
| 322 | r.write.dst.write(|w| unsafe { w.dst().bits(address as u32) }); | 365 | r.write.dst.write(|w| unsafe { w.dst().bits(address) }); |
| 323 | r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); | 366 | r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); |
| 324 | 367 | ||
| 325 | r.events_ready.reset(); | 368 | r.events_ready.reset(); |
| @@ -329,14 +372,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 329 | Ok(()) | 372 | Ok(()) |
| 330 | } | 373 | } |
| 331 | 374 | ||
| 332 | fn start_erase(&mut self, address: usize) -> Result<(), Error> { | 375 | fn start_erase(&mut self, address: u32) -> Result<(), Error> { |
| 333 | assert_eq!(address as u32 % 4096, 0); | 376 | // TODO: Return these as errors instead. |
| 334 | if address > FLASH_SIZE { | 377 | assert_eq!(address % 4096, 0); |
| 335 | return Err(Error::OutOfBounds); | ||
| 336 | } | ||
| 337 | 378 | ||
| 338 | let r = T::regs(); | 379 | let r = T::regs(); |
| 339 | r.erase.ptr.write(|w| unsafe { w.ptr().bits(address as u32) }); | 380 | r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); |
| 340 | r.erase.len.write(|w| w.len()._4kb()); | 381 | r.erase.len.write(|w| w.len()._4kb()); |
| 341 | 382 | ||
| 342 | r.events_ready.reset(); | 383 | r.events_ready.reset(); |
| @@ -346,59 +387,122 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Qspi<'d, T, FLASH_SIZE> { | |||
| 346 | Ok(()) | 387 | Ok(()) |
| 347 | } | 388 | } |
| 348 | 389 | ||
| 349 | pub async fn read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { | 390 | /// Raw QSPI read. |
| 350 | let bomb = DropBomb::new(); | 391 | /// |
| 392 | /// The difference with `read` is that this does not do bounds checks | ||
| 393 | /// against the flash capacity. It is intended for use when QSPI is used as | ||
| 394 | /// a raw bus, not with flash memory. | ||
| 395 | pub async fn read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { | ||
| 396 | let ondrop = OnDrop::new(Self::blocking_wait_ready); | ||
| 351 | 397 | ||
| 352 | self.start_read(address, data)?; | 398 | self.start_read(address, data)?; |
| 353 | self.wait_ready().await; | 399 | self.wait_ready().await; |
| 354 | 400 | ||
| 355 | bomb.defuse(); | 401 | ondrop.defuse(); |
| 356 | 402 | ||
| 357 | Ok(()) | 403 | Ok(()) |
| 358 | } | 404 | } |
| 359 | 405 | ||
| 360 | pub async fn write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { | 406 | /// Raw QSPI write. |
| 361 | let bomb = DropBomb::new(); | 407 | /// |
| 408 | /// The difference with `write` is that this does not do bounds checks | ||
| 409 | /// against the flash capacity. It is intended for use when QSPI is used as | ||
| 410 | /// a raw bus, not with flash memory. | ||
| 411 | pub async fn write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { | ||
| 412 | let ondrop = OnDrop::new(Self::blocking_wait_ready); | ||
| 362 | 413 | ||
| 363 | self.start_write(address, data)?; | 414 | self.start_write(address, data)?; |
| 364 | self.wait_ready().await; | 415 | self.wait_ready().await; |
| 365 | 416 | ||
| 366 | bomb.defuse(); | 417 | ondrop.defuse(); |
| 367 | 418 | ||
| 368 | Ok(()) | 419 | Ok(()) |
| 369 | } | 420 | } |
| 370 | 421 | ||
| 371 | pub async fn erase(&mut self, address: usize) -> Result<(), Error> { | 422 | /// Raw QSPI read, blocking version. |
| 372 | let bomb = DropBomb::new(); | 423 | /// |
| 424 | /// The difference with `blocking_read` is that this does not do bounds checks | ||
| 425 | /// against the flash capacity. It is intended for use when QSPI is used as | ||
| 426 | /// a raw bus, not with flash memory. | ||
| 427 | pub fn blocking_read_raw(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { | ||
| 428 | self.start_read(address, data)?; | ||
| 429 | Self::blocking_wait_ready(); | ||
| 430 | Ok(()) | ||
| 431 | } | ||
| 432 | |||
| 433 | /// Raw QSPI write, blocking version. | ||
| 434 | /// | ||
| 435 | /// The difference with `blocking_write` is that this does not do bounds checks | ||
| 436 | /// against the flash capacity. It is intended for use when QSPI is used as | ||
| 437 | /// a raw bus, not with flash memory. | ||
| 438 | pub fn blocking_write_raw(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { | ||
| 439 | self.start_write(address, data)?; | ||
| 440 | Self::blocking_wait_ready(); | ||
| 441 | Ok(()) | ||
| 442 | } | ||
| 443 | |||
| 444 | /// Read data from the flash memory. | ||
| 445 | pub async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { | ||
| 446 | self.bounds_check(address, data.len())?; | ||
| 447 | self.read_raw(address, data).await | ||
| 448 | } | ||
| 449 | |||
| 450 | /// Write data to the flash memory. | ||
| 451 | pub async fn write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { | ||
| 452 | self.bounds_check(address, data.len())?; | ||
| 453 | self.write_raw(address, data).await | ||
| 454 | } | ||
| 455 | |||
| 456 | /// Erase a sector on the flash memory. | ||
| 457 | pub async fn erase(&mut self, address: u32) -> Result<(), Error> { | ||
| 458 | if address >= self.capacity { | ||
| 459 | return Err(Error::OutOfBounds); | ||
| 460 | } | ||
| 461 | |||
| 462 | let ondrop = OnDrop::new(Self::blocking_wait_ready); | ||
| 373 | 463 | ||
| 374 | self.start_erase(address)?; | 464 | self.start_erase(address)?; |
| 375 | self.wait_ready().await; | 465 | self.wait_ready().await; |
| 376 | 466 | ||
| 377 | bomb.defuse(); | 467 | ondrop.defuse(); |
| 378 | 468 | ||
| 379 | Ok(()) | 469 | Ok(()) |
| 380 | } | 470 | } |
| 381 | 471 | ||
| 382 | pub fn blocking_read(&mut self, address: usize, data: &mut [u8]) -> Result<(), Error> { | 472 | /// Read data from the flash memory, blocking version. |
| 383 | self.start_read(address, data)?; | 473 | pub fn blocking_read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Error> { |
| 384 | self.blocking_wait_ready(); | 474 | self.bounds_check(address, data.len())?; |
| 385 | Ok(()) | 475 | self.blocking_read_raw(address, data) |
| 386 | } | 476 | } |
| 387 | 477 | ||
| 388 | pub fn blocking_write(&mut self, address: usize, data: &[u8]) -> Result<(), Error> { | 478 | /// Write data to the flash memory, blocking version. |
| 389 | self.start_write(address, data)?; | 479 | pub fn blocking_write(&mut self, address: u32, data: &[u8]) -> Result<(), Error> { |
| 390 | self.blocking_wait_ready(); | 480 | self.bounds_check(address, data.len())?; |
| 391 | Ok(()) | 481 | self.blocking_write_raw(address, data) |
| 392 | } | 482 | } |
| 393 | 483 | ||
| 394 | pub fn blocking_erase(&mut self, address: usize) -> Result<(), Error> { | 484 | /// Erase a sector on the flash memory, blocking version. |
| 485 | pub fn blocking_erase(&mut self, address: u32) -> Result<(), Error> { | ||
| 486 | if address >= self.capacity { | ||
| 487 | return Err(Error::OutOfBounds); | ||
| 488 | } | ||
| 489 | |||
| 395 | self.start_erase(address)?; | 490 | self.start_erase(address)?; |
| 396 | self.blocking_wait_ready(); | 491 | Self::blocking_wait_ready(); |
| 492 | Ok(()) | ||
| 493 | } | ||
| 494 | |||
| 495 | fn bounds_check(&self, address: u32, len: usize) -> Result<(), Error> { | ||
| 496 | let len_u32: u32 = len.try_into().map_err(|_| Error::OutOfBounds)?; | ||
| 497 | let end_address = address.checked_add(len_u32).ok_or(Error::OutOfBounds)?; | ||
| 498 | if end_address > self.capacity { | ||
| 499 | return Err(Error::OutOfBounds); | ||
| 500 | } | ||
| 397 | Ok(()) | 501 | Ok(()) |
| 398 | } | 502 | } |
| 399 | } | 503 | } |
| 400 | 504 | ||
| 401 | impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> { | 505 | impl<'d, T: Instance> Drop for Qspi<'d, T> { |
| 402 | fn drop(&mut self) { | 506 | fn drop(&mut self) { |
| 403 | let r = T::regs(); | 507 | let r = T::regs(); |
| 404 | 508 | ||
| @@ -428,8 +532,6 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> | |||
| 428 | 532 | ||
| 429 | r.enable.write(|w| w.enable().disabled()); | 533 | r.enable.write(|w| w.enable().disabled()); |
| 430 | 534 | ||
| 431 | self.irq.disable(); | ||
| 432 | |||
| 433 | // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, | 535 | // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, |
| 434 | // leaving it floating, the flash chip might read it as zero which would cause it to | 536 | // leaving it floating, the flash chip might read it as zero which would cause it to |
| 435 | // spuriously exit DPM. | 537 | // spuriously exit DPM. |
| @@ -443,9 +545,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Drop for Qspi<'d, T, FLASH_SIZE> | |||
| 443 | } | 545 | } |
| 444 | } | 546 | } |
| 445 | 547 | ||
| 446 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 548 | impl<'d, T: Instance> ErrorType for Qspi<'d, T> { |
| 447 | |||
| 448 | impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Qspi<'d, T, FLASH_SIZE> { | ||
| 449 | type Error = Error; | 549 | type Error = Error; |
| 450 | } | 550 | } |
| 451 | 551 | ||
| @@ -455,72 +555,66 @@ impl NorFlashError for Error { | |||
| 455 | } | 555 | } |
| 456 | } | 556 | } |
| 457 | 557 | ||
| 458 | impl<'d, T: Instance, const FLASH_SIZE: usize> ReadNorFlash for Qspi<'d, T, FLASH_SIZE> { | 558 | impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { |
| 459 | const READ_SIZE: usize = 4; | 559 | const READ_SIZE: usize = 4; |
| 460 | 560 | ||
| 461 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | 561 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { |
| 462 | self.blocking_read(offset as usize, bytes)?; | 562 | self.blocking_read(offset, bytes)?; |
| 463 | Ok(()) | 563 | Ok(()) |
| 464 | } | 564 | } |
| 465 | 565 | ||
| 466 | fn capacity(&self) -> usize { | 566 | fn capacity(&self) -> usize { |
| 467 | FLASH_SIZE | 567 | self.capacity as usize |
| 468 | } | 568 | } |
| 469 | } | 569 | } |
| 470 | 570 | ||
| 471 | impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Qspi<'d, T, FLASH_SIZE> { | 571 | impl<'d, T: Instance> NorFlash for Qspi<'d, T> { |
| 472 | const WRITE_SIZE: usize = 4; | 572 | const WRITE_SIZE: usize = 4; |
| 473 | const ERASE_SIZE: usize = 4096; | 573 | const ERASE_SIZE: usize = 4096; |
| 474 | 574 | ||
| 475 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 575 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 476 | for address in (from as usize..to as usize).step_by(<Self as NorFlash>::ERASE_SIZE) { | 576 | for address in (from..to).step_by(<Self as NorFlash>::ERASE_SIZE) { |
| 477 | self.blocking_erase(address)?; | 577 | self.blocking_erase(address)?; |
| 478 | } | 578 | } |
| 479 | Ok(()) | 579 | Ok(()) |
| 480 | } | 580 | } |
| 481 | 581 | ||
| 482 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 582 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 483 | self.blocking_write(offset as usize, bytes)?; | 583 | self.blocking_write(offset, bytes)?; |
| 484 | Ok(()) | 584 | Ok(()) |
| 485 | } | 585 | } |
| 486 | } | 586 | } |
| 487 | 587 | ||
| 488 | cfg_if::cfg_if! { | 588 | #[cfg(feature = "nightly")] |
| 489 | if #[cfg(feature = "nightly")] | 589 | mod _eh1 { |
| 490 | { | 590 | use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; |
| 491 | use embedded_storage_async::nor_flash::{AsyncNorFlash, AsyncReadNorFlash}; | ||
| 492 | use core::future::Future; | ||
| 493 | 591 | ||
| 494 | impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncNorFlash for Qspi<'d, T, FLASH_SIZE> { | 592 | use super::*; |
| 495 | const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE; | ||
| 496 | const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE; | ||
| 497 | 593 | ||
| 498 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 594 | impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> { |
| 499 | fn write<'a>(&'a mut self, offset: u32, data: &'a [u8]) -> Self::WriteFuture<'a> { | 595 | const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE; |
| 500 | async move { self.write(offset as usize, data).await } | 596 | const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE; |
| 501 | } | ||
| 502 | 597 | ||
| 503 | type EraseFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 598 | async fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { |
| 504 | fn erase<'a>(&'a mut self, from: u32, to: u32) -> Self::EraseFuture<'a> { | 599 | self.write(offset, data).await |
| 505 | async move { | ||
| 506 | for address in (from as usize..to as usize).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) { | ||
| 507 | self.erase(address).await? | ||
| 508 | } | ||
| 509 | Ok(()) | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | 600 | } |
| 513 | 601 | ||
| 514 | impl<'d, T: Instance, const FLASH_SIZE: usize> AsyncReadNorFlash for Qspi<'d, T, FLASH_SIZE> { | 602 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 515 | const READ_SIZE: usize = 4; | 603 | for address in (from..to).step_by(<Self as AsyncNorFlash>::ERASE_SIZE) { |
| 516 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 604 | self.erase(address).await? |
| 517 | fn read<'a>(&'a mut self, address: u32, data: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 518 | async move { self.read(address as usize, data).await } | ||
| 519 | } | 605 | } |
| 606 | Ok(()) | ||
| 607 | } | ||
| 608 | } | ||
| 520 | 609 | ||
| 521 | fn capacity(&self) -> usize { | 610 | impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> { |
| 522 | FLASH_SIZE | 611 | const READ_SIZE: usize = 4; |
| 523 | } | 612 | async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { |
| 613 | self.read(address, data).await | ||
| 614 | } | ||
| 615 | |||
| 616 | fn capacity(&self) -> usize { | ||
| 617 | self.capacity as usize | ||
| 524 | } | 618 | } |
| 525 | } | 619 | } |
| 526 | } | 620 | } |
| @@ -528,33 +622,35 @@ cfg_if::cfg_if! { | |||
| 528 | pub(crate) mod sealed { | 622 | pub(crate) mod sealed { |
| 529 | use embassy_sync::waitqueue::AtomicWaker; | 623 | use embassy_sync::waitqueue::AtomicWaker; |
| 530 | 624 | ||
| 531 | use super::*; | 625 | /// Peripheral static state |
| 532 | |||
| 533 | pub struct State { | 626 | pub struct State { |
| 534 | pub ready_waker: AtomicWaker, | 627 | pub waker: AtomicWaker, |
| 535 | } | 628 | } |
| 629 | |||
| 536 | impl State { | 630 | impl State { |
| 537 | pub const fn new() -> Self { | 631 | pub const fn new() -> Self { |
| 538 | Self { | 632 | Self { |
| 539 | ready_waker: AtomicWaker::new(), | 633 | waker: AtomicWaker::new(), |
| 540 | } | 634 | } |
| 541 | } | 635 | } |
| 542 | } | 636 | } |
| 543 | 637 | ||
| 544 | pub trait Instance { | 638 | pub trait Instance { |
| 545 | fn regs() -> &'static pac::qspi::RegisterBlock; | 639 | fn regs() -> &'static crate::pac::qspi::RegisterBlock; |
| 546 | fn state() -> &'static State; | 640 | fn state() -> &'static State; |
| 547 | } | 641 | } |
| 548 | } | 642 | } |
| 549 | 643 | ||
| 550 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 644 | /// QSPI peripheral instance. |
| 551 | type Interrupt: Interrupt; | 645 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 646 | /// Interrupt for this peripheral. | ||
| 647 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 552 | } | 648 | } |
| 553 | 649 | ||
| 554 | macro_rules! impl_qspi { | 650 | macro_rules! impl_qspi { |
| 555 | ($type:ident, $pac_type:ident, $irq:ident) => { | 651 | ($type:ident, $pac_type:ident, $irq:ident) => { |
| 556 | impl crate::qspi::sealed::Instance for peripherals::$type { | 652 | impl crate::qspi::sealed::Instance for peripherals::$type { |
| 557 | fn regs() -> &'static pac::qspi::RegisterBlock { | 653 | fn regs() -> &'static crate::pac::qspi::RegisterBlock { |
| 558 | unsafe { &*pac::$pac_type::ptr() } | 654 | unsafe { &*pac::$pac_type::ptr() } |
| 559 | } | 655 | } |
| 560 | fn state() -> &'static crate::qspi::sealed::State { | 656 | fn state() -> &'static crate::qspi::sealed::State { |
| @@ -563,7 +659,7 @@ macro_rules! impl_qspi { | |||
| 563 | } | 659 | } |
| 564 | } | 660 | } |
| 565 | impl crate::qspi::Instance for peripherals::$type { | 661 | impl crate::qspi::Instance for peripherals::$type { |
| 566 | type Interrupt = crate::interrupt::$irq; | 662 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 567 | } | 663 | } |
| 568 | }; | 664 | }; |
| 569 | } | 665 | } |
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 42da51d0f..923b8b467 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | //! Random Number Generator (RNG) driver. | ||
| 2 | |||
| 3 | #![macro_use] | ||
| 4 | |||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 1 | use core::ptr; | 7 | use core::ptr; |
| 2 | use core::sync::atomic::{AtomicPtr, Ordering}; | 8 | use core::sync::atomic::{AtomicPtr, Ordering}; |
| 3 | use core::task::Poll; | 9 | use core::task::Poll; |
| @@ -5,77 +11,37 @@ use core::task::Poll; | |||
| 5 | use embassy_hal_common::drop::OnDrop; | 11 | use embassy_hal_common::drop::OnDrop; |
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 12 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use futures::future::poll_fn; | ||
| 9 | 14 | ||
| 10 | use crate::interrupt::InterruptExt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 11 | use crate::peripherals::RNG; | 16 | use crate::{interrupt, Peripheral}; |
| 12 | use crate::{interrupt, pac, Peripheral}; | ||
| 13 | 17 | ||
| 14 | impl RNG { | 18 | /// Interrupt handler. |
| 15 | fn regs() -> &'static pac::rng::RegisterBlock { | 19 | pub struct InterruptHandler<T: Instance> { |
| 16 | unsafe { &*pac::RNG::ptr() } | 20 | _phantom: PhantomData<T>, |
| 17 | } | ||
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | static STATE: State = State { | 23 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 21 | ptr: AtomicPtr::new(ptr::null_mut()), | 24 | unsafe fn on_interrupt() { |
| 22 | end: AtomicPtr::new(ptr::null_mut()), | 25 | let s = T::state(); |
| 23 | waker: AtomicWaker::new(), | 26 | let r = T::regs(); |
| 24 | }; | ||
| 25 | |||
| 26 | struct State { | ||
| 27 | ptr: AtomicPtr<u8>, | ||
| 28 | end: AtomicPtr<u8>, | ||
| 29 | waker: AtomicWaker, | ||
| 30 | } | ||
| 31 | |||
| 32 | /// A wrapper around an nRF RNG peripheral. | ||
| 33 | /// | ||
| 34 | /// It has a non-blocking API, and a blocking api through `rand`. | ||
| 35 | pub struct Rng<'d> { | ||
| 36 | irq: PeripheralRef<'d, interrupt::RNG>, | ||
| 37 | } | ||
| 38 | |||
| 39 | impl<'d> Rng<'d> { | ||
| 40 | /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | ||
| 41 | /// | ||
| 42 | /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | ||
| 43 | /// e.g. using `mem::forget`. | ||
| 44 | /// | ||
| 45 | /// The synchronous API is safe. | ||
| 46 | pub fn new(_rng: impl Peripheral<P = RNG> + 'd, irq: impl Peripheral<P = interrupt::RNG> + 'd) -> Self { | ||
| 47 | into_ref!(irq); | ||
| 48 | 27 | ||
| 49 | let this = Self { irq }; | ||
| 50 | |||
| 51 | this.stop(); | ||
| 52 | this.disable_irq(); | ||
| 53 | |||
| 54 | this.irq.set_handler(Self::on_interrupt); | ||
| 55 | this.irq.unpend(); | ||
| 56 | this.irq.enable(); | ||
| 57 | |||
| 58 | this | ||
| 59 | } | ||
| 60 | |||
| 61 | fn on_interrupt(_: *mut ()) { | ||
| 62 | // Clear the event. | 28 | // Clear the event. |
| 63 | RNG::regs().events_valrdy.reset(); | 29 | r.events_valrdy.reset(); |
| 64 | 30 | ||
| 65 | // Mutate the slice within a critical section, | 31 | // Mutate the slice within a critical section, |
| 66 | // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. | 32 | // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. |
| 67 | let (ptr, end) = critical_section::with(|_| { | 33 | let (ptr, end) = critical_section::with(|_| { |
| 68 | let ptr = STATE.ptr.load(Ordering::Relaxed); | 34 | let ptr = s.ptr.load(Ordering::Relaxed); |
| 69 | // We need to make sure we haven't already filled the whole slice, | 35 | // We need to make sure we haven't already filled the whole slice, |
| 70 | // in case the interrupt fired again before the executor got back to the future. | 36 | // in case the interrupt fired again before the executor got back to the future. |
| 71 | let end = STATE.end.load(Ordering::Relaxed); | 37 | let end = s.end.load(Ordering::Relaxed); |
| 72 | if !ptr.is_null() && ptr != end { | 38 | if !ptr.is_null() && ptr != end { |
| 73 | // If the future was dropped, the pointer would have been set to null, | 39 | // If the future was dropped, the pointer would have been set to null, |
| 74 | // so we're still good to mutate the slice. | 40 | // so we're still good to mutate the slice. |
| 75 | // The safety contract of `Rng::new` means that the future can't have been dropped | 41 | // The safety contract of `Rng::new` means that the future can't have been dropped |
| 76 | // without calling its destructor. | 42 | // without calling its destructor. |
| 77 | unsafe { | 43 | unsafe { |
| 78 | *ptr = RNG::regs().value.read().value().bits(); | 44 | *ptr = r.value.read().value().bits(); |
| 79 | } | 45 | } |
| 80 | } | 46 | } |
| 81 | (ptr, end) | 47 | (ptr, end) |
| @@ -88,15 +54,15 @@ impl<'d> Rng<'d> { | |||
| 88 | } | 54 | } |
| 89 | 55 | ||
| 90 | let new_ptr = unsafe { ptr.add(1) }; | 56 | let new_ptr = unsafe { ptr.add(1) }; |
| 91 | match STATE | 57 | match s |
| 92 | .ptr | 58 | .ptr |
| 93 | .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed) | 59 | .compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed) |
| 94 | { | 60 | { |
| 95 | Ok(_) => { | 61 | Ok(_) => { |
| 96 | let end = STATE.end.load(Ordering::Relaxed); | 62 | let end = s.end.load(Ordering::Relaxed); |
| 97 | // It doesn't matter if `end` was changed under our feet, because then this will just be false. | 63 | // It doesn't matter if `end` was changed under our feet, because then this will just be false. |
| 98 | if new_ptr == end { | 64 | if new_ptr == end { |
| 99 | STATE.waker.wake(); | 65 | s.waker.wake(); |
| 100 | } | 66 | } |
| 101 | } | 67 | } |
| 102 | Err(_) => { | 68 | Err(_) => { |
| @@ -105,21 +71,53 @@ impl<'d> Rng<'d> { | |||
| 105 | } | 71 | } |
| 106 | } | 72 | } |
| 107 | } | 73 | } |
| 74 | } | ||
| 75 | |||
| 76 | /// A wrapper around an nRF RNG peripheral. | ||
| 77 | /// | ||
| 78 | /// It has a non-blocking API, and a blocking api through `rand`. | ||
| 79 | pub struct Rng<'d, T: Instance> { | ||
| 80 | _peri: PeripheralRef<'d, T>, | ||
| 81 | } | ||
| 82 | |||
| 83 | impl<'d, T: Instance> Rng<'d, T> { | ||
| 84 | /// Creates a new RNG driver from the `RNG` peripheral and interrupt. | ||
| 85 | /// | ||
| 86 | /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, | ||
| 87 | /// e.g. using `mem::forget`. | ||
| 88 | /// | ||
| 89 | /// The synchronous API is safe. | ||
| 90 | pub fn new( | ||
| 91 | rng: impl Peripheral<P = T> + 'd, | ||
| 92 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 93 | ) -> Self { | ||
| 94 | into_ref!(rng); | ||
| 95 | |||
| 96 | let this = Self { _peri: rng }; | ||
| 97 | |||
| 98 | this.stop(); | ||
| 99 | this.disable_irq(); | ||
| 100 | |||
| 101 | T::Interrupt::unpend(); | ||
| 102 | unsafe { T::Interrupt::enable() }; | ||
| 103 | |||
| 104 | this | ||
| 105 | } | ||
| 108 | 106 | ||
| 109 | fn stop(&self) { | 107 | fn stop(&self) { |
| 110 | RNG::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) | 108 | T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) |
| 111 | } | 109 | } |
| 112 | 110 | ||
| 113 | fn start(&self) { | 111 | fn start(&self) { |
| 114 | RNG::regs().tasks_start.write(|w| unsafe { w.bits(1) }) | 112 | T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) |
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | fn enable_irq(&self) { | 115 | fn enable_irq(&self) { |
| 118 | RNG::regs().intenset.write(|w| w.valrdy().set()); | 116 | T::regs().intenset.write(|w| w.valrdy().set()); |
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | fn disable_irq(&self) { | 119 | fn disable_irq(&self) { |
| 122 | RNG::regs().intenclr.write(|w| w.valrdy().clear()); | 120 | T::regs().intenclr.write(|w| w.valrdy().clear()); |
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | /// Enable or disable the RNG's bias correction. | 123 | /// Enable or disable the RNG's bias correction. |
| @@ -128,20 +126,23 @@ impl<'d> Rng<'d> { | |||
| 128 | /// However, this makes the generation of numbers slower. | 126 | /// However, this makes the generation of numbers slower. |
| 129 | /// | 127 | /// |
| 130 | /// Defaults to disabled. | 128 | /// Defaults to disabled. |
| 131 | pub fn bias_correction(&self, enable: bool) { | 129 | pub fn set_bias_correction(&self, enable: bool) { |
| 132 | RNG::regs().config.write(|w| w.dercen().bit(enable)) | 130 | T::regs().config.write(|w| w.dercen().bit(enable)) |
| 133 | } | 131 | } |
| 134 | 132 | ||
| 133 | /// Fill the buffer with random bytes. | ||
| 135 | pub async fn fill_bytes(&mut self, dest: &mut [u8]) { | 134 | pub async fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 136 | if dest.len() == 0 { | 135 | if dest.len() == 0 { |
| 137 | return; // Nothing to fill | 136 | return; // Nothing to fill |
| 138 | } | 137 | } |
| 139 | 138 | ||
| 139 | let s = T::state(); | ||
| 140 | |||
| 140 | let range = dest.as_mut_ptr_range(); | 141 | let range = dest.as_mut_ptr_range(); |
| 141 | // Even if we've preempted the interrupt, it can't preempt us again, | 142 | // Even if we've preempted the interrupt, it can't preempt us again, |
| 142 | // so we don't need to worry about the order we write these in. | 143 | // so we don't need to worry about the order we write these in. |
| 143 | STATE.ptr.store(range.start, Ordering::Relaxed); | 144 | s.ptr.store(range.start, Ordering::Relaxed); |
| 144 | STATE.end.store(range.end, Ordering::Relaxed); | 145 | s.end.store(range.end, Ordering::Relaxed); |
| 145 | 146 | ||
| 146 | self.enable_irq(); | 147 | self.enable_irq(); |
| 147 | self.start(); | 148 | self.start(); |
| @@ -151,16 +152,16 @@ impl<'d> Rng<'d> { | |||
| 151 | self.disable_irq(); | 152 | self.disable_irq(); |
| 152 | 153 | ||
| 153 | // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. | 154 | // The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here. |
| 154 | STATE.ptr.store(ptr::null_mut(), Ordering::Relaxed); | 155 | s.ptr.store(ptr::null_mut(), Ordering::Relaxed); |
| 155 | STATE.end.store(ptr::null_mut(), Ordering::Relaxed); | 156 | s.end.store(ptr::null_mut(), Ordering::Relaxed); |
| 156 | }); | 157 | }); |
| 157 | 158 | ||
| 158 | poll_fn(|cx| { | 159 | poll_fn(|cx| { |
| 159 | STATE.waker.register(cx.waker()); | 160 | s.waker.register(cx.waker()); |
| 160 | 161 | ||
| 161 | // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. | 162 | // The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`. |
| 162 | let end = STATE.end.load(Ordering::Relaxed); | 163 | let end = s.end.load(Ordering::Relaxed); |
| 163 | let ptr = STATE.ptr.load(Ordering::Relaxed); | 164 | let ptr = s.ptr.load(Ordering::Relaxed); |
| 164 | 165 | ||
| 165 | if ptr == end { | 166 | if ptr == end { |
| 166 | // We're done. | 167 | // We're done. |
| @@ -175,11 +176,12 @@ impl<'d> Rng<'d> { | |||
| 175 | drop(on_drop); | 176 | drop(on_drop); |
| 176 | } | 177 | } |
| 177 | 178 | ||
| 179 | /// Fill the buffer with random bytes, blocking version. | ||
| 178 | pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { | 180 | pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { |
| 179 | self.start(); | 181 | self.start(); |
| 180 | 182 | ||
| 181 | for byte in dest.iter_mut() { | 183 | for byte in dest.iter_mut() { |
| 182 | let regs = RNG::regs(); | 184 | let regs = T::regs(); |
| 183 | while regs.events_valrdy.read().bits() == 0 {} | 185 | while regs.events_valrdy.read().bits() == 0 {} |
| 184 | regs.events_valrdy.reset(); | 186 | regs.events_valrdy.reset(); |
| 185 | *byte = regs.value.read().value().bits(); | 187 | *byte = regs.value.read().value().bits(); |
| @@ -189,13 +191,16 @@ impl<'d> Rng<'d> { | |||
| 189 | } | 191 | } |
| 190 | } | 192 | } |
| 191 | 193 | ||
| 192 | impl<'d> Drop for Rng<'d> { | 194 | impl<'d, T: Instance> Drop for Rng<'d, T> { |
| 193 | fn drop(&mut self) { | 195 | fn drop(&mut self) { |
| 194 | self.irq.disable() | 196 | self.stop(); |
| 197 | let s = T::state(); | ||
| 198 | s.ptr.store(ptr::null_mut(), Ordering::Relaxed); | ||
| 199 | s.end.store(ptr::null_mut(), Ordering::Relaxed); | ||
| 195 | } | 200 | } |
| 196 | } | 201 | } |
| 197 | 202 | ||
| 198 | impl<'d> rand_core::RngCore for Rng<'d> { | 203 | impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { |
| 199 | fn fill_bytes(&mut self, dest: &mut [u8]) { | 204 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
| 200 | self.blocking_fill_bytes(dest); | 205 | self.blocking_fill_bytes(dest); |
| 201 | } | 206 | } |
| @@ -219,4 +224,53 @@ impl<'d> rand_core::RngCore for Rng<'d> { | |||
| 219 | } | 224 | } |
| 220 | } | 225 | } |
| 221 | 226 | ||
| 222 | impl<'d> rand_core::CryptoRng for Rng<'d> {} | 227 | impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} |
| 228 | |||
| 229 | pub(crate) mod sealed { | ||
| 230 | use super::*; | ||
| 231 | |||
| 232 | /// Peripheral static state | ||
| 233 | pub struct State { | ||
| 234 | pub ptr: AtomicPtr<u8>, | ||
| 235 | pub end: AtomicPtr<u8>, | ||
| 236 | pub waker: AtomicWaker, | ||
| 237 | } | ||
| 238 | |||
| 239 | impl State { | ||
| 240 | pub const fn new() -> Self { | ||
| 241 | Self { | ||
| 242 | ptr: AtomicPtr::new(ptr::null_mut()), | ||
| 243 | end: AtomicPtr::new(ptr::null_mut()), | ||
| 244 | waker: AtomicWaker::new(), | ||
| 245 | } | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | pub trait Instance { | ||
| 250 | fn regs() -> &'static crate::pac::rng::RegisterBlock; | ||
| 251 | fn state() -> &'static State; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | /// RNG peripheral instance. | ||
| 256 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | ||
| 257 | /// Interrupt for this peripheral. | ||
| 258 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 259 | } | ||
| 260 | |||
| 261 | macro_rules! impl_rng { | ||
| 262 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 263 | impl crate::rng::sealed::Instance for peripherals::$type { | ||
| 264 | fn regs() -> &'static crate::pac::rng::RegisterBlock { | ||
| 265 | unsafe { &*pac::$pac_type::ptr() } | ||
| 266 | } | ||
| 267 | fn state() -> &'static crate::rng::sealed::State { | ||
| 268 | static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new(); | ||
| 269 | &STATE | ||
| 270 | } | ||
| 271 | } | ||
| 272 | impl crate::rng::Instance for peripherals::$type { | ||
| 273 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 274 | } | ||
| 275 | }; | ||
| 276 | } | ||
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 7dc66349e..23292924c 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -1,11 +1,14 @@ | |||
| 1 | //! Successive Approximation Analog-to-Digital Converter (SAADC) driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 5 | use core::future::poll_fn; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 6 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 7 | use core::task::Poll; |
| 5 | 8 | ||
| 9 | use embassy_hal_common::drop::OnDrop; | ||
| 6 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; | 10 | use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use futures::future::poll_fn; | ||
| 9 | use pac::{saadc, SAADC}; | 12 | use pac::{saadc, SAADC}; |
| 10 | use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A}; | 13 | use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A}; |
| 11 | // We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same | 14 | // We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same |
| @@ -19,14 +22,36 @@ use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | |||
| 19 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 20 | use crate::{interrupt, pac, peripherals, Peripheral}; | 23 | use crate::{interrupt, pac, peripherals, Peripheral}; |
| 21 | 24 | ||
| 25 | /// SAADC error | ||
| 22 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 26 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 27 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 24 | #[non_exhaustive] | 28 | #[non_exhaustive] |
| 25 | pub enum Error {} | 29 | pub enum Error {} |
| 26 | 30 | ||
| 27 | /// One-shot and continuous SAADC. | 31 | /// Interrupt handler. |
| 28 | pub struct Saadc<'d, const N: usize> { | 32 | pub struct InterruptHandler { |
| 29 | _p: PeripheralRef<'d, peripherals::SAADC>, | 33 | _private: (), |
| 34 | } | ||
| 35 | |||
| 36 | impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler { | ||
| 37 | unsafe fn on_interrupt() { | ||
| 38 | let r = unsafe { &*SAADC::ptr() }; | ||
| 39 | |||
| 40 | if r.events_calibratedone.read().bits() != 0 { | ||
| 41 | r.intenclr.write(|w| w.calibratedone().clear()); | ||
| 42 | WAKER.wake(); | ||
| 43 | } | ||
| 44 | |||
| 45 | if r.events_end.read().bits() != 0 { | ||
| 46 | r.intenclr.write(|w| w.end().clear()); | ||
| 47 | WAKER.wake(); | ||
| 48 | } | ||
| 49 | |||
| 50 | if r.events_started.read().bits() != 0 { | ||
| 51 | r.intenclr.write(|w| w.started().clear()); | ||
| 52 | WAKER.wake(); | ||
| 53 | } | ||
| 54 | } | ||
| 30 | } | 55 | } |
| 31 | 56 | ||
| 32 | static WAKER: AtomicWaker = AtomicWaker::new(); | 57 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| @@ -101,24 +126,29 @@ impl<'d> ChannelConfig<'d> { | |||
| 101 | } | 126 | } |
| 102 | } | 127 | } |
| 103 | 128 | ||
| 104 | /// The state of a continuously running sampler. While it reflects | 129 | /// Value returned by the SAADC callback, deciding what happens next. |
| 105 | /// the progress of a sampler, it also signals what should be done | ||
| 106 | /// next. For example, if the sampler has stopped then the Saadc implementation | ||
| 107 | /// can then tear down its infrastructure. | ||
| 108 | #[derive(PartialEq)] | 130 | #[derive(PartialEq)] |
| 109 | pub enum SamplerState { | 131 | pub enum CallbackResult { |
| 110 | Sampled, | 132 | /// The SAADC should keep sampling and calling the callback. |
| 111 | Stopped, | 133 | Continue, |
| 134 | /// The SAADC should stop sampling, and return. | ||
| 135 | Stop, | ||
| 136 | } | ||
| 137 | |||
| 138 | /// One-shot and continuous SAADC. | ||
| 139 | pub struct Saadc<'d, const N: usize> { | ||
| 140 | _p: PeripheralRef<'d, peripherals::SAADC>, | ||
| 112 | } | 141 | } |
| 113 | 142 | ||
| 114 | impl<'d, const N: usize> Saadc<'d, N> { | 143 | impl<'d, const N: usize> Saadc<'d, N> { |
| 144 | /// Create a new SAADC driver. | ||
| 115 | pub fn new( | 145 | pub fn new( |
| 116 | saadc: impl Peripheral<P = peripherals::SAADC> + 'd, | 146 | saadc: impl Peripheral<P = peripherals::SAADC> + 'd, |
| 117 | irq: impl Peripheral<P = interrupt::SAADC> + 'd, | 147 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd, |
| 118 | config: Config, | 148 | config: Config, |
| 119 | channel_configs: [ChannelConfig; N], | 149 | channel_configs: [ChannelConfig; N], |
| 120 | ) -> Self { | 150 | ) -> Self { |
| 121 | into_ref!(saadc, irq); | 151 | into_ref!(saadc); |
| 122 | 152 | ||
| 123 | let r = unsafe { &*SAADC::ptr() }; | 153 | let r = unsafe { &*SAADC::ptr() }; |
| 124 | 154 | ||
| @@ -159,32 +189,12 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 159 | // Disable all events interrupts | 189 | // Disable all events interrupts |
| 160 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | 190 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); |
| 161 | 191 | ||
| 162 | irq.set_handler(Self::on_interrupt); | 192 | interrupt::SAADC.unpend(); |
| 163 | irq.unpend(); | 193 | unsafe { interrupt::SAADC.enable() }; |
| 164 | irq.enable(); | ||
| 165 | 194 | ||
| 166 | Self { _p: saadc } | 195 | Self { _p: saadc } |
| 167 | } | 196 | } |
| 168 | 197 | ||
| 169 | fn on_interrupt(_ctx: *mut ()) { | ||
| 170 | let r = Self::regs(); | ||
| 171 | |||
| 172 | if r.events_calibratedone.read().bits() != 0 { | ||
| 173 | r.intenclr.write(|w| w.calibratedone().clear()); | ||
| 174 | WAKER.wake(); | ||
| 175 | } | ||
| 176 | |||
| 177 | if r.events_end.read().bits() != 0 { | ||
| 178 | r.intenclr.write(|w| w.end().clear()); | ||
| 179 | WAKER.wake(); | ||
| 180 | } | ||
| 181 | |||
| 182 | if r.events_started.read().bits() != 0 { | ||
| 183 | r.intenclr.write(|w| w.started().clear()); | ||
| 184 | WAKER.wake(); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | fn regs() -> &'static saadc::RegisterBlock { | 198 | fn regs() -> &'static saadc::RegisterBlock { |
| 189 | unsafe { &*SAADC::ptr() } | 199 | unsafe { &*SAADC::ptr() } |
| 190 | } | 200 | } |
| @@ -219,7 +229,13 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 219 | } | 229 | } |
| 220 | 230 | ||
| 221 | /// One shot sampling. The buffer must be the same size as the number of channels configured. | 231 | /// One shot sampling. The buffer must be the same size as the number of channels configured. |
| 232 | /// The sampling is stopped prior to returning in order to reduce power consumption (power | ||
| 233 | /// consumption remains higher if sampling is not stopped explicitly). Cancellation will | ||
| 234 | /// also cause the sampling to be stopped. | ||
| 222 | pub async fn sample(&mut self, buf: &mut [i16; N]) { | 235 | pub async fn sample(&mut self, buf: &mut [i16; N]) { |
| 236 | // In case the future is dropped, stop the task and wait for it to end. | ||
| 237 | let on_drop = OnDrop::new(Self::stop_sampling_immediately); | ||
| 238 | |||
| 223 | let r = Self::regs(); | 239 | let r = Self::regs(); |
| 224 | 240 | ||
| 225 | // Set up the DMA | 241 | // Set up the DMA |
| @@ -251,6 +267,8 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 251 | Poll::Pending | 267 | Poll::Pending |
| 252 | }) | 268 | }) |
| 253 | .await; | 269 | .await; |
| 270 | |||
| 271 | drop(on_drop); | ||
| 254 | } | 272 | } |
| 255 | 273 | ||
| 256 | /// Continuous sampling with double buffers. | 274 | /// Continuous sampling with double buffers. |
| @@ -270,7 +288,13 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 270 | /// taken to acquire the samples into a single buffer. You should measure the | 288 | /// taken to acquire the samples into a single buffer. You should measure the |
| 271 | /// time taken by the callback and set the sample buffer size accordingly. | 289 | /// time taken by the callback and set the sample buffer size accordingly. |
| 272 | /// Exceeding this time can lead to samples becoming dropped. | 290 | /// Exceeding this time can lead to samples becoming dropped. |
| 273 | pub async fn run_task_sampler<S, T: TimerInstance, const N0: usize>( | 291 | /// |
| 292 | /// The sampling is stopped prior to returning in order to reduce power consumption (power | ||
| 293 | /// consumption remains higher if sampling is not stopped explicitly), and to | ||
| 294 | /// free the buffers from being used by the peripheral. Cancellation will | ||
| 295 | /// also cause the sampling to be stopped. | ||
| 296 | |||
| 297 | pub async fn run_task_sampler<F, T: TimerInstance, const N0: usize>( | ||
| 274 | &mut self, | 298 | &mut self, |
| 275 | timer: &mut T, | 299 | timer: &mut T, |
| 276 | ppi_ch1: &mut impl ConfigurableChannel, | 300 | ppi_ch1: &mut impl ConfigurableChannel, |
| @@ -278,9 +302,9 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 278 | frequency: Frequency, | 302 | frequency: Frequency, |
| 279 | sample_counter: u32, | 303 | sample_counter: u32, |
| 280 | bufs: &mut [[[i16; N]; N0]; 2], | 304 | bufs: &mut [[[i16; N]; N0]; 2], |
| 281 | sampler: S, | 305 | callback: F, |
| 282 | ) where | 306 | ) where |
| 283 | S: FnMut(&[[i16; N]]) -> SamplerState, | 307 | F: FnMut(&[[i16; N]]) -> CallbackResult, |
| 284 | { | 308 | { |
| 285 | let r = Self::regs(); | 309 | let r = Self::regs(); |
| 286 | 310 | ||
| @@ -291,12 +315,14 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 291 | Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_end), Task::from_reg(&r.tasks_start)); | 315 | Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_end), Task::from_reg(&r.tasks_start)); |
| 292 | start_ppi.enable(); | 316 | start_ppi.enable(); |
| 293 | 317 | ||
| 294 | let mut timer = Timer::new(timer); | 318 | let timer = Timer::new(timer); |
| 295 | timer.set_frequency(frequency); | 319 | timer.set_frequency(frequency); |
| 296 | timer.cc(0).write(sample_counter); | 320 | timer.cc(0).write(sample_counter); |
| 297 | timer.cc(0).short_compare_clear(); | 321 | timer.cc(0).short_compare_clear(); |
| 298 | 322 | ||
| 299 | let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer.cc(0).event_compare(), Task::from_reg(&r.tasks_sample)); | 323 | let timer_cc = timer.cc(0); |
| 324 | |||
| 325 | let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample)); | ||
| 300 | 326 | ||
| 301 | timer.start(); | 327 | timer.start(); |
| 302 | 328 | ||
| @@ -306,21 +332,24 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 306 | || { | 332 | || { |
| 307 | sample_ppi.enable(); | 333 | sample_ppi.enable(); |
| 308 | }, | 334 | }, |
| 309 | sampler, | 335 | callback, |
| 310 | ) | 336 | ) |
| 311 | .await; | 337 | .await; |
| 312 | } | 338 | } |
| 313 | 339 | ||
| 314 | async fn run_sampler<I, S, const N0: usize>( | 340 | async fn run_sampler<I, F, const N0: usize>( |
| 315 | &mut self, | 341 | &mut self, |
| 316 | bufs: &mut [[[i16; N]; N0]; 2], | 342 | bufs: &mut [[[i16; N]; N0]; 2], |
| 317 | sample_rate_divisor: Option<u16>, | 343 | sample_rate_divisor: Option<u16>, |
| 318 | mut init: I, | 344 | mut init: I, |
| 319 | mut sampler: S, | 345 | mut callback: F, |
| 320 | ) where | 346 | ) where |
| 321 | I: FnMut(), | 347 | I: FnMut(), |
| 322 | S: FnMut(&[[i16; N]]) -> SamplerState, | 348 | F: FnMut(&[[i16; N]]) -> CallbackResult, |
| 323 | { | 349 | { |
| 350 | // In case the future is dropped, stop the task and wait for it to end. | ||
| 351 | let on_drop = OnDrop::new(Self::stop_sampling_immediately); | ||
| 352 | |||
| 324 | let r = Self::regs(); | 353 | let r = Self::regs(); |
| 325 | 354 | ||
| 326 | // Establish mode and sample rate | 355 | // Establish mode and sample rate |
| @@ -366,7 +395,7 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 366 | let mut current_buffer = 0; | 395 | let mut current_buffer = 0; |
| 367 | 396 | ||
| 368 | // Wait for events and complete when the sampler indicates it has had enough. | 397 | // Wait for events and complete when the sampler indicates it has had enough. |
| 369 | poll_fn(|cx| { | 398 | let r = poll_fn(|cx| { |
| 370 | let r = Self::regs(); | 399 | let r = Self::regs(); |
| 371 | 400 | ||
| 372 | WAKER.register(cx.waker()); | 401 | WAKER.register(cx.waker()); |
| @@ -377,12 +406,15 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 377 | r.events_end.reset(); | 406 | r.events_end.reset(); |
| 378 | r.intenset.write(|w| w.end().set()); | 407 | r.intenset.write(|w| w.end().set()); |
| 379 | 408 | ||
| 380 | if sampler(&bufs[current_buffer]) == SamplerState::Sampled { | 409 | match callback(&bufs[current_buffer]) { |
| 381 | let next_buffer = 1 - current_buffer; | 410 | CallbackResult::Continue => { |
| 382 | current_buffer = next_buffer; | 411 | let next_buffer = 1 - current_buffer; |
| 383 | } else { | 412 | current_buffer = next_buffer; |
| 384 | return Poll::Ready(()); | 413 | } |
| 385 | }; | 414 | CallbackResult::Stop => { |
| 415 | return Poll::Ready(()); | ||
| 416 | } | ||
| 417 | } | ||
| 386 | } | 418 | } |
| 387 | 419 | ||
| 388 | if r.events_started.read().bits() != 0 { | 420 | if r.events_started.read().bits() != 0 { |
| @@ -403,6 +435,23 @@ impl<'d, const N: usize> Saadc<'d, N> { | |||
| 403 | Poll::Pending | 435 | Poll::Pending |
| 404 | }) | 436 | }) |
| 405 | .await; | 437 | .await; |
| 438 | |||
| 439 | drop(on_drop); | ||
| 440 | |||
| 441 | r | ||
| 442 | } | ||
| 443 | |||
| 444 | // Stop sampling and wait for it to stop in a blocking fashion | ||
| 445 | fn stop_sampling_immediately() { | ||
| 446 | let r = Self::regs(); | ||
| 447 | |||
| 448 | compiler_fence(Ordering::SeqCst); | ||
| 449 | |||
| 450 | r.events_stopped.reset(); | ||
| 451 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 452 | |||
| 453 | while r.events_stopped.read().bits() == 0 {} | ||
| 454 | r.events_stopped.reset(); | ||
| 406 | } | 455 | } |
| 407 | } | 456 | } |
| 408 | 457 | ||
| @@ -423,7 +472,7 @@ impl<'d> Saadc<'d, 1> { | |||
| 423 | sample_rate_divisor: u16, | 472 | sample_rate_divisor: u16, |
| 424 | sampler: S, | 473 | sampler: S, |
| 425 | ) where | 474 | ) where |
| 426 | S: FnMut(&[[i16; 1]]) -> SamplerState, | 475 | S: FnMut(&[[i16; 1]]) -> CallbackResult, |
| 427 | { | 476 | { |
| 428 | self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler).await; | 477 | self.run_sampler(bufs, Some(sample_rate_divisor), || {}, sampler).await; |
| 429 | } | 478 | } |
| @@ -623,6 +672,10 @@ pub(crate) mod sealed { | |||
| 623 | 672 | ||
| 624 | /// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal. | 673 | /// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal. |
| 625 | pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static { | 674 | pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static { |
| 675 | /// Convert this SAADC input to a type-erased `AnyInput`. | ||
| 676 | /// | ||
| 677 | /// This allows using several inputs in situations that might require | ||
| 678 | /// them to be the same type, like putting them in an array. | ||
| 626 | fn degrade_saadc(self) -> AnyInput { | 679 | fn degrade_saadc(self) -> AnyInput { |
| 627 | AnyInput { | 680 | AnyInput { |
| 628 | channel: self.channel(), | 681 | channel: self.channel(), |
| @@ -630,6 +683,10 @@ pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + | |||
| 630 | } | 683 | } |
| 631 | } | 684 | } |
| 632 | 685 | ||
| 686 | /// A type-erased SAADC input. | ||
| 687 | /// | ||
| 688 | /// This allows using several inputs in situations that might require | ||
| 689 | /// them to be the same type, like putting them in an array. | ||
| 633 | pub struct AnyInput { | 690 | pub struct AnyInput { |
| 634 | channel: InputChannel, | 691 | channel: InputChannel, |
| 635 | } | 692 | } |
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index be2fc02fc..b7dc332e9 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -1,42 +1,50 @@ | |||
| 1 | //! Serial Peripheral Instance in master mode (SPIM) driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 3 | use core::sync::atomic::{compiler_fence, Ordering}; | 7 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 4 | use core::task::Poll; | 8 | use core::task::Poll; |
| 5 | 9 | ||
| 6 | use embassy_embedded_hal::SetConfig; | 10 | use embassy_embedded_hal::SetConfig; |
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | 11 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 8 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 12 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 9 | use futures::future::poll_fn; | ||
| 10 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | 13 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; |
| 11 | 14 | ||
| 12 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | 15 | use crate::chip::FORCE_COPY_BUFFER_SIZE; |
| 13 | use crate::gpio::sealed::Pin as _; | 16 | use crate::gpio::sealed::Pin as _; |
| 14 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 17 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 15 | use crate::interrupt::{Interrupt, InterruptExt}; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 17 | use crate::{pac, Peripheral}; | 20 | use crate::{interrupt, pac, Peripheral}; |
| 18 | 21 | ||
| 22 | /// SPIM error | ||
| 19 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 23 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 24 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 21 | #[non_exhaustive] | 25 | #[non_exhaustive] |
| 22 | pub enum Error { | 26 | pub enum Error { |
| 27 | /// TX buffer was too long. | ||
| 23 | TxBufferTooLong, | 28 | TxBufferTooLong, |
| 29 | /// RX buffer was too long. | ||
| 24 | RxBufferTooLong, | 30 | RxBufferTooLong, |
| 25 | /// EasyDMA can only read from data memory, read only buffers in flash will fail. | 31 | /// EasyDMA can only read from data memory, read only buffers in flash will fail. |
| 26 | DMABufferNotInDataMemory, | 32 | BufferNotInRAM, |
| 27 | } | ||
| 28 | |||
| 29 | /// Interface for the SPIM peripheral using EasyDMA to offload the transmission and reception workload. | ||
| 30 | /// | ||
| 31 | /// For more details about EasyDMA, consult the module documentation. | ||
| 32 | pub struct Spim<'d, T: Instance> { | ||
| 33 | _p: PeripheralRef<'d, T>, | ||
| 34 | } | 33 | } |
| 35 | 34 | ||
| 35 | /// SPIM configuration. | ||
| 36 | #[non_exhaustive] | 36 | #[non_exhaustive] |
| 37 | pub struct Config { | 37 | pub struct Config { |
| 38 | /// Frequency | ||
| 38 | pub frequency: Frequency, | 39 | pub frequency: Frequency, |
| 40 | |||
| 41 | /// SPI mode | ||
| 39 | pub mode: Mode, | 42 | pub mode: Mode, |
| 43 | |||
| 44 | /// Overread character. | ||
| 45 | /// | ||
| 46 | /// When doing bidirectional transfers, if the TX buffer is shorter than the RX buffer, | ||
| 47 | /// this byte will be transmitted in the MOSI line for the left-over bytes. | ||
| 40 | pub orc: u8, | 48 | pub orc: u8, |
| 41 | } | 49 | } |
| 42 | 50 | ||
| @@ -50,10 +58,33 @@ impl Default for Config { | |||
| 50 | } | 58 | } |
| 51 | } | 59 | } |
| 52 | 60 | ||
| 61 | /// Interrupt handler. | ||
| 62 | pub struct InterruptHandler<T: Instance> { | ||
| 63 | _phantom: PhantomData<T>, | ||
| 64 | } | ||
| 65 | |||
| 66 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 67 | unsafe fn on_interrupt() { | ||
| 68 | let r = T::regs(); | ||
| 69 | let s = T::state(); | ||
| 70 | |||
| 71 | if r.events_end.read().bits() != 0 { | ||
| 72 | s.end_waker.wake(); | ||
| 73 | r.intenclr.write(|w| w.end().clear()); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /// SPIM driver. | ||
| 79 | pub struct Spim<'d, T: Instance> { | ||
| 80 | _p: PeripheralRef<'d, T>, | ||
| 81 | } | ||
| 82 | |||
| 53 | impl<'d, T: Instance> Spim<'d, T> { | 83 | impl<'d, T: Instance> Spim<'d, T> { |
| 84 | /// Create a new SPIM driver. | ||
| 54 | pub fn new( | 85 | pub fn new( |
| 55 | spim: impl Peripheral<P = T> + 'd, | 86 | spim: impl Peripheral<P = T> + 'd, |
| 56 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 87 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 57 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 88 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 58 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 89 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| 59 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | 90 | mosi: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -62,7 +93,6 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 62 | into_ref!(sck, miso, mosi); | 93 | into_ref!(sck, miso, mosi); |
| 63 | Self::new_inner( | 94 | Self::new_inner( |
| 64 | spim, | 95 | spim, |
| 65 | irq, | ||
| 66 | sck.map_into(), | 96 | sck.map_into(), |
| 67 | Some(miso.map_into()), | 97 | Some(miso.map_into()), |
| 68 | Some(mosi.map_into()), | 98 | Some(mosi.map_into()), |
| @@ -70,37 +100,38 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 70 | ) | 100 | ) |
| 71 | } | 101 | } |
| 72 | 102 | ||
| 103 | /// Create a new SPIM driver, capable of TX only (MOSI only). | ||
| 73 | pub fn new_txonly( | 104 | pub fn new_txonly( |
| 74 | spim: impl Peripheral<P = T> + 'd, | 105 | spim: impl Peripheral<P = T> + 'd, |
| 75 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 106 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 76 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 107 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 77 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | 108 | mosi: impl Peripheral<P = impl GpioPin> + 'd, |
| 78 | config: Config, | 109 | config: Config, |
| 79 | ) -> Self { | 110 | ) -> Self { |
| 80 | into_ref!(sck, mosi); | 111 | into_ref!(sck, mosi); |
| 81 | Self::new_inner(spim, irq, sck.map_into(), None, Some(mosi.map_into()), config) | 112 | Self::new_inner(spim, sck.map_into(), None, Some(mosi.map_into()), config) |
| 82 | } | 113 | } |
| 83 | 114 | ||
| 115 | /// Create a new SPIM driver, capable of RX only (MISO only). | ||
| 84 | pub fn new_rxonly( | 116 | pub fn new_rxonly( |
| 85 | spim: impl Peripheral<P = T> + 'd, | 117 | spim: impl Peripheral<P = T> + 'd, |
| 86 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 118 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 87 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 119 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 88 | miso: impl Peripheral<P = impl GpioPin> + 'd, | 120 | miso: impl Peripheral<P = impl GpioPin> + 'd, |
| 89 | config: Config, | 121 | config: Config, |
| 90 | ) -> Self { | 122 | ) -> Self { |
| 91 | into_ref!(sck, miso); | 123 | into_ref!(sck, miso); |
| 92 | Self::new_inner(spim, irq, sck.map_into(), Some(miso.map_into()), None, config) | 124 | Self::new_inner(spim, sck.map_into(), Some(miso.map_into()), None, config) |
| 93 | } | 125 | } |
| 94 | 126 | ||
| 95 | fn new_inner( | 127 | fn new_inner( |
| 96 | spim: impl Peripheral<P = T> + 'd, | 128 | spim: impl Peripheral<P = T> + 'd, |
| 97 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 98 | sck: PeripheralRef<'d, AnyPin>, | 129 | sck: PeripheralRef<'d, AnyPin>, |
| 99 | miso: Option<PeripheralRef<'d, AnyPin>>, | 130 | miso: Option<PeripheralRef<'d, AnyPin>>, |
| 100 | mosi: Option<PeripheralRef<'d, AnyPin>>, | 131 | mosi: Option<PeripheralRef<'d, AnyPin>>, |
| 101 | config: Config, | 132 | config: Config, |
| 102 | ) -> Self { | 133 | ) -> Self { |
| 103 | into_ref!(spim, irq); | 134 | into_ref!(spim); |
| 104 | 135 | ||
| 105 | let r = T::regs(); | 136 | let r = T::regs(); |
| 106 | 137 | ||
| @@ -176,25 +207,14 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 176 | // Disable all events interrupts | 207 | // Disable all events interrupts |
| 177 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | 208 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |
| 178 | 209 | ||
| 179 | irq.set_handler(Self::on_interrupt); | 210 | T::Interrupt::unpend(); |
| 180 | irq.unpend(); | 211 | unsafe { T::Interrupt::enable() }; |
| 181 | irq.enable(); | ||
| 182 | 212 | ||
| 183 | Self { _p: spim } | 213 | Self { _p: spim } |
| 184 | } | 214 | } |
| 185 | 215 | ||
| 186 | fn on_interrupt(_: *mut ()) { | ||
| 187 | let r = T::regs(); | ||
| 188 | let s = T::state(); | ||
| 189 | |||
| 190 | if r.events_end.read().bits() != 0 { | ||
| 191 | s.end_waker.wake(); | ||
| 192 | r.intenclr.write(|w| w.end().clear()); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { | 216 | fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { |
| 197 | slice_in_ram_or(tx, Error::DMABufferNotInDataMemory)?; | 217 | slice_in_ram_or(tx, Error::BufferNotInRAM)?; |
| 198 | // NOTE: RAM slice check for rx is not necessary, as a mutable | 218 | // NOTE: RAM slice check for rx is not necessary, as a mutable |
| 199 | // slice can only be built from data located in RAM. | 219 | // slice can only be built from data located in RAM. |
| 200 | 220 | ||
| @@ -236,7 +256,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 236 | fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { | 256 | fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { |
| 237 | match self.blocking_inner_from_ram(rx, tx) { | 257 | match self.blocking_inner_from_ram(rx, tx) { |
| 238 | Ok(_) => Ok(()), | 258 | Ok(_) => Ok(()), |
| 239 | Err(Error::DMABufferNotInDataMemory) => { | 259 | Err(Error::BufferNotInRAM) => { |
| 240 | trace!("Copying SPIM tx buffer into RAM for DMA"); | 260 | trace!("Copying SPIM tx buffer into RAM for DMA"); |
| 241 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; | 261 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; |
| 242 | tx_ram_buf.copy_from_slice(tx); | 262 | tx_ram_buf.copy_from_slice(tx); |
| @@ -268,7 +288,7 @@ impl<'d, T: Instance> Spim<'d, T> { | |||
| 268 | async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { | 288 | async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { |
| 269 | match self.async_inner_from_ram(rx, tx).await { | 289 | match self.async_inner_from_ram(rx, tx).await { |
| 270 | Ok(_) => Ok(()), | 290 | Ok(_) => Ok(()), |
| 271 | Err(Error::DMABufferNotInDataMemory) => { | 291 | Err(Error::BufferNotInRAM) => { |
| 272 | trace!("Copying SPIM tx buffer into RAM for DMA"); | 292 | trace!("Copying SPIM tx buffer into RAM for DMA"); |
| 273 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; | 293 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; |
| 274 | tx_ram_buf.copy_from_slice(tx); | 294 | tx_ram_buf.copy_from_slice(tx); |
| @@ -385,8 +405,10 @@ pub(crate) mod sealed { | |||
| 385 | } | 405 | } |
| 386 | } | 406 | } |
| 387 | 407 | ||
| 408 | /// SPIM peripheral instance | ||
| 388 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 409 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 389 | type Interrupt: Interrupt; | 410 | /// Interrupt for this peripheral. |
| 411 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 390 | } | 412 | } |
| 391 | 413 | ||
| 392 | macro_rules! impl_spim { | 414 | macro_rules! impl_spim { |
| @@ -401,7 +423,7 @@ macro_rules! impl_spim { | |||
| 401 | } | 423 | } |
| 402 | } | 424 | } |
| 403 | impl crate::spim::Instance for peripherals::$type { | 425 | impl crate::spim::Instance for peripherals::$type { |
| 404 | type Interrupt = crate::interrupt::$irq; | 426 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 405 | } | 427 | } |
| 406 | }; | 428 | }; |
| 407 | } | 429 | } |
| @@ -437,7 +459,7 @@ mod eh1 { | |||
| 437 | match *self { | 459 | match *self { |
| 438 | Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, | 460 | Self::TxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, |
| 439 | Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, | 461 | Self::RxBufferTooLong => embedded_hal_1::spi::ErrorKind::Other, |
| 440 | Self::DMABufferNotInDataMemory => embedded_hal_1::spi::ErrorKind::Other, | 462 | Self::BufferNotInRAM => embedded_hal_1::spi::ErrorKind::Other, |
| 441 | } | 463 | } |
| 442 | } | 464 | } |
| 443 | } | 465 | } |
| @@ -446,25 +468,19 @@ mod eh1 { | |||
| 446 | type Error = Error; | 468 | type Error = Error; |
| 447 | } | 469 | } |
| 448 | 470 | ||
| 449 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusFlush for Spim<'d, T> { | 471 | impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> { |
| 450 | fn flush(&mut self) -> Result<(), Self::Error> { | 472 | fn flush(&mut self) -> Result<(), Self::Error> { |
| 451 | Ok(()) | 473 | Ok(()) |
| 452 | } | 474 | } |
| 453 | } | ||
| 454 | 475 | ||
| 455 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusRead<u8> for Spim<'d, T> { | ||
| 456 | fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { | 476 | fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { |
| 457 | self.blocking_transfer(words, &[]) | 477 | self.blocking_transfer(words, &[]) |
| 458 | } | 478 | } |
| 459 | } | ||
| 460 | 479 | ||
| 461 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBusWrite<u8> for Spim<'d, T> { | ||
| 462 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { | 480 | fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { |
| 463 | self.blocking_write(words) | 481 | self.blocking_write(words) |
| 464 | } | 482 | } |
| 465 | } | ||
| 466 | 483 | ||
| 467 | impl<'d, T: Instance> embedded_hal_1::spi::blocking::SpiBus<u8> for Spim<'d, T> { | ||
| 468 | fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { | 484 | fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { |
| 469 | self.blocking_transfer(read, write) | 485 | self.blocking_transfer(read, write) |
| 470 | } | 486 | } |
| @@ -475,49 +491,30 @@ mod eh1 { | |||
| 475 | } | 491 | } |
| 476 | } | 492 | } |
| 477 | 493 | ||
| 478 | cfg_if::cfg_if! { | 494 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] |
| 479 | if #[cfg(all(feature = "unstable-traits", feature = "nightly"))] { | 495 | mod eha { |
| 480 | use core::future::Future; | ||
| 481 | 496 | ||
| 482 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusFlush for Spim<'d, T> { | 497 | use super::*; |
| 483 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 484 | 498 | ||
| 485 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | 499 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> { |
| 486 | async move { Ok(()) } | 500 | async fn flush(&mut self) -> Result<(), Error> { |
| 487 | } | 501 | Ok(()) |
| 488 | } | 502 | } |
| 489 | 503 | ||
| 490 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusRead<u8> for Spim<'d, T> { | 504 | async fn read(&mut self, words: &mut [u8]) -> Result<(), Error> { |
| 491 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 505 | self.read(words).await |
| 492 | |||
| 493 | fn read<'a>(&'a mut self, words: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 494 | self.read(words) | ||
| 495 | } | ||
| 496 | } | 506 | } |
| 497 | 507 | ||
| 498 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBusWrite<u8> for Spim<'d, T> { | 508 | async fn write(&mut self, data: &[u8]) -> Result<(), Error> { |
| 499 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 509 | self.write(data).await |
| 500 | |||
| 501 | fn write<'a>(&'a mut self, data: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 502 | self.write(data) | ||
| 503 | } | ||
| 504 | } | 510 | } |
| 505 | 511 | ||
| 506 | impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> { | 512 | async fn transfer(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(), Error> { |
| 507 | type TransferFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 513 | self.transfer(rx, tx).await |
| 508 | 514 | } | |
| 509 | fn transfer<'a>(&'a mut self, rx: &'a mut [u8], tx: &'a [u8]) -> Self::TransferFuture<'a> { | ||
| 510 | self.transfer(rx, tx) | ||
| 511 | } | ||
| 512 | |||
| 513 | type TransferInPlaceFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 514 | 515 | ||
| 515 | fn transfer_in_place<'a>( | 516 | async fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Error> { |
| 516 | &'a mut self, | 517 | self.transfer_in_place(words).await |
| 517 | words: &'a mut [u8], | ||
| 518 | ) -> Self::TransferInPlaceFuture<'a> { | ||
| 519 | self.transfer_in_place(words) | ||
| 520 | } | ||
| 521 | } | 518 | } |
| 522 | } | 519 | } |
| 523 | } | 520 | } |
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs new file mode 100644 index 000000000..aa438415a --- /dev/null +++ b/embassy-nrf/src/spis.rs | |||
| @@ -0,0 +1,550 @@ | |||
| 1 | //! Serial Peripheral Instance in slave mode (SPIS) driver. | ||
| 2 | |||
| 3 | #![macro_use] | ||
| 4 | use core::future::poll_fn; | ||
| 5 | use core::marker::PhantomData; | ||
| 6 | use core::sync::atomic::{compiler_fence, Ordering}; | ||
| 7 | use core::task::Poll; | ||
| 8 | |||
| 9 | use embassy_embedded_hal::SetConfig; | ||
| 10 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 11 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | ||
| 12 | |||
| 13 | use crate::chip::FORCE_COPY_BUFFER_SIZE; | ||
| 14 | use crate::gpio::sealed::Pin as _; | ||
| 15 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | ||
| 16 | use crate::interrupt::typelevel::Interrupt; | ||
| 17 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | ||
| 18 | use crate::{interrupt, pac, Peripheral}; | ||
| 19 | |||
| 20 | /// SPIS error | ||
| 21 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 23 | #[non_exhaustive] | ||
| 24 | pub enum Error { | ||
| 25 | /// TX buffer was too long. | ||
| 26 | TxBufferTooLong, | ||
| 27 | /// RX buffer was too long. | ||
| 28 | RxBufferTooLong, | ||
| 29 | /// EasyDMA can only read from data memory, read only buffers in flash will fail. | ||
| 30 | BufferNotInRAM, | ||
| 31 | } | ||
| 32 | |||
| 33 | /// SPIS configuration. | ||
| 34 | #[non_exhaustive] | ||
| 35 | pub struct Config { | ||
| 36 | /// SPI mode | ||
| 37 | pub mode: Mode, | ||
| 38 | |||
| 39 | /// Overread character. | ||
| 40 | /// | ||
| 41 | /// If the master keeps clocking the bus after all the bytes in the TX buffer have | ||
| 42 | /// already been transmitted, this byte will be constantly transmitted in the MISO line. | ||
| 43 | pub orc: u8, | ||
| 44 | |||
| 45 | /// Default byte. | ||
| 46 | /// | ||
| 47 | /// This is the byte clocked out in the MISO line for ignored transactions (if the master | ||
| 48 | /// sets CSN low while the semaphore is owned by the firmware) | ||
| 49 | pub def: u8, | ||
| 50 | |||
| 51 | /// Automatically make the firmware side acquire the semaphore on transfer end. | ||
| 52 | pub auto_acquire: bool, | ||
| 53 | } | ||
| 54 | |||
| 55 | impl Default for Config { | ||
| 56 | fn default() -> Self { | ||
| 57 | Self { | ||
| 58 | mode: MODE_0, | ||
| 59 | orc: 0x00, | ||
| 60 | def: 0x00, | ||
| 61 | auto_acquire: true, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | /// Interrupt handler. | ||
| 67 | pub struct InterruptHandler<T: Instance> { | ||
| 68 | _phantom: PhantomData<T>, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 72 | unsafe fn on_interrupt() { | ||
| 73 | let r = T::regs(); | ||
| 74 | let s = T::state(); | ||
| 75 | |||
| 76 | if r.events_end.read().bits() != 0 { | ||
| 77 | s.waker.wake(); | ||
| 78 | r.intenclr.write(|w| w.end().clear()); | ||
| 79 | } | ||
| 80 | |||
| 81 | if r.events_acquired.read().bits() != 0 { | ||
| 82 | s.waker.wake(); | ||
| 83 | r.intenclr.write(|w| w.acquired().clear()); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | /// SPIS driver. | ||
| 89 | pub struct Spis<'d, T: Instance> { | ||
| 90 | _p: PeripheralRef<'d, T>, | ||
| 91 | } | ||
| 92 | |||
| 93 | impl<'d, T: Instance> Spis<'d, T> { | ||
| 94 | /// Create a new SPIS driver. | ||
| 95 | pub fn new( | ||
| 96 | spis: impl Peripheral<P = T> + 'd, | ||
| 97 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 98 | cs: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 99 | sck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 100 | miso: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 101 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 102 | config: Config, | ||
| 103 | ) -> Self { | ||
| 104 | into_ref!(cs, sck, miso, mosi); | ||
| 105 | Self::new_inner( | ||
| 106 | spis, | ||
| 107 | cs.map_into(), | ||
| 108 | sck.map_into(), | ||
| 109 | Some(miso.map_into()), | ||
| 110 | Some(mosi.map_into()), | ||
| 111 | config, | ||
| 112 | ) | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Create a new SPIS driver, capable of TX only (MISO only). | ||
| 116 | pub fn new_txonly( | ||
| 117 | spis: impl Peripheral<P = T> + 'd, | ||
| 118 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 119 | cs: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 120 | sck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 121 | miso: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 122 | config: Config, | ||
| 123 | ) -> Self { | ||
| 124 | into_ref!(cs, sck, miso); | ||
| 125 | Self::new_inner(spis, cs.map_into(), sck.map_into(), Some(miso.map_into()), None, config) | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Create a new SPIS driver, capable of RX only (MOSI only). | ||
| 129 | pub fn new_rxonly( | ||
| 130 | spis: impl Peripheral<P = T> + 'd, | ||
| 131 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 132 | cs: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 133 | sck: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 134 | mosi: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 135 | config: Config, | ||
| 136 | ) -> Self { | ||
| 137 | into_ref!(cs, sck, mosi); | ||
| 138 | Self::new_inner(spis, cs.map_into(), sck.map_into(), None, Some(mosi.map_into()), config) | ||
| 139 | } | ||
| 140 | |||
| 141 | fn new_inner( | ||
| 142 | spis: impl Peripheral<P = T> + 'd, | ||
| 143 | cs: PeripheralRef<'d, AnyPin>, | ||
| 144 | sck: PeripheralRef<'d, AnyPin>, | ||
| 145 | miso: Option<PeripheralRef<'d, AnyPin>>, | ||
| 146 | mosi: Option<PeripheralRef<'d, AnyPin>>, | ||
| 147 | config: Config, | ||
| 148 | ) -> Self { | ||
| 149 | compiler_fence(Ordering::SeqCst); | ||
| 150 | |||
| 151 | into_ref!(spis, cs, sck); | ||
| 152 | |||
| 153 | let r = T::regs(); | ||
| 154 | |||
| 155 | // Configure pins. | ||
| 156 | sck.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 157 | r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); | ||
| 158 | cs.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 159 | r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) }); | ||
| 160 | if let Some(mosi) = &mosi { | ||
| 161 | mosi.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 162 | r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); | ||
| 163 | } | ||
| 164 | if let Some(miso) = &miso { | ||
| 165 | miso.conf().write(|w| w.dir().output().drive().h0h1()); | ||
| 166 | r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); | ||
| 167 | } | ||
| 168 | |||
| 169 | // Enable SPIS instance. | ||
| 170 | r.enable.write(|w| w.enable().enabled()); | ||
| 171 | |||
| 172 | // Configure mode. | ||
| 173 | let mode = config.mode; | ||
| 174 | r.config.write(|w| { | ||
| 175 | match mode { | ||
| 176 | MODE_0 => { | ||
| 177 | w.order().msb_first(); | ||
| 178 | w.cpol().active_high(); | ||
| 179 | w.cpha().leading(); | ||
| 180 | } | ||
| 181 | MODE_1 => { | ||
| 182 | w.order().msb_first(); | ||
| 183 | w.cpol().active_high(); | ||
| 184 | w.cpha().trailing(); | ||
| 185 | } | ||
| 186 | MODE_2 => { | ||
| 187 | w.order().msb_first(); | ||
| 188 | w.cpol().active_low(); | ||
| 189 | w.cpha().leading(); | ||
| 190 | } | ||
| 191 | MODE_3 => { | ||
| 192 | w.order().msb_first(); | ||
| 193 | w.cpol().active_low(); | ||
| 194 | w.cpha().trailing(); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | w | ||
| 199 | }); | ||
| 200 | |||
| 201 | // Set over-read character. | ||
| 202 | let orc = config.orc; | ||
| 203 | r.orc.write(|w| unsafe { w.orc().bits(orc) }); | ||
| 204 | |||
| 205 | // Set default character. | ||
| 206 | let def = config.def; | ||
| 207 | r.def.write(|w| unsafe { w.def().bits(def) }); | ||
| 208 | |||
| 209 | // Configure auto-acquire on 'transfer end' event. | ||
| 210 | if config.auto_acquire { | ||
| 211 | r.shorts.write(|w| w.end_acquire().bit(true)); | ||
| 212 | } | ||
| 213 | |||
| 214 | // Disable all events interrupts. | ||
| 215 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||
| 216 | |||
| 217 | T::Interrupt::unpend(); | ||
| 218 | unsafe { T::Interrupt::enable() }; | ||
| 219 | |||
| 220 | Self { _p: spis } | ||
| 221 | } | ||
| 222 | |||
| 223 | fn prepare(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { | ||
| 224 | slice_in_ram_or(tx, Error::BufferNotInRAM)?; | ||
| 225 | // NOTE: RAM slice check for rx is not necessary, as a mutable | ||
| 226 | // slice can only be built from data located in RAM. | ||
| 227 | |||
| 228 | compiler_fence(Ordering::SeqCst); | ||
| 229 | |||
| 230 | let r = T::regs(); | ||
| 231 | |||
| 232 | // Set up the DMA write. | ||
| 233 | let (ptr, len) = slice_ptr_parts(tx); | ||
| 234 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); | ||
| 235 | r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 236 | |||
| 237 | // Set up the DMA read. | ||
| 238 | let (ptr, len) = slice_ptr_parts_mut(rx); | ||
| 239 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); | ||
| 240 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 241 | |||
| 242 | // Reset end event. | ||
| 243 | r.events_end.reset(); | ||
| 244 | |||
| 245 | // Release the semaphore. | ||
| 246 | r.tasks_release.write(|w| unsafe { w.bits(1) }); | ||
| 247 | |||
| 248 | Ok(()) | ||
| 249 | } | ||
| 250 | |||
| 251 | fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { | ||
| 252 | compiler_fence(Ordering::SeqCst); | ||
| 253 | let r = T::regs(); | ||
| 254 | |||
| 255 | // Acquire semaphore. | ||
| 256 | if r.semstat.read().bits() != 1 { | ||
| 257 | r.events_acquired.reset(); | ||
| 258 | r.tasks_acquire.write(|w| unsafe { w.bits(1) }); | ||
| 259 | // Wait until CPU has acquired the semaphore. | ||
| 260 | while r.semstat.read().bits() != 1 {} | ||
| 261 | } | ||
| 262 | |||
| 263 | self.prepare(rx, tx)?; | ||
| 264 | |||
| 265 | // Wait for 'end' event. | ||
| 266 | while r.events_end.read().bits() == 0 {} | ||
| 267 | |||
| 268 | let n_rx = r.rxd.amount.read().bits() as usize; | ||
| 269 | let n_tx = r.txd.amount.read().bits() as usize; | ||
| 270 | |||
| 271 | compiler_fence(Ordering::SeqCst); | ||
| 272 | |||
| 273 | Ok((n_rx, n_tx)) | ||
| 274 | } | ||
| 275 | |||
| 276 | fn blocking_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> { | ||
| 277 | match self.blocking_inner_from_ram(rx, tx) { | ||
| 278 | Ok(n) => Ok(n), | ||
| 279 | Err(Error::BufferNotInRAM) => { | ||
| 280 | trace!("Copying SPIS tx buffer into RAM for DMA"); | ||
| 281 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; | ||
| 282 | tx_ram_buf.copy_from_slice(tx); | ||
| 283 | self.blocking_inner_from_ram(rx, tx_ram_buf) | ||
| 284 | } | ||
| 285 | Err(error) => Err(error), | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { | ||
| 290 | let r = T::regs(); | ||
| 291 | let s = T::state(); | ||
| 292 | |||
| 293 | // Clear status register. | ||
| 294 | r.status.write(|w| w.overflow().clear().overread().clear()); | ||
| 295 | |||
| 296 | // Acquire semaphore. | ||
| 297 | if r.semstat.read().bits() != 1 { | ||
| 298 | // Reset and enable the acquire event. | ||
| 299 | r.events_acquired.reset(); | ||
| 300 | r.intenset.write(|w| w.acquired().set()); | ||
| 301 | |||
| 302 | // Request acquiring the SPIS semaphore. | ||
| 303 | r.tasks_acquire.write(|w| unsafe { w.bits(1) }); | ||
| 304 | |||
| 305 | // Wait until CPU has acquired the semaphore. | ||
| 306 | poll_fn(|cx| { | ||
| 307 | s.waker.register(cx.waker()); | ||
| 308 | if r.events_acquired.read().bits() == 1 { | ||
| 309 | r.events_acquired.reset(); | ||
| 310 | return Poll::Ready(()); | ||
| 311 | } | ||
| 312 | Poll::Pending | ||
| 313 | }) | ||
| 314 | .await; | ||
| 315 | } | ||
| 316 | |||
| 317 | self.prepare(rx, tx)?; | ||
| 318 | |||
| 319 | // Wait for 'end' event. | ||
| 320 | r.intenset.write(|w| w.end().set()); | ||
| 321 | poll_fn(|cx| { | ||
| 322 | s.waker.register(cx.waker()); | ||
| 323 | if r.events_end.read().bits() != 0 { | ||
| 324 | r.events_end.reset(); | ||
| 325 | return Poll::Ready(()); | ||
| 326 | } | ||
| 327 | Poll::Pending | ||
| 328 | }) | ||
| 329 | .await; | ||
| 330 | |||
| 331 | let n_rx = r.rxd.amount.read().bits() as usize; | ||
| 332 | let n_tx = r.txd.amount.read().bits() as usize; | ||
| 333 | |||
| 334 | compiler_fence(Ordering::SeqCst); | ||
| 335 | |||
| 336 | Ok((n_rx, n_tx)) | ||
| 337 | } | ||
| 338 | |||
| 339 | async fn async_inner(&mut self, rx: &mut [u8], tx: &[u8]) -> Result<(usize, usize), Error> { | ||
| 340 | match self.async_inner_from_ram(rx, tx).await { | ||
| 341 | Ok(n) => Ok(n), | ||
| 342 | Err(Error::BufferNotInRAM) => { | ||
| 343 | trace!("Copying SPIS tx buffer into RAM for DMA"); | ||
| 344 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..tx.len()]; | ||
| 345 | tx_ram_buf.copy_from_slice(tx); | ||
| 346 | self.async_inner_from_ram(rx, tx_ram_buf).await | ||
| 347 | } | ||
| 348 | Err(error) => Err(error), | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Reads data from the SPI bus without sending anything. Blocks until `cs` is deasserted. | ||
| 353 | /// Returns number of bytes read. | ||
| 354 | pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<usize, Error> { | ||
| 355 | self.blocking_inner(data, &[]).map(|n| n.0) | ||
| 356 | } | ||
| 357 | |||
| 358 | /// Simultaneously sends and receives data. Blocks until the transmission is completed. | ||
| 359 | /// If necessary, the write buffer will be copied into RAM (see struct description for detail). | ||
| 360 | /// Returns number of bytes transferred `(n_rx, n_tx)`. | ||
| 361 | pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> { | ||
| 362 | self.blocking_inner(read, write) | ||
| 363 | } | ||
| 364 | |||
| 365 | /// Same as [`blocking_transfer`](Spis::blocking_transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 366 | /// Returns number of bytes transferred `(n_rx, n_tx)`. | ||
| 367 | pub fn blocking_transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> { | ||
| 368 | self.blocking_inner_from_ram(read, write) | ||
| 369 | } | ||
| 370 | |||
| 371 | /// Simultaneously sends and receives data. | ||
| 372 | /// Places the received data into the same buffer and blocks until the transmission is completed. | ||
| 373 | /// Returns number of bytes transferred. | ||
| 374 | pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> { | ||
| 375 | self.blocking_inner_from_ram(data, data).map(|n| n.0) | ||
| 376 | } | ||
| 377 | |||
| 378 | /// Sends data, discarding any received data. Blocks until the transmission is completed. | ||
| 379 | /// If necessary, the write buffer will be copied into RAM (see struct description for detail). | ||
| 380 | /// Returns number of bytes written. | ||
| 381 | pub fn blocking_write(&mut self, data: &[u8]) -> Result<usize, Error> { | ||
| 382 | self.blocking_inner(&mut [], data).map(|n| n.1) | ||
| 383 | } | ||
| 384 | |||
| 385 | /// Same as [`blocking_write`](Spis::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 386 | /// Returns number of bytes written. | ||
| 387 | pub fn blocking_write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> { | ||
| 388 | self.blocking_inner_from_ram(&mut [], data).map(|n| n.1) | ||
| 389 | } | ||
| 390 | |||
| 391 | /// Reads data from the SPI bus without sending anything. | ||
| 392 | /// Returns number of bytes read. | ||
| 393 | pub async fn read(&mut self, data: &mut [u8]) -> Result<usize, Error> { | ||
| 394 | self.async_inner(data, &[]).await.map(|n| n.0) | ||
| 395 | } | ||
| 396 | |||
| 397 | /// Simultaneously sends and receives data. | ||
| 398 | /// If necessary, the write buffer will be copied into RAM (see struct description for detail). | ||
| 399 | /// Returns number of bytes transferred `(n_rx, n_tx)`. | ||
| 400 | pub async fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> { | ||
| 401 | self.async_inner(read, write).await | ||
| 402 | } | ||
| 403 | |||
| 404 | /// Same as [`transfer`](Spis::transfer) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 405 | /// Returns number of bytes transferred `(n_rx, n_tx)`. | ||
| 406 | pub async fn transfer_from_ram(&mut self, read: &mut [u8], write: &[u8]) -> Result<(usize, usize), Error> { | ||
| 407 | self.async_inner_from_ram(read, write).await | ||
| 408 | } | ||
| 409 | |||
| 410 | /// Simultaneously sends and receives data. Places the received data into the same buffer. | ||
| 411 | /// Returns number of bytes transferred. | ||
| 412 | pub async fn transfer_in_place(&mut self, data: &mut [u8]) -> Result<usize, Error> { | ||
| 413 | self.async_inner_from_ram(data, data).await.map(|n| n.0) | ||
| 414 | } | ||
| 415 | |||
| 416 | /// Sends data, discarding any received data. | ||
| 417 | /// If necessary, the write buffer will be copied into RAM (see struct description for detail). | ||
| 418 | /// Returns number of bytes written. | ||
| 419 | pub async fn write(&mut self, data: &[u8]) -> Result<usize, Error> { | ||
| 420 | self.async_inner(&mut [], data).await.map(|n| n.1) | ||
| 421 | } | ||
| 422 | |||
| 423 | /// Same as [`write`](Spis::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 424 | /// Returns number of bytes written. | ||
| 425 | pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<usize, Error> { | ||
| 426 | self.async_inner_from_ram(&mut [], data).await.map(|n| n.1) | ||
| 427 | } | ||
| 428 | |||
| 429 | /// Checks if last transaction overread. | ||
| 430 | pub fn is_overread(&mut self) -> bool { | ||
| 431 | T::regs().status.read().overread().is_present() | ||
| 432 | } | ||
| 433 | |||
| 434 | /// Checks if last transaction overflowed. | ||
| 435 | pub fn is_overflow(&mut self) -> bool { | ||
| 436 | T::regs().status.read().overflow().is_present() | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | impl<'d, T: Instance> Drop for Spis<'d, T> { | ||
| 441 | fn drop(&mut self) { | ||
| 442 | trace!("spis drop"); | ||
| 443 | |||
| 444 | // Disable | ||
| 445 | let r = T::regs(); | ||
| 446 | r.enable.write(|w| w.enable().disabled()); | ||
| 447 | |||
| 448 | gpio::deconfigure_pin(r.psel.sck.read().bits()); | ||
| 449 | gpio::deconfigure_pin(r.psel.csn.read().bits()); | ||
| 450 | gpio::deconfigure_pin(r.psel.miso.read().bits()); | ||
| 451 | gpio::deconfigure_pin(r.psel.mosi.read().bits()); | ||
| 452 | |||
| 453 | trace!("spis drop: done"); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | pub(crate) mod sealed { | ||
| 458 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 459 | |||
| 460 | use super::*; | ||
| 461 | |||
| 462 | pub struct State { | ||
| 463 | pub waker: AtomicWaker, | ||
| 464 | } | ||
| 465 | |||
| 466 | impl State { | ||
| 467 | pub const fn new() -> Self { | ||
| 468 | Self { | ||
| 469 | waker: AtomicWaker::new(), | ||
| 470 | } | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | pub trait Instance { | ||
| 475 | fn regs() -> &'static pac::spis0::RegisterBlock; | ||
| 476 | fn state() -> &'static State; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | /// SPIS peripheral instance | ||
| 481 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||
| 482 | /// Interrupt for this peripheral. | ||
| 483 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 484 | } | ||
| 485 | |||
| 486 | macro_rules! impl_spis { | ||
| 487 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 488 | impl crate::spis::sealed::Instance for peripherals::$type { | ||
| 489 | fn regs() -> &'static pac::spis0::RegisterBlock { | ||
| 490 | unsafe { &*pac::$pac_type::ptr() } | ||
| 491 | } | ||
| 492 | fn state() -> &'static crate::spis::sealed::State { | ||
| 493 | static STATE: crate::spis::sealed::State = crate::spis::sealed::State::new(); | ||
| 494 | &STATE | ||
| 495 | } | ||
| 496 | } | ||
| 497 | impl crate::spis::Instance for peripherals::$type { | ||
| 498 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 499 | } | ||
| 500 | }; | ||
| 501 | } | ||
| 502 | |||
| 503 | // ==================== | ||
| 504 | |||
| 505 | impl<'d, T: Instance> SetConfig for Spis<'d, T> { | ||
| 506 | type Config = Config; | ||
| 507 | fn set_config(&mut self, config: &Self::Config) { | ||
| 508 | let r = T::regs(); | ||
| 509 | // Configure mode. | ||
| 510 | let mode = config.mode; | ||
| 511 | r.config.write(|w| { | ||
| 512 | match mode { | ||
| 513 | MODE_0 => { | ||
| 514 | w.order().msb_first(); | ||
| 515 | w.cpol().active_high(); | ||
| 516 | w.cpha().leading(); | ||
| 517 | } | ||
| 518 | MODE_1 => { | ||
| 519 | w.order().msb_first(); | ||
| 520 | w.cpol().active_high(); | ||
| 521 | w.cpha().trailing(); | ||
| 522 | } | ||
| 523 | MODE_2 => { | ||
| 524 | w.order().msb_first(); | ||
| 525 | w.cpol().active_low(); | ||
| 526 | w.cpha().leading(); | ||
| 527 | } | ||
| 528 | MODE_3 => { | ||
| 529 | w.order().msb_first(); | ||
| 530 | w.cpol().active_low(); | ||
| 531 | w.cpha().trailing(); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | w | ||
| 536 | }); | ||
| 537 | |||
| 538 | // Set over-read character. | ||
| 539 | let orc = config.orc; | ||
| 540 | r.orc.write(|w| unsafe { w.orc().bits(orc) }); | ||
| 541 | |||
| 542 | // Set default character. | ||
| 543 | let def = config.def; | ||
| 544 | r.def.write(|w| unsafe { w.def().bits(def) }); | ||
| 545 | |||
| 546 | // Configure auto-acquire on 'transfer end' event. | ||
| 547 | let auto_acquire = config.auto_acquire; | ||
| 548 | r.shorts.write(|w| w.end_acquire().bit(auto_acquire)); | ||
| 549 | } | ||
| 550 | } | ||
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index d520fd686..491e92c04 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs | |||
| @@ -1,37 +1,50 @@ | |||
| 1 | //! Temperature sensor interface. | 1 | //! Builtin temperature sensor driver. |
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | ||
| 3 | use core::task::Poll; | 4 | use core::task::Poll; |
| 4 | 5 | ||
| 5 | use embassy_hal_common::drop::OnDrop; | 6 | use embassy_hal_common::drop::OnDrop; |
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 7 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use fixed::types::I30F2; | 9 | use fixed::types::I30F2; |
| 9 | use futures::future::poll_fn; | ||
| 10 | 10 | ||
| 11 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 12 | use crate::peripherals::TEMP; | 12 | use crate::peripherals::TEMP; |
| 13 | use crate::{interrupt, pac, Peripheral}; | 13 | use crate::{interrupt, pac, Peripheral}; |
| 14 | 14 | ||
| 15 | /// Integrated temperature sensor. | 15 | /// Interrupt handler. |
| 16 | pub struct InterruptHandler { | ||
| 17 | _private: (), | ||
| 18 | } | ||
| 19 | |||
| 20 | impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler { | ||
| 21 | unsafe fn on_interrupt() { | ||
| 22 | let r = unsafe { &*pac::TEMP::PTR }; | ||
| 23 | r.intenclr.write(|w| w.datardy().clear()); | ||
| 24 | WAKER.wake(); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | /// Builtin temperature sensor driver. | ||
| 16 | pub struct Temp<'d> { | 29 | pub struct Temp<'d> { |
| 17 | _irq: PeripheralRef<'d, interrupt::TEMP>, | 30 | _peri: PeripheralRef<'d, TEMP>, |
| 18 | } | 31 | } |
| 19 | 32 | ||
| 20 | static WAKER: AtomicWaker = AtomicWaker::new(); | 33 | static WAKER: AtomicWaker = AtomicWaker::new(); |
| 21 | 34 | ||
| 22 | impl<'d> Temp<'d> { | 35 | impl<'d> Temp<'d> { |
| 23 | pub fn new(_t: impl Peripheral<P = TEMP> + 'd, irq: impl Peripheral<P = interrupt::TEMP> + 'd) -> Self { | 36 | /// Create a new temperature sensor driver. |
| 24 | into_ref!(_t, irq); | 37 | pub fn new( |
| 38 | _peri: impl Peripheral<P = TEMP> + 'd, | ||
| 39 | _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd, | ||
| 40 | ) -> Self { | ||
| 41 | into_ref!(_peri); | ||
| 25 | 42 | ||
| 26 | // Enable interrupt that signals temperature values | 43 | // Enable interrupt that signals temperature values |
| 27 | irq.disable(); | 44 | interrupt::TEMP.unpend(); |
| 28 | irq.set_handler(|_| { | 45 | unsafe { interrupt::TEMP.enable() }; |
| 29 | let t = Self::regs(); | 46 | |
| 30 | t.intenclr.write(|w| w.datardy().clear()); | 47 | Self { _peri } |
| 31 | WAKER.wake(); | ||
| 32 | }); | ||
| 33 | irq.enable(); | ||
| 34 | Self { _irq: irq } | ||
| 35 | } | 48 | } |
| 36 | 49 | ||
| 37 | /// Perform an asynchronous temperature measurement. The returned future | 50 | /// Perform an asynchronous temperature measurement. The returned future |
| @@ -42,8 +55,19 @@ impl<'d> Temp<'d> { | |||
| 42 | /// # Example | 55 | /// # Example |
| 43 | /// | 56 | /// |
| 44 | /// ```no_run | 57 | /// ```no_run |
| 45 | /// let mut t = Temp::new(p.TEMP, interrupt::take!(TEMP)); | 58 | /// use embassy_nrf::{bind_interrupts, temp}; |
| 59 | /// use embassy_nrf::temp::Temp; | ||
| 60 | /// use embassy_time::{Duration, Timer}; | ||
| 61 | /// | ||
| 62 | /// bind_interrupts!(struct Irqs { | ||
| 63 | /// TEMP => temp::InterruptHandler; | ||
| 64 | /// }); | ||
| 65 | /// | ||
| 66 | /// # async { | ||
| 67 | /// # let p: embassy_nrf::Peripherals = todo!(); | ||
| 68 | /// let mut t = Temp::new(p.TEMP, Irqs); | ||
| 46 | /// let v: u16 = t.read().await.to_num::<u16>(); | 69 | /// let v: u16 = t.read().await.to_num::<u16>(); |
| 70 | /// # }; | ||
| 47 | /// ``` | 71 | /// ``` |
| 48 | pub async fn read(&mut self) -> I30F2 { | 72 | pub async fn read(&mut self) -> I30F2 { |
| 49 | // In case the future is dropped, stop the task and reset events. | 73 | // In case the future is dropped, stop the task and reset events. |
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index c32a44637..f1ab4f8fd 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs | |||
| @@ -7,7 +7,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | |||
| 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; | 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; |
| 8 | use embassy_time::driver::{AlarmHandle, Driver}; | 8 | use embassy_time::driver::{AlarmHandle, Driver}; |
| 9 | 9 | ||
| 10 | use crate::interrupt::{Interrupt, InterruptExt}; | 10 | use crate::interrupt::InterruptExt; |
| 11 | use crate::{interrupt, pac}; | 11 | use crate::{interrupt, pac}; |
| 12 | 12 | ||
| 13 | fn rtc() -> &'static pac::rtc0::RegisterBlock { | 13 | fn rtc() -> &'static pac::rtc0::RegisterBlock { |
| @@ -67,7 +67,7 @@ fn compare_n(n: usize) -> u32 { | |||
| 67 | 1 << (n + 16) | 67 | 1 << (n + 16) |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | #[cfg(tests)] | 70 | #[cfg(test)] |
| 71 | mod test { | 71 | mod test { |
| 72 | use super::*; | 72 | use super::*; |
| 73 | 73 | ||
| @@ -142,9 +142,8 @@ impl RtcDriver { | |||
| 142 | // Wait for clear | 142 | // Wait for clear |
| 143 | while r.counter.read().bits() != 0 {} | 143 | while r.counter.read().bits() != 0 {} |
| 144 | 144 | ||
| 145 | let irq = unsafe { interrupt::RTC1::steal() }; | 145 | interrupt::RTC1.set_priority(irq_prio); |
| 146 | irq.set_priority(irq_prio); | 146 | unsafe { interrupt::RTC1.enable() }; |
| 147 | irq.enable(); | ||
| 148 | } | 147 | } |
| 149 | 148 | ||
| 150 | fn on_interrupt(&self) { | 149 | fn on_interrupt(&self) { |
| @@ -243,21 +242,24 @@ impl Driver for RtcDriver { | |||
| 243 | }) | 242 | }) |
| 244 | } | 243 | } |
| 245 | 244 | ||
| 246 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) { | 245 | fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { |
| 247 | critical_section::with(|cs| { | 246 | critical_section::with(|cs| { |
| 248 | let n = alarm.id() as _; | 247 | let n = alarm.id() as _; |
| 249 | let alarm = self.get_alarm(cs, alarm); | 248 | let alarm = self.get_alarm(cs, alarm); |
| 250 | alarm.timestamp.set(timestamp); | 249 | alarm.timestamp.set(timestamp); |
| 251 | 250 | ||
| 252 | let t = self.now(); | 251 | let r = rtc(); |
| 253 | 252 | ||
| 254 | // If alarm timestamp has passed, trigger it instantly. | 253 | let t = self.now(); |
| 255 | if timestamp <= t { | 254 | if timestamp <= t { |
| 256 | self.trigger_alarm(n, cs); | 255 | // If alarm timestamp has passed the alarm will not fire. |
| 257 | return; | 256 | // Disarm the alarm and return `false` to indicate that. |
| 258 | } | 257 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); |
| 259 | 258 | ||
| 260 | let r = rtc(); | 259 | alarm.timestamp.set(u64::MAX); |
| 260 | |||
| 261 | return false; | ||
| 262 | } | ||
| 261 | 263 | ||
| 262 | // If it hasn't triggered yet, setup it in the compare channel. | 264 | // If it hasn't triggered yet, setup it in the compare channel. |
| 263 | 265 | ||
| @@ -287,10 +289,13 @@ impl Driver for RtcDriver { | |||
| 287 | // It will be setup later by `next_period`. | 289 | // It will be setup later by `next_period`. |
| 288 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); | 290 | r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); |
| 289 | } | 291 | } |
| 292 | |||
| 293 | true | ||
| 290 | }) | 294 | }) |
| 291 | } | 295 | } |
| 292 | } | 296 | } |
| 293 | 297 | ||
| 298 | #[cfg(feature = "rt")] | ||
| 294 | #[interrupt] | 299 | #[interrupt] |
| 295 | fn RTC1() { | 300 | fn RTC1() { |
| 296 | DRIVER.on_interrupt() | 301 | DRIVER.on_interrupt() |
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index 3de5a8962..04748238d 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs | |||
| @@ -1,14 +1,13 @@ | |||
| 1 | #![macro_use] | 1 | //! Timer driver. |
| 2 | //! | ||
| 3 | //! Important note! This driver is very low level. For most time-related use cases, like | ||
| 4 | //! "sleep for X seconds", "do something every X seconds", or measuring time, you should | ||
| 5 | //! use [`embassy-time`](https://crates.io/crates/embassy-time) instead! | ||
| 2 | 6 | ||
| 3 | use core::marker::PhantomData; | 7 | #![macro_use] |
| 4 | use core::task::Poll; | ||
| 5 | 8 | ||
| 6 | use embassy_hal_common::drop::OnDrop; | ||
| 7 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | use futures::future::poll_fn; | ||
| 10 | 10 | ||
| 11 | use crate::interrupt::{Interrupt, InterruptExt}; | ||
| 12 | use crate::ppi::{Event, Task}; | 11 | use crate::ppi::{Event, Task}; |
| 13 | use crate::{pac, Peripheral}; | 12 | use crate::{pac, Peripheral}; |
| 14 | 13 | ||
| @@ -20,17 +19,19 @@ pub(crate) mod sealed { | |||
| 20 | /// The number of CC registers this instance has. | 19 | /// The number of CC registers this instance has. |
| 21 | const CCS: usize; | 20 | const CCS: usize; |
| 22 | fn regs() -> &'static pac::timer0::RegisterBlock; | 21 | fn regs() -> &'static pac::timer0::RegisterBlock; |
| 23 | /// Storage for the waker for CC register `n`. | ||
| 24 | fn waker(n: usize) -> &'static AtomicWaker; | ||
| 25 | } | 22 | } |
| 26 | pub trait ExtendedInstance {} | 23 | pub trait ExtendedInstance {} |
| 27 | 24 | ||
| 28 | pub trait TimerType {} | 25 | pub trait TimerType {} |
| 29 | } | 26 | } |
| 30 | 27 | ||
| 28 | /// Basic Timer instance. | ||
| 31 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 29 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 32 | type Interrupt: Interrupt; | 30 | /// Interrupt for this peripheral. |
| 31 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 33 | } | 32 | } |
| 33 | |||
| 34 | /// Extended timer instance. | ||
| 34 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} | 35 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} |
| 35 | 36 | ||
| 36 | macro_rules! impl_timer { | 37 | macro_rules! impl_timer { |
| @@ -40,15 +41,9 @@ macro_rules! impl_timer { | |||
| 40 | fn regs() -> &'static pac::timer0::RegisterBlock { | 41 | fn regs() -> &'static pac::timer0::RegisterBlock { |
| 41 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } | 42 | unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } |
| 42 | } | 43 | } |
| 43 | fn waker(n: usize) -> &'static ::embassy_sync::waitqueue::AtomicWaker { | ||
| 44 | use ::embassy_sync::waitqueue::AtomicWaker; | ||
| 45 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | ||
| 46 | static WAKERS: [AtomicWaker; $ccs] = [NEW_AW; $ccs]; | ||
| 47 | &WAKERS[n] | ||
| 48 | } | ||
| 49 | } | 44 | } |
| 50 | impl crate::timer::Instance for peripherals::$type { | 45 | impl crate::timer::Instance for peripherals::$type { |
| 51 | type Interrupt = crate::interrupt::$irq; | 46 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 52 | } | 47 | } |
| 53 | }; | 48 | }; |
| 54 | ($type:ident, $pac_type:ident, $irq:ident) => { | 49 | ($type:ident, $pac_type:ident, $irq:ident) => { |
| @@ -61,85 +56,77 @@ macro_rules! impl_timer { | |||
| 61 | }; | 56 | }; |
| 62 | } | 57 | } |
| 63 | 58 | ||
| 59 | /// Timer frequency | ||
| 64 | #[repr(u8)] | 60 | #[repr(u8)] |
| 65 | pub enum Frequency { | 61 | pub enum Frequency { |
| 66 | // I'd prefer not to prefix these with `F`, but Rust identifiers can't start with digits. | 62 | /// 16MHz |
| 67 | F16MHz = 0, | 63 | F16MHz = 0, |
| 64 | /// 8MHz | ||
| 68 | F8MHz = 1, | 65 | F8MHz = 1, |
| 66 | /// 4MHz | ||
| 69 | F4MHz = 2, | 67 | F4MHz = 2, |
| 68 | /// 2MHz | ||
| 70 | F2MHz = 3, | 69 | F2MHz = 3, |
| 70 | /// 1MHz | ||
| 71 | F1MHz = 4, | 71 | F1MHz = 4, |
| 72 | /// 500kHz | ||
| 72 | F500kHz = 5, | 73 | F500kHz = 5, |
| 74 | /// 250kHz | ||
| 73 | F250kHz = 6, | 75 | F250kHz = 6, |
| 76 | /// 125kHz | ||
| 74 | F125kHz = 7, | 77 | F125kHz = 7, |
| 78 | /// 62500Hz | ||
| 75 | F62500Hz = 8, | 79 | F62500Hz = 8, |
| 80 | /// 31250Hz | ||
| 76 | F31250Hz = 9, | 81 | F31250Hz = 9, |
| 77 | } | 82 | } |
| 78 | 83 | ||
| 79 | /// nRF Timer driver. | 84 | /// nRF Timer driver. |
| 80 | /// | 85 | /// |
| 81 | /// The timer has an internal counter, which is incremented for every tick of the timer. | 86 | /// The timer has an internal counter, which is incremented for every tick of the timer. |
| 82 | /// The counter is 32-bit, so it wraps back to 0 at 4294967296. | 87 | /// The counter is 32-bit, so it wraps back to 0 when it reaches 2^32. |
| 83 | /// | 88 | /// |
| 84 | /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter | 89 | /// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter |
| 85 | /// or trigger an event when the counter reaches a certain value. | 90 | /// or trigger an event when the counter reaches a certain value. |
| 86 | 91 | ||
| 87 | pub trait TimerType: sealed::TimerType {} | 92 | /// Timer driver. |
| 88 | 93 | pub struct Timer<'d, T: Instance> { | |
| 89 | pub enum Awaitable {} | ||
| 90 | pub enum NotAwaitable {} | ||
| 91 | |||
| 92 | impl sealed::TimerType for Awaitable {} | ||
| 93 | impl sealed::TimerType for NotAwaitable {} | ||
| 94 | impl TimerType for Awaitable {} | ||
| 95 | impl TimerType for NotAwaitable {} | ||
| 96 | |||
| 97 | pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> { | ||
| 98 | _p: PeripheralRef<'d, T>, | 94 | _p: PeripheralRef<'d, T>, |
| 99 | _i: PhantomData<I>, | ||
| 100 | } | 95 | } |
| 101 | 96 | ||
| 102 | impl<'d, T: Instance> Timer<'d, T, Awaitable> { | 97 | impl<'d, T: Instance> Timer<'d, T> { |
| 103 | pub fn new_awaitable(timer: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd) -> Self { | 98 | /// Create a new `Timer` driver. |
| 104 | into_ref!(irq); | ||
| 105 | |||
| 106 | irq.set_handler(Self::on_interrupt); | ||
| 107 | irq.unpend(); | ||
| 108 | irq.enable(); | ||
| 109 | |||
| 110 | Self::new_irqless(timer) | ||
| 111 | } | ||
| 112 | } | ||
| 113 | impl<'d, T: Instance> Timer<'d, T, NotAwaitable> { | ||
| 114 | /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. | ||
| 115 | /// | 99 | /// |
| 116 | /// This can be useful for triggering tasks via PPI | 100 | /// This can be useful for triggering tasks via PPI |
| 117 | /// `Uarte` uses this internally. | 101 | /// `Uarte` uses this internally. |
| 118 | pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self { | 102 | pub fn new(timer: impl Peripheral<P = T> + 'd) -> Self { |
| 119 | Self::new_irqless(timer) | 103 | Self::new_inner(timer, false) |
| 120 | } | 104 | } |
| 121 | } | ||
| 122 | 105 | ||
| 123 | impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | 106 | /// Create a new `Timer` driver in counter mode. |
| 124 | /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. | ||
| 125 | /// | 107 | /// |
| 126 | /// This is used by the public constructors. | 108 | /// This can be useful for triggering tasks via PPI |
| 127 | fn new_irqless(timer: impl Peripheral<P = T> + 'd) -> Self { | 109 | /// `Uarte` uses this internally. |
| 110 | pub fn new_counter(timer: impl Peripheral<P = T> + 'd) -> Self { | ||
| 111 | Self::new_inner(timer, true) | ||
| 112 | } | ||
| 113 | |||
| 114 | fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self { | ||
| 128 | into_ref!(timer); | 115 | into_ref!(timer); |
| 129 | 116 | ||
| 130 | let regs = T::regs(); | 117 | let regs = T::regs(); |
| 131 | 118 | ||
| 132 | let mut this = Self { | 119 | let this = Self { _p: timer }; |
| 133 | _p: timer, | ||
| 134 | _i: PhantomData, | ||
| 135 | }; | ||
| 136 | 120 | ||
| 137 | // Stop the timer before doing anything else, | 121 | // Stop the timer before doing anything else, |
| 138 | // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. | 122 | // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. |
| 139 | this.stop(); | 123 | this.stop(); |
| 140 | 124 | ||
| 141 | // Set the instance to timer mode. | 125 | if is_counter { |
| 142 | regs.mode.write(|w| w.mode().timer()); | 126 | regs.mode.write(|w| w.mode().low_power_counter()); |
| 127 | } else { | ||
| 128 | regs.mode.write(|w| w.mode().timer()); | ||
| 129 | } | ||
| 143 | 130 | ||
| 144 | // Make the counter's max value as high as possible. | 131 | // Make the counter's max value as high as possible. |
| 145 | // TODO: is there a reason someone would want to set this lower? | 132 | // TODO: is there a reason someone would want to set this lower? |
| @@ -181,24 +168,32 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | |||
| 181 | /// Returns the START task, for use with PPI. | 168 | /// Returns the START task, for use with PPI. |
| 182 | /// | 169 | /// |
| 183 | /// When triggered, this task starts the timer. | 170 | /// When triggered, this task starts the timer. |
| 184 | pub fn task_start(&self) -> Task { | 171 | pub fn task_start(&self) -> Task<'d> { |
| 185 | Task::from_reg(&T::regs().tasks_start) | 172 | Task::from_reg(&T::regs().tasks_start) |
| 186 | } | 173 | } |
| 187 | 174 | ||
| 188 | /// Returns the STOP task, for use with PPI. | 175 | /// Returns the STOP task, for use with PPI. |
| 189 | /// | 176 | /// |
| 190 | /// When triggered, this task stops the timer. | 177 | /// When triggered, this task stops the timer. |
| 191 | pub fn task_stop(&self) -> Task { | 178 | pub fn task_stop(&self) -> Task<'d> { |
| 192 | Task::from_reg(&T::regs().tasks_stop) | 179 | Task::from_reg(&T::regs().tasks_stop) |
| 193 | } | 180 | } |
| 194 | 181 | ||
| 195 | /// Returns the CLEAR task, for use with PPI. | 182 | /// Returns the CLEAR task, for use with PPI. |
| 196 | /// | 183 | /// |
| 197 | /// When triggered, this task resets the timer's counter to 0. | 184 | /// When triggered, this task resets the timer's counter to 0. |
| 198 | pub fn task_clear(&self) -> Task { | 185 | pub fn task_clear(&self) -> Task<'d> { |
| 199 | Task::from_reg(&T::regs().tasks_clear) | 186 | Task::from_reg(&T::regs().tasks_clear) |
| 200 | } | 187 | } |
| 201 | 188 | ||
| 189 | /// Returns the COUNT task, for use with PPI. | ||
| 190 | /// | ||
| 191 | /// When triggered, this task increments the timer's counter by 1. | ||
| 192 | /// Only works in counter mode. | ||
| 193 | pub fn task_count(&self) -> Task<'d> { | ||
| 194 | Task::from_reg(&T::regs().tasks_count) | ||
| 195 | } | ||
| 196 | |||
| 202 | /// Change the timer's frequency. | 197 | /// Change the timer's frequency. |
| 203 | /// | 198 | /// |
| 204 | /// This will stop the timer if it isn't already stopped, | 199 | /// This will stop the timer if it isn't already stopped, |
| @@ -213,31 +208,17 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | |||
| 213 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) | 208 | .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) |
| 214 | } | 209 | } |
| 215 | 210 | ||
| 216 | fn on_interrupt(_: *mut ()) { | ||
| 217 | let regs = T::regs(); | ||
| 218 | for n in 0..T::CCS { | ||
| 219 | if regs.events_compare[n].read().bits() != 0 { | ||
| 220 | // Clear the interrupt, otherwise the interrupt will be repeatedly raised as soon as the interrupt handler exits. | ||
| 221 | // We can't clear the event, because it's used to poll whether the future is done or still pending. | ||
| 222 | regs.intenclr | ||
| 223 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + n))) }); | ||
| 224 | T::waker(n).wake(); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | /// Returns this timer's `n`th CC register. | 211 | /// Returns this timer's `n`th CC register. |
| 230 | /// | 212 | /// |
| 231 | /// # Panics | 213 | /// # Panics |
| 232 | /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). | 214 | /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). |
| 233 | pub fn cc(&mut self, n: usize) -> Cc<T, I> { | 215 | pub fn cc(&self, n: usize) -> Cc<'d, T> { |
| 234 | if n >= T::CCS { | 216 | if n >= T::CCS { |
| 235 | panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); | 217 | panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); |
| 236 | } | 218 | } |
| 237 | Cc { | 219 | Cc { |
| 238 | n, | 220 | n, |
| 239 | _p: self._p.reborrow(), | 221 | _p: unsafe { self._p.clone_unchecked() }, |
| 240 | _i: PhantomData, | ||
| 241 | } | 222 | } |
| 242 | } | 223 | } |
| 243 | } | 224 | } |
| @@ -249,49 +230,12 @@ impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> { | |||
| 249 | /// | 230 | /// |
| 250 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. | 231 | /// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. |
| 251 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register | 232 | /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register |
| 252 | pub struct Cc<'d, T: Instance, I: TimerType = NotAwaitable> { | 233 | pub struct Cc<'d, T: Instance> { |
| 253 | n: usize, | 234 | n: usize, |
| 254 | _p: PeripheralRef<'d, T>, | 235 | _p: PeripheralRef<'d, T>, |
| 255 | _i: PhantomData<I>, | ||
| 256 | } | ||
| 257 | |||
| 258 | impl<'d, T: Instance> Cc<'d, T, Awaitable> { | ||
| 259 | /// Wait until the timer's counter reaches the value stored in this register. | ||
| 260 | /// | ||
| 261 | /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`. | ||
| 262 | pub async fn wait(&mut self) { | ||
| 263 | let regs = T::regs(); | ||
| 264 | |||
| 265 | // Enable the interrupt for this CC's COMPARE event. | ||
| 266 | regs.intenset | ||
| 267 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 268 | |||
| 269 | // Disable the interrupt if the future is dropped. | ||
| 270 | let on_drop = OnDrop::new(|| { | ||
| 271 | regs.intenclr | ||
| 272 | .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) }); | ||
| 273 | }); | ||
| 274 | |||
| 275 | poll_fn(|cx| { | ||
| 276 | T::waker(self.n).register(cx.waker()); | ||
| 277 | |||
| 278 | if regs.events_compare[self.n].read().bits() != 0 { | ||
| 279 | // Reset the register for next time | ||
| 280 | regs.events_compare[self.n].reset(); | ||
| 281 | Poll::Ready(()) | ||
| 282 | } else { | ||
| 283 | Poll::Pending | ||
| 284 | } | ||
| 285 | }) | ||
| 286 | .await; | ||
| 287 | |||
| 288 | // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again. | ||
| 289 | on_drop.defuse(); | ||
| 290 | } | ||
| 291 | } | 236 | } |
| 292 | impl<'d, T: Instance> Cc<'d, T, NotAwaitable> {} | ||
| 293 | 237 | ||
| 294 | impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { | 238 | impl<'d, T: Instance> Cc<'d, T> { |
| 295 | /// Get the current value stored in the register. | 239 | /// Get the current value stored in the register. |
| 296 | pub fn read(&self) -> u32 { | 240 | pub fn read(&self) -> u32 { |
| 297 | T::regs().cc[self.n].read().cc().bits() | 241 | T::regs().cc[self.n].read().cc().bits() |
| @@ -314,14 +258,14 @@ impl<'d, T: Instance, I: TimerType> Cc<'d, T, I> { | |||
| 314 | /// Returns this CC register's CAPTURE task, for use with PPI. | 258 | /// Returns this CC register's CAPTURE task, for use with PPI. |
| 315 | /// | 259 | /// |
| 316 | /// When triggered, this task will capture the current value of the timer's counter in this register. | 260 | /// When triggered, this task will capture the current value of the timer's counter in this register. |
| 317 | pub fn task_capture(&self) -> Task { | 261 | pub fn task_capture(&self) -> Task<'d> { |
| 318 | Task::from_reg(&T::regs().tasks_capture) | 262 | Task::from_reg(&T::regs().tasks_capture) |
| 319 | } | 263 | } |
| 320 | 264 | ||
| 321 | /// Returns this CC register's COMPARE event, for use with PPI. | 265 | /// Returns this CC register's COMPARE event, for use with PPI. |
| 322 | /// | 266 | /// |
| 323 | /// This event will fire when the timer's counter reaches the value in this CC register. | 267 | /// This event will fire when the timer's counter reaches the value in this CC register. |
| 324 | pub fn event_compare(&self) -> Event { | 268 | pub fn event_compare(&self) -> Event<'d> { |
| 325 | Event::from_reg(&T::regs().events_compare[self.n]) | 269 | Event::from_reg(&T::regs().events_compare[self.n]) |
| 326 | } | 270 | } |
| 327 | 271 | ||
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 850f6d0fa..2ad0d19b1 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -1,12 +1,9 @@ | |||
| 1 | //! I2C-compatible Two Wire Interface in master mode (TWIM) driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 3 | //! HAL interface to the TWIM peripheral. | 5 | use core::future::{poll_fn, Future}; |
| 4 | //! | 6 | use core::marker::PhantomData; |
| 5 | //! See product specification: | ||
| 6 | //! | ||
| 7 | //! - nRF52832: Section 33 | ||
| 8 | //! - nRF52840: Section 6.31 | ||
| 9 | use core::future::Future; | ||
| 10 | use core::sync::atomic::compiler_fence; | 7 | use core::sync::atomic::compiler_fence; |
| 11 | use core::sync::atomic::Ordering::SeqCst; | 8 | use core::sync::atomic::Ordering::SeqCst; |
| 12 | use core::task::Poll; | 9 | use core::task::Poll; |
| @@ -16,30 +13,46 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | |||
| 16 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 17 | #[cfg(feature = "time")] | 14 | #[cfg(feature = "time")] |
| 18 | use embassy_time::{Duration, Instant}; | 15 | use embassy_time::{Duration, Instant}; |
| 19 | use futures::future::poll_fn; | ||
| 20 | 16 | ||
| 21 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 17 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 22 | use crate::gpio::Pin as GpioPin; | 18 | use crate::gpio::Pin as GpioPin; |
| 23 | use crate::interrupt::{Interrupt, InterruptExt}; | 19 | use crate::interrupt::typelevel::Interrupt; |
| 24 | use crate::util::{slice_in_ram, slice_in_ram_or}; | 20 | use crate::util::{slice_in_ram, slice_in_ram_or}; |
| 25 | use crate::{gpio, pac, Peripheral}; | 21 | use crate::{gpio, interrupt, pac, Peripheral}; |
| 26 | 22 | ||
| 23 | /// TWI frequency | ||
| 27 | #[derive(Clone, Copy)] | 24 | #[derive(Clone, Copy)] |
| 28 | pub enum Frequency { | 25 | pub enum Frequency { |
| 29 | #[doc = "26738688: 100 kbps"] | 26 | /// 100 kbps |
| 30 | K100 = 26738688, | 27 | K100 = 26738688, |
| 31 | #[doc = "67108864: 250 kbps"] | 28 | /// 250 kbps |
| 32 | K250 = 67108864, | 29 | K250 = 67108864, |
| 33 | #[doc = "104857600: 400 kbps"] | 30 | /// 400 kbps |
| 34 | K400 = 104857600, | 31 | K400 = 104857600, |
| 35 | } | 32 | } |
| 36 | 33 | ||
| 34 | /// TWIM config. | ||
| 37 | #[non_exhaustive] | 35 | #[non_exhaustive] |
| 38 | pub struct Config { | 36 | pub struct Config { |
| 37 | /// Frequency | ||
| 39 | pub frequency: Frequency, | 38 | pub frequency: Frequency, |
| 39 | |||
| 40 | /// Enable high drive for the SDA line. | ||
| 40 | pub sda_high_drive: bool, | 41 | pub sda_high_drive: bool, |
| 42 | |||
| 43 | /// Enable internal pullup for the SDA line. | ||
| 44 | /// | ||
| 45 | /// Note that using external pullups is recommended for I2C, and | ||
| 46 | /// most boards already have them. | ||
| 41 | pub sda_pullup: bool, | 47 | pub sda_pullup: bool, |
| 48 | |||
| 49 | /// Enable high drive for the SCL line. | ||
| 42 | pub scl_high_drive: bool, | 50 | pub scl_high_drive: bool, |
| 51 | |||
| 52 | /// Enable internal pullup for the SCL line. | ||
| 53 | /// | ||
| 54 | /// Note that using external pullups is recommended for I2C, and | ||
| 55 | /// most boards already have them. | ||
| 43 | pub scl_pullup: bool, | 56 | pub scl_pullup: bool, |
| 44 | } | 57 | } |
| 45 | 58 | ||
| @@ -55,37 +68,67 @@ impl Default for Config { | |||
| 55 | } | 68 | } |
| 56 | } | 69 | } |
| 57 | 70 | ||
| 71 | /// TWI error. | ||
| 58 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | 72 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 59 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 73 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 60 | #[non_exhaustive] | 74 | #[non_exhaustive] |
| 61 | pub enum Error { | 75 | pub enum Error { |
| 76 | /// TX buffer was too long. | ||
| 62 | TxBufferTooLong, | 77 | TxBufferTooLong, |
| 78 | /// RX buffer was too long. | ||
| 63 | RxBufferTooLong, | 79 | RxBufferTooLong, |
| 80 | /// Data transmit failed. | ||
| 64 | Transmit, | 81 | Transmit, |
| 82 | /// Data reception failed. | ||
| 65 | Receive, | 83 | Receive, |
| 66 | DMABufferNotInDataMemory, | 84 | /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. |
| 85 | BufferNotInRAM, | ||
| 86 | /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly. | ||
| 67 | AddressNack, | 87 | AddressNack, |
| 88 | /// Didn't receive an ACK bit after a data byte. | ||
| 68 | DataNack, | 89 | DataNack, |
| 90 | /// Overrun error. | ||
| 69 | Overrun, | 91 | Overrun, |
| 92 | /// Timeout error. | ||
| 70 | Timeout, | 93 | Timeout, |
| 71 | } | 94 | } |
| 72 | 95 | ||
| 73 | /// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. | 96 | /// Interrupt handler. |
| 74 | /// | 97 | pub struct InterruptHandler<T: Instance> { |
| 75 | /// For more details about EasyDMA, consult the module documentation. | 98 | _phantom: PhantomData<T>, |
| 99 | } | ||
| 100 | |||
| 101 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 102 | unsafe fn on_interrupt() { | ||
| 103 | let r = T::regs(); | ||
| 104 | let s = T::state(); | ||
| 105 | |||
| 106 | if r.events_stopped.read().bits() != 0 { | ||
| 107 | s.end_waker.wake(); | ||
| 108 | r.intenclr.write(|w| w.stopped().clear()); | ||
| 109 | } | ||
| 110 | if r.events_error.read().bits() != 0 { | ||
| 111 | s.end_waker.wake(); | ||
| 112 | r.intenclr.write(|w| w.error().clear()); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | /// TWI driver. | ||
| 76 | pub struct Twim<'d, T: Instance> { | 118 | pub struct Twim<'d, T: Instance> { |
| 77 | _p: PeripheralRef<'d, T>, | 119 | _p: PeripheralRef<'d, T>, |
| 78 | } | 120 | } |
| 79 | 121 | ||
| 80 | impl<'d, T: Instance> Twim<'d, T> { | 122 | impl<'d, T: Instance> Twim<'d, T> { |
| 123 | /// Create a new TWI driver. | ||
| 81 | pub fn new( | 124 | pub fn new( |
| 82 | twim: impl Peripheral<P = T> + 'd, | 125 | twim: impl Peripheral<P = T> + 'd, |
| 83 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 126 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 84 | sda: impl Peripheral<P = impl GpioPin> + 'd, | 127 | sda: impl Peripheral<P = impl GpioPin> + 'd, |
| 85 | scl: impl Peripheral<P = impl GpioPin> + 'd, | 128 | scl: impl Peripheral<P = impl GpioPin> + 'd, |
| 86 | config: Config, | 129 | config: Config, |
| 87 | ) -> Self { | 130 | ) -> Self { |
| 88 | into_ref!(twim, irq, sda, scl); | 131 | into_ref!(twim, sda, scl); |
| 89 | 132 | ||
| 90 | let r = T::regs(); | 133 | let r = T::regs(); |
| 91 | 134 | ||
| @@ -131,30 +174,15 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 131 | // Disable all events interrupts | 174 | // Disable all events interrupts |
| 132 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | 175 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); |
| 133 | 176 | ||
| 134 | irq.set_handler(Self::on_interrupt); | 177 | T::Interrupt::unpend(); |
| 135 | irq.unpend(); | 178 | unsafe { T::Interrupt::enable() }; |
| 136 | irq.enable(); | ||
| 137 | 179 | ||
| 138 | Self { _p: twim } | 180 | Self { _p: twim } |
| 139 | } | 181 | } |
| 140 | 182 | ||
| 141 | fn on_interrupt(_: *mut ()) { | ||
| 142 | let r = T::regs(); | ||
| 143 | let s = T::state(); | ||
| 144 | |||
| 145 | if r.events_stopped.read().bits() != 0 { | ||
| 146 | s.end_waker.wake(); | ||
| 147 | r.intenclr.write(|w| w.stopped().clear()); | ||
| 148 | } | ||
| 149 | if r.events_error.read().bits() != 0 { | ||
| 150 | s.end_waker.wake(); | ||
| 151 | r.intenclr.write(|w| w.error().clear()); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | /// Set TX buffer, checking that it is in RAM and has suitable length. | 183 | /// Set TX buffer, checking that it is in RAM and has suitable length. |
| 156 | unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | 184 | unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 157 | slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; | 185 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; |
| 158 | 186 | ||
| 159 | if buffer.len() > EASY_DMA_SIZE { | 187 | if buffer.len() > EASY_DMA_SIZE { |
| 160 | return Err(Error::TxBufferTooLong); | 188 | return Err(Error::TxBufferTooLong); |
| @@ -234,7 +262,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 234 | return Err(Error::DataNack); | 262 | return Err(Error::DataNack); |
| 235 | } | 263 | } |
| 236 | if err.overrun().is_received() { | 264 | if err.overrun().is_received() { |
| 237 | return Err(Error::DataNack); | 265 | return Err(Error::Overrun); |
| 238 | } | 266 | } |
| 239 | Ok(()) | 267 | Ok(()) |
| 240 | } | 268 | } |
| @@ -308,7 +336,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 308 | return Poll::Ready(()); | 336 | return Poll::Ready(()); |
| 309 | } | 337 | } |
| 310 | 338 | ||
| 311 | // stop if an error occured | 339 | // stop if an error occurred |
| 312 | if r.events_error.read().bits() != 0 { | 340 | if r.events_error.read().bits() != 0 { |
| 313 | r.events_error.reset(); | 341 | r.events_error.reset(); |
| 314 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 342 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); |
| @@ -436,7 +464,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 436 | ) -> Result<(), Error> { | 464 | ) -> Result<(), Error> { |
| 437 | match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { | 465 | match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { |
| 438 | Ok(_) => Ok(()), | 466 | Ok(_) => Ok(()), |
| 439 | Err(Error::DMABufferNotInDataMemory) => { | 467 | Err(Error::BufferNotInRAM) => { |
| 440 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 468 | trace!("Copying TWIM tx buffer into RAM for DMA"); |
| 441 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 469 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; |
| 442 | tx_ram_buf.copy_from_slice(wr_buffer); | 470 | tx_ram_buf.copy_from_slice(wr_buffer); |
| @@ -449,7 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 449 | fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { | 477 | fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { |
| 450 | match self.setup_write_from_ram(address, wr_buffer, inten) { | 478 | match self.setup_write_from_ram(address, wr_buffer, inten) { |
| 451 | Ok(_) => Ok(()), | 479 | Ok(_) => Ok(()), |
| 452 | Err(Error::DMABufferNotInDataMemory) => { | 480 | Err(Error::BufferNotInRAM) => { |
| 453 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 481 | trace!("Copying TWIM tx buffer into RAM for DMA"); |
| 454 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 482 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; |
| 455 | tx_ram_buf.copy_from_slice(wr_buffer); | 483 | tx_ram_buf.copy_from_slice(wr_buffer); |
| @@ -613,6 +641,10 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 613 | 641 | ||
| 614 | // =========================================== | 642 | // =========================================== |
| 615 | 643 | ||
| 644 | /// Read from an I2C slave. | ||
| 645 | /// | ||
| 646 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 647 | /// and at most 65535 bytes on the nRF52840. | ||
| 616 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 648 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 617 | self.setup_read(address, buffer, true)?; | 649 | self.setup_read(address, buffer, true)?; |
| 618 | self.async_wait().await; | 650 | self.async_wait().await; |
| @@ -622,6 +654,10 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 622 | Ok(()) | 654 | Ok(()) |
| 623 | } | 655 | } |
| 624 | 656 | ||
| 657 | /// Write to an I2C slave. | ||
| 658 | /// | ||
| 659 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 660 | /// and at most 65535 bytes on the nRF52840. | ||
| 625 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 661 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 626 | self.setup_write(address, buffer, true)?; | 662 | self.setup_write(address, buffer, true)?; |
| 627 | self.async_wait().await; | 663 | self.async_wait().await; |
| @@ -641,6 +677,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 641 | Ok(()) | 677 | Ok(()) |
| 642 | } | 678 | } |
| 643 | 679 | ||
| 680 | /// Write data to an I2C slave, then read data from the slave without | ||
| 681 | /// triggering a stop condition between the two. | ||
| 682 | /// | ||
| 683 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||
| 684 | /// and at most 65535 bytes on the nRF52840. | ||
| 644 | pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { | 685 | pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { |
| 645 | self.setup_write_read(address, wr_buffer, rd_buffer, true)?; | 686 | self.setup_write_read(address, wr_buffer, rd_buffer, true)?; |
| 646 | self.async_wait().await; | 687 | self.async_wait().await; |
| @@ -706,8 +747,10 @@ pub(crate) mod sealed { | |||
| 706 | } | 747 | } |
| 707 | } | 748 | } |
| 708 | 749 | ||
| 750 | /// TWIM peripheral instance. | ||
| 709 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 751 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { |
| 710 | type Interrupt: Interrupt; | 752 | /// Interrupt for this peripheral. |
| 753 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 711 | } | 754 | } |
| 712 | 755 | ||
| 713 | macro_rules! impl_twim { | 756 | macro_rules! impl_twim { |
| @@ -722,7 +765,7 @@ macro_rules! impl_twim { | |||
| 722 | } | 765 | } |
| 723 | } | 766 | } |
| 724 | impl crate::twim::Instance for peripherals::$type { | 767 | impl crate::twim::Instance for peripherals::$type { |
| 725 | type Interrupt = crate::interrupt::$irq; | 768 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 726 | } | 769 | } |
| 727 | }; | 770 | }; |
| 728 | } | 771 | } |
| @@ -777,7 +820,7 @@ mod eh1 { | |||
| 777 | Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, | 820 | Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, |
| 778 | Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, | 821 | Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, |
| 779 | Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, | 822 | Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, |
| 780 | Self::DMABufferNotInDataMemory => embedded_hal_1::i2c::ErrorKind::Other, | 823 | Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, |
| 781 | Self::AddressNack => { | 824 | Self::AddressNack => { |
| 782 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) | 825 | embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) |
| 783 | } | 826 | } |
| @@ -794,7 +837,7 @@ mod eh1 { | |||
| 794 | type Error = Error; | 837 | type Error = Error; |
| 795 | } | 838 | } |
| 796 | 839 | ||
| 797 | impl<'d, T: Instance> embedded_hal_1::i2c::blocking::I2c for Twim<'d, T> { | 840 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { |
| 798 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 841 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { |
| 799 | self.blocking_read(address, buffer) | 842 | self.blocking_read(address, buffer) |
| 800 | } | 843 | } |
| @@ -803,20 +846,6 @@ mod eh1 { | |||
| 803 | self.blocking_write(address, buffer) | 846 | self.blocking_write(address, buffer) |
| 804 | } | 847 | } |
| 805 | 848 | ||
| 806 | fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> | ||
| 807 | where | ||
| 808 | B: IntoIterator<Item = u8>, | ||
| 809 | { | ||
| 810 | todo!(); | ||
| 811 | } | ||
| 812 | |||
| 813 | fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> | ||
| 814 | where | ||
| 815 | B: IntoIterator<Item = u8>, | ||
| 816 | { | ||
| 817 | todo!(); | ||
| 818 | } | ||
| 819 | |||
| 820 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | 849 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { |
| 821 | self.blocking_write_read(address, wr_buffer, rd_buffer) | 850 | self.blocking_write_read(address, wr_buffer, rd_buffer) |
| 822 | } | 851 | } |
| @@ -824,57 +853,36 @@ mod eh1 { | |||
| 824 | fn transaction<'a>( | 853 | fn transaction<'a>( |
| 825 | &mut self, | 854 | &mut self, |
| 826 | _address: u8, | 855 | _address: u8, |
| 827 | _operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>], | 856 | _operations: &mut [embedded_hal_1::i2c::Operation<'a>], |
| 828 | ) -> Result<(), Self::Error> { | 857 | ) -> Result<(), Self::Error> { |
| 829 | todo!(); | 858 | todo!(); |
| 830 | } | 859 | } |
| 831 | |||
| 832 | fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> | ||
| 833 | where | ||
| 834 | O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>, | ||
| 835 | { | ||
| 836 | todo!(); | ||
| 837 | } | ||
| 838 | } | 860 | } |
| 839 | } | 861 | } |
| 840 | 862 | ||
| 841 | cfg_if::cfg_if! { | 863 | #[cfg(all(feature = "unstable-traits", feature = "nightly"))] |
| 842 | if #[cfg(all(feature = "unstable-traits", feature = "nightly"))] { | 864 | mod eha { |
| 843 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { | 865 | use super::*; |
| 844 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | 866 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { |
| 845 | 867 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | |
| 846 | fn read<'a>(&'a mut self, address: u8, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | 868 | self.read(address, read).await |
| 847 | self.read(address, buffer) | 869 | } |
| 848 | } | ||
| 849 | |||
| 850 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 851 | |||
| 852 | fn write<'a>(&'a mut self, address: u8, bytes: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 853 | self.write(address, bytes) | ||
| 854 | } | ||
| 855 | |||
| 856 | type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 857 | |||
| 858 | fn write_read<'a>( | ||
| 859 | &'a mut self, | ||
| 860 | address: u8, | ||
| 861 | wr_buffer: &'a [u8], | ||
| 862 | rd_buffer: &'a mut [u8], | ||
| 863 | ) -> Self::WriteReadFuture<'a> { | ||
| 864 | self.write_read(address, wr_buffer, rd_buffer) | ||
| 865 | } | ||
| 866 | 870 | ||
| 867 | type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a, 'b: 'a; | 871 | async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { |
| 872 | self.write(address, write).await | ||
| 873 | } | ||
| 874 | async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | ||
| 875 | self.write_read(address, write, read).await | ||
| 876 | } | ||
| 868 | 877 | ||
| 869 | fn transaction<'a, 'b>( | 878 | async fn transaction( |
| 870 | &'a mut self, | 879 | &mut self, |
| 871 | address: u8, | 880 | address: u8, |
| 872 | operations: &'a mut [embedded_hal_async::i2c::Operation<'b>], | 881 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], |
| 873 | ) -> Self::TransactionFuture<'a, 'b> { | 882 | ) -> Result<(), Self::Error> { |
| 874 | let _ = address; | 883 | let _ = address; |
| 875 | let _ = operations; | 884 | let _ = operations; |
| 876 | async move { todo!() } | 885 | todo!() |
| 877 | } | ||
| 878 | } | 886 | } |
| 879 | } | 887 | } |
| 880 | } | 888 | } |
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs new file mode 100644 index 000000000..a115d5616 --- /dev/null +++ b/embassy-nrf/src/twis.rs | |||
| @@ -0,0 +1,799 @@ | |||
| 1 | //! I2C-compatible Two Wire Interface in slave mode (TWIM) driver. | ||
| 2 | |||
| 3 | #![macro_use] | ||
| 4 | |||
| 5 | use core::future::{poll_fn, Future}; | ||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::sync::atomic::compiler_fence; | ||
| 8 | use core::sync::atomic::Ordering::SeqCst; | ||
| 9 | use core::task::Poll; | ||
| 10 | |||
| 11 | use embassy_hal_common::{into_ref, PeripheralRef}; | ||
| 12 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 13 | #[cfg(feature = "time")] | ||
| 14 | use embassy_time::{Duration, Instant}; | ||
| 15 | |||
| 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | ||
| 17 | use crate::gpio::Pin as GpioPin; | ||
| 18 | use crate::interrupt::typelevel::Interrupt; | ||
| 19 | use crate::util::slice_in_ram_or; | ||
| 20 | use crate::{gpio, interrupt, pac, Peripheral}; | ||
| 21 | |||
| 22 | /// TWIS config. | ||
| 23 | #[non_exhaustive] | ||
| 24 | pub struct Config { | ||
| 25 | /// First address | ||
| 26 | pub address0: u8, | ||
| 27 | |||
| 28 | /// Second address, optional. | ||
| 29 | pub address1: Option<u8>, | ||
| 30 | |||
| 31 | /// Overread character. | ||
| 32 | /// | ||
| 33 | /// If the master keeps clocking the bus after all the bytes in the TX buffer have | ||
| 34 | /// already been transmitted, this byte will be constantly transmitted. | ||
| 35 | pub orc: u8, | ||
| 36 | |||
| 37 | /// Enable high drive for the SDA line. | ||
| 38 | pub sda_high_drive: bool, | ||
| 39 | |||
| 40 | /// Enable internal pullup for the SDA line. | ||
| 41 | /// | ||
| 42 | /// Note that using external pullups is recommended for I2C, and | ||
| 43 | /// most boards already have them. | ||
| 44 | pub sda_pullup: bool, | ||
| 45 | |||
| 46 | /// Enable high drive for the SCL line. | ||
| 47 | pub scl_high_drive: bool, | ||
| 48 | |||
| 49 | /// Enable internal pullup for the SCL line. | ||
| 50 | /// | ||
| 51 | /// Note that using external pullups is recommended for I2C, and | ||
| 52 | /// most boards already have them. | ||
| 53 | pub scl_pullup: bool, | ||
| 54 | } | ||
| 55 | |||
| 56 | impl Default for Config { | ||
| 57 | fn default() -> Self { | ||
| 58 | Self { | ||
| 59 | address0: 0x55, | ||
| 60 | address1: None, | ||
| 61 | orc: 0x00, | ||
| 62 | scl_high_drive: false, | ||
| 63 | sda_pullup: false, | ||
| 64 | sda_high_drive: false, | ||
| 65 | scl_pullup: false, | ||
| 66 | } | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 71 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 72 | enum Status { | ||
| 73 | Read, | ||
| 74 | Write, | ||
| 75 | } | ||
| 76 | |||
| 77 | /// TWIS error. | ||
| 78 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 79 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 80 | #[non_exhaustive] | ||
| 81 | pub enum Error { | ||
| 82 | /// TX buffer was too long. | ||
| 83 | TxBufferTooLong, | ||
| 84 | /// RX buffer was too long. | ||
| 85 | RxBufferTooLong, | ||
| 86 | /// Didn't receive an ACK bit after a data byte. | ||
| 87 | DataNack, | ||
| 88 | /// Bus error. | ||
| 89 | Bus, | ||
| 90 | /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. | ||
| 91 | BufferNotInRAM, | ||
| 92 | /// Overflow | ||
| 93 | Overflow, | ||
| 94 | /// Overread | ||
| 95 | OverRead, | ||
| 96 | /// Timeout | ||
| 97 | Timeout, | ||
| 98 | } | ||
| 99 | |||
| 100 | /// Received command | ||
| 101 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 102 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 103 | pub enum Command { | ||
| 104 | /// Read | ||
| 105 | Read, | ||
| 106 | /// Write+read | ||
| 107 | WriteRead(usize), | ||
| 108 | /// Write | ||
| 109 | Write(usize), | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Interrupt handler. | ||
| 113 | pub struct InterruptHandler<T: Instance> { | ||
| 114 | _phantom: PhantomData<T>, | ||
| 115 | } | ||
| 116 | |||
| 117 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 118 | unsafe fn on_interrupt() { | ||
| 119 | let r = T::regs(); | ||
| 120 | let s = T::state(); | ||
| 121 | |||
| 122 | if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { | ||
| 123 | s.waker.wake(); | ||
| 124 | r.intenclr.modify(|_r, w| w.read().clear().write().clear()); | ||
| 125 | } | ||
| 126 | if r.events_stopped.read().bits() != 0 { | ||
| 127 | s.waker.wake(); | ||
| 128 | r.intenclr.modify(|_r, w| w.stopped().clear()); | ||
| 129 | } | ||
| 130 | if r.events_error.read().bits() != 0 { | ||
| 131 | s.waker.wake(); | ||
| 132 | r.intenclr.modify(|_r, w| w.error().clear()); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | /// TWIS driver. | ||
| 138 | pub struct Twis<'d, T: Instance> { | ||
| 139 | _p: PeripheralRef<'d, T>, | ||
| 140 | } | ||
| 141 | |||
| 142 | impl<'d, T: Instance> Twis<'d, T> { | ||
| 143 | /// Create a new TWIS driver. | ||
| 144 | pub fn new( | ||
| 145 | twis: impl Peripheral<P = T> + 'd, | ||
| 146 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 147 | sda: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 148 | scl: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 149 | config: Config, | ||
| 150 | ) -> Self { | ||
| 151 | into_ref!(twis, sda, scl); | ||
| 152 | |||
| 153 | let r = T::regs(); | ||
| 154 | |||
| 155 | // Configure pins | ||
| 156 | sda.conf().write(|w| { | ||
| 157 | w.dir().input(); | ||
| 158 | w.input().connect(); | ||
| 159 | if config.sda_high_drive { | ||
| 160 | w.drive().h0d1(); | ||
| 161 | } else { | ||
| 162 | w.drive().s0d1(); | ||
| 163 | } | ||
| 164 | if config.sda_pullup { | ||
| 165 | w.pull().pullup(); | ||
| 166 | } | ||
| 167 | w | ||
| 168 | }); | ||
| 169 | scl.conf().write(|w| { | ||
| 170 | w.dir().input(); | ||
| 171 | w.input().connect(); | ||
| 172 | if config.scl_high_drive { | ||
| 173 | w.drive().h0d1(); | ||
| 174 | } else { | ||
| 175 | w.drive().s0d1(); | ||
| 176 | } | ||
| 177 | if config.scl_pullup { | ||
| 178 | w.pull().pullup(); | ||
| 179 | } | ||
| 180 | w | ||
| 181 | }); | ||
| 182 | |||
| 183 | // Select pins. | ||
| 184 | r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); | ||
| 185 | r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); | ||
| 186 | |||
| 187 | // Enable TWIS instance. | ||
| 188 | r.enable.write(|w| w.enable().enabled()); | ||
| 189 | |||
| 190 | // Disable all events interrupts | ||
| 191 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||
| 192 | |||
| 193 | // Set address | ||
| 194 | r.address[0].write(|w| unsafe { w.address().bits(config.address0) }); | ||
| 195 | r.config.write(|w| w.address0().enabled()); | ||
| 196 | if let Some(address1) = config.address1 { | ||
| 197 | r.address[1].write(|w| unsafe { w.address().bits(address1) }); | ||
| 198 | r.config.modify(|_r, w| w.address1().enabled()); | ||
| 199 | } | ||
| 200 | |||
| 201 | // Set over-read character | ||
| 202 | r.orc.write(|w| unsafe { w.orc().bits(config.orc) }); | ||
| 203 | |||
| 204 | // Generate suspend on read event | ||
| 205 | r.shorts.write(|w| w.read_suspend().enabled()); | ||
| 206 | |||
| 207 | T::Interrupt::unpend(); | ||
| 208 | unsafe { T::Interrupt::enable() }; | ||
| 209 | |||
| 210 | Self { _p: twis } | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Set TX buffer, checking that it is in RAM and has suitable length. | ||
| 214 | unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 215 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||
| 216 | |||
| 217 | if buffer.len() > EASY_DMA_SIZE { | ||
| 218 | return Err(Error::TxBufferTooLong); | ||
| 219 | } | ||
| 220 | |||
| 221 | let r = T::regs(); | ||
| 222 | |||
| 223 | r.txd.ptr.write(|w| | ||
| 224 | // We're giving the register a pointer to the stack. Since we're | ||
| 225 | // waiting for the I2C transaction to end before this stack pointer | ||
| 226 | // becomes invalid, there's nothing wrong here. | ||
| 227 | // | ||
| 228 | // The PTR field is a full 32 bits wide and accepts the full range | ||
| 229 | // of values. | ||
| 230 | w.ptr().bits(buffer.as_ptr() as u32)); | ||
| 231 | r.txd.maxcnt.write(|w| | ||
| 232 | // We're giving it the length of the buffer, so no danger of | ||
| 233 | // accessing invalid memory. We have verified that the length of the | ||
| 234 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||
| 235 | // | ||
| 236 | // The MAXCNT field is 8 bits wide and accepts the full range of | ||
| 237 | // values. | ||
| 238 | w.maxcnt().bits(buffer.len() as _)); | ||
| 239 | |||
| 240 | Ok(()) | ||
| 241 | } | ||
| 242 | |||
| 243 | /// Set RX buffer, checking that it has suitable length. | ||
| 244 | unsafe fn set_rx_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 245 | // NOTE: RAM slice check is not necessary, as a mutable | ||
| 246 | // slice can only be built from data located in RAM. | ||
| 247 | |||
| 248 | if buffer.len() > EASY_DMA_SIZE { | ||
| 249 | return Err(Error::RxBufferTooLong); | ||
| 250 | } | ||
| 251 | |||
| 252 | let r = T::regs(); | ||
| 253 | |||
| 254 | r.rxd.ptr.write(|w| | ||
| 255 | // We're giving the register a pointer to the stack. Since we're | ||
| 256 | // waiting for the I2C transaction to end before this stack pointer | ||
| 257 | // becomes invalid, there's nothing wrong here. | ||
| 258 | // | ||
| 259 | // The PTR field is a full 32 bits wide and accepts the full range | ||
| 260 | // of values. | ||
| 261 | w.ptr().bits(buffer.as_mut_ptr() as u32)); | ||
| 262 | r.rxd.maxcnt.write(|w| | ||
| 263 | // We're giving it the length of the buffer, so no danger of | ||
| 264 | // accessing invalid memory. We have verified that the length of the | ||
| 265 | // buffer fits in an `u8`, so the cast to the type of maxcnt | ||
| 266 | // is also fine. | ||
| 267 | // | ||
| 268 | // Note that that nrf52840 maxcnt is a wider | ||
| 269 | // type than a u8, so we use a `_` cast rather than a `u8` cast. | ||
| 270 | // The MAXCNT field is thus at least 8 bits wide and accepts the | ||
| 271 | // full range of values that fit in a `u8`. | ||
| 272 | w.maxcnt().bits(buffer.len() as _)); | ||
| 273 | |||
| 274 | Ok(()) | ||
| 275 | } | ||
| 276 | |||
| 277 | fn clear_errorsrc(&mut self) { | ||
| 278 | let r = T::regs(); | ||
| 279 | r.errorsrc | ||
| 280 | .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true)); | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Returns matched address for latest command. | ||
| 284 | pub fn address_match(&self) -> u8 { | ||
| 285 | let r = T::regs(); | ||
| 286 | r.address[r.match_.read().bits() as usize].read().address().bits() | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Returns the index of the address matched in the latest command. | ||
| 290 | pub fn address_match_index(&self) -> usize { | ||
| 291 | T::regs().match_.read().bits() as _ | ||
| 292 | } | ||
| 293 | |||
| 294 | /// Wait for read, write, stop or error | ||
| 295 | fn blocking_listen_wait(&mut self) -> Result<Status, Error> { | ||
| 296 | let r = T::regs(); | ||
| 297 | loop { | ||
| 298 | if r.events_error.read().bits() != 0 { | ||
| 299 | r.events_error.reset(); | ||
| 300 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 301 | while r.events_stopped.read().bits() == 0 {} | ||
| 302 | return Err(Error::Overflow); | ||
| 303 | } | ||
| 304 | if r.events_stopped.read().bits() != 0 { | ||
| 305 | r.events_stopped.reset(); | ||
| 306 | return Err(Error::Bus); | ||
| 307 | } | ||
| 308 | if r.events_read.read().bits() != 0 { | ||
| 309 | r.events_read.reset(); | ||
| 310 | return Ok(Status::Read); | ||
| 311 | } | ||
| 312 | if r.events_write.read().bits() != 0 { | ||
| 313 | r.events_write.reset(); | ||
| 314 | return Ok(Status::Write); | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | /// Wait for stop, repeated start or error | ||
| 320 | fn blocking_listen_wait_end(&mut self, status: Status) -> Result<Command, Error> { | ||
| 321 | let r = T::regs(); | ||
| 322 | loop { | ||
| 323 | // stop if an error occurred | ||
| 324 | if r.events_error.read().bits() != 0 { | ||
| 325 | r.events_error.reset(); | ||
| 326 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 327 | return Err(Error::Overflow); | ||
| 328 | } else if r.events_stopped.read().bits() != 0 { | ||
| 329 | r.events_stopped.reset(); | ||
| 330 | return match status { | ||
| 331 | Status::Read => Ok(Command::Read), | ||
| 332 | Status::Write => { | ||
| 333 | let n = r.rxd.amount.read().bits() as usize; | ||
| 334 | Ok(Command::Write(n)) | ||
| 335 | } | ||
| 336 | }; | ||
| 337 | } else if r.events_read.read().bits() != 0 { | ||
| 338 | r.events_read.reset(); | ||
| 339 | let n = r.rxd.amount.read().bits() as usize; | ||
| 340 | return Ok(Command::WriteRead(n)); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | /// Wait for stop or error | ||
| 346 | fn blocking_wait(&mut self) -> Result<usize, Error> { | ||
| 347 | let r = T::regs(); | ||
| 348 | loop { | ||
| 349 | // stop if an error occurred | ||
| 350 | if r.events_error.read().bits() != 0 { | ||
| 351 | r.events_error.reset(); | ||
| 352 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 353 | let errorsrc = r.errorsrc.read(); | ||
| 354 | if errorsrc.overread().is_detected() { | ||
| 355 | return Err(Error::OverRead); | ||
| 356 | } else if errorsrc.dnack().is_received() { | ||
| 357 | return Err(Error::DataNack); | ||
| 358 | } else { | ||
| 359 | return Err(Error::Bus); | ||
| 360 | } | ||
| 361 | } else if r.events_stopped.read().bits() != 0 { | ||
| 362 | r.events_stopped.reset(); | ||
| 363 | let n = r.txd.amount.read().bits() as usize; | ||
| 364 | return Ok(n); | ||
| 365 | } | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | /// Wait for stop or error with timeout | ||
| 370 | #[cfg(feature = "time")] | ||
| 371 | fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<usize, Error> { | ||
| 372 | let r = T::regs(); | ||
| 373 | let deadline = Instant::now() + timeout; | ||
| 374 | loop { | ||
| 375 | // stop if an error occurred | ||
| 376 | if r.events_error.read().bits() != 0 { | ||
| 377 | r.events_error.reset(); | ||
| 378 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 379 | let errorsrc = r.errorsrc.read(); | ||
| 380 | if errorsrc.overread().is_detected() { | ||
| 381 | return Err(Error::OverRead); | ||
| 382 | } else if errorsrc.dnack().is_received() { | ||
| 383 | return Err(Error::DataNack); | ||
| 384 | } else { | ||
| 385 | return Err(Error::Bus); | ||
| 386 | } | ||
| 387 | } else if r.events_stopped.read().bits() != 0 { | ||
| 388 | r.events_stopped.reset(); | ||
| 389 | let n = r.txd.amount.read().bits() as usize; | ||
| 390 | return Ok(n); | ||
| 391 | } else if Instant::now() > deadline { | ||
| 392 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 393 | return Err(Error::Timeout); | ||
| 394 | } | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | /// Wait for read, write, stop or error with timeout | ||
| 399 | #[cfg(feature = "time")] | ||
| 400 | fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result<Status, Error> { | ||
| 401 | let r = T::regs(); | ||
| 402 | let deadline = Instant::now() + timeout; | ||
| 403 | loop { | ||
| 404 | if r.events_error.read().bits() != 0 { | ||
| 405 | r.events_error.reset(); | ||
| 406 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 407 | while r.events_stopped.read().bits() == 0 {} | ||
| 408 | return Err(Error::Overflow); | ||
| 409 | } | ||
| 410 | if r.events_stopped.read().bits() != 0 { | ||
| 411 | r.events_stopped.reset(); | ||
| 412 | return Err(Error::Bus); | ||
| 413 | } | ||
| 414 | if r.events_read.read().bits() != 0 { | ||
| 415 | r.events_read.reset(); | ||
| 416 | return Ok(Status::Read); | ||
| 417 | } | ||
| 418 | if r.events_write.read().bits() != 0 { | ||
| 419 | r.events_write.reset(); | ||
| 420 | return Ok(Status::Write); | ||
| 421 | } | ||
| 422 | if Instant::now() > deadline { | ||
| 423 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 424 | return Err(Error::Timeout); | ||
| 425 | } | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | /// Wait for stop, repeated start or error with timeout | ||
| 430 | #[cfg(feature = "time")] | ||
| 431 | fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result<Command, Error> { | ||
| 432 | let r = T::regs(); | ||
| 433 | let deadline = Instant::now() + timeout; | ||
| 434 | loop { | ||
| 435 | // stop if an error occurred | ||
| 436 | if r.events_error.read().bits() != 0 { | ||
| 437 | r.events_error.reset(); | ||
| 438 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 439 | return Err(Error::Overflow); | ||
| 440 | } else if r.events_stopped.read().bits() != 0 { | ||
| 441 | r.events_stopped.reset(); | ||
| 442 | return match status { | ||
| 443 | Status::Read => Ok(Command::Read), | ||
| 444 | Status::Write => { | ||
| 445 | let n = r.rxd.amount.read().bits() as usize; | ||
| 446 | Ok(Command::Write(n)) | ||
| 447 | } | ||
| 448 | }; | ||
| 449 | } else if r.events_read.read().bits() != 0 { | ||
| 450 | r.events_read.reset(); | ||
| 451 | let n = r.rxd.amount.read().bits() as usize; | ||
| 452 | return Ok(Command::WriteRead(n)); | ||
| 453 | } else if Instant::now() > deadline { | ||
| 454 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 455 | return Err(Error::Timeout); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | /// Wait for stop or error | ||
| 461 | fn async_wait(&mut self) -> impl Future<Output = Result<usize, Error>> { | ||
| 462 | poll_fn(move |cx| { | ||
| 463 | let r = T::regs(); | ||
| 464 | let s = T::state(); | ||
| 465 | |||
| 466 | s.waker.register(cx.waker()); | ||
| 467 | |||
| 468 | // stop if an error occurred | ||
| 469 | if r.events_error.read().bits() != 0 { | ||
| 470 | r.events_error.reset(); | ||
| 471 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 472 | let errorsrc = r.errorsrc.read(); | ||
| 473 | if errorsrc.overread().is_detected() { | ||
| 474 | return Poll::Ready(Err(Error::OverRead)); | ||
| 475 | } else if errorsrc.dnack().is_received() { | ||
| 476 | return Poll::Ready(Err(Error::DataNack)); | ||
| 477 | } else { | ||
| 478 | return Poll::Ready(Err(Error::Bus)); | ||
| 479 | } | ||
| 480 | } else if r.events_stopped.read().bits() != 0 { | ||
| 481 | r.events_stopped.reset(); | ||
| 482 | let n = r.txd.amount.read().bits() as usize; | ||
| 483 | return Poll::Ready(Ok(n)); | ||
| 484 | } | ||
| 485 | |||
| 486 | Poll::Pending | ||
| 487 | }) | ||
| 488 | } | ||
| 489 | |||
| 490 | /// Wait for read or write | ||
| 491 | fn async_listen_wait(&mut self) -> impl Future<Output = Result<Status, Error>> { | ||
| 492 | poll_fn(move |cx| { | ||
| 493 | let r = T::regs(); | ||
| 494 | let s = T::state(); | ||
| 495 | |||
| 496 | s.waker.register(cx.waker()); | ||
| 497 | |||
| 498 | // stop if an error occurred | ||
| 499 | if r.events_error.read().bits() != 0 { | ||
| 500 | r.events_error.reset(); | ||
| 501 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 502 | return Poll::Ready(Err(Error::Overflow)); | ||
| 503 | } else if r.events_read.read().bits() != 0 { | ||
| 504 | r.events_read.reset(); | ||
| 505 | return Poll::Ready(Ok(Status::Read)); | ||
| 506 | } else if r.events_write.read().bits() != 0 { | ||
| 507 | r.events_write.reset(); | ||
| 508 | return Poll::Ready(Ok(Status::Write)); | ||
| 509 | } else if r.events_stopped.read().bits() != 0 { | ||
| 510 | r.events_stopped.reset(); | ||
| 511 | return Poll::Ready(Err(Error::Bus)); | ||
| 512 | } | ||
| 513 | Poll::Pending | ||
| 514 | }) | ||
| 515 | } | ||
| 516 | |||
| 517 | /// Wait for stop, repeated start or error | ||
| 518 | fn async_listen_wait_end(&mut self, status: Status) -> impl Future<Output = Result<Command, Error>> { | ||
| 519 | poll_fn(move |cx| { | ||
| 520 | let r = T::regs(); | ||
| 521 | let s = T::state(); | ||
| 522 | |||
| 523 | s.waker.register(cx.waker()); | ||
| 524 | |||
| 525 | // stop if an error occurred | ||
| 526 | if r.events_error.read().bits() != 0 { | ||
| 527 | r.events_error.reset(); | ||
| 528 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 529 | return Poll::Ready(Err(Error::Overflow)); | ||
| 530 | } else if r.events_stopped.read().bits() != 0 { | ||
| 531 | r.events_stopped.reset(); | ||
| 532 | return match status { | ||
| 533 | Status::Read => Poll::Ready(Ok(Command::Read)), | ||
| 534 | Status::Write => { | ||
| 535 | let n = r.rxd.amount.read().bits() as usize; | ||
| 536 | Poll::Ready(Ok(Command::Write(n))) | ||
| 537 | } | ||
| 538 | }; | ||
| 539 | } else if r.events_read.read().bits() != 0 { | ||
| 540 | r.events_read.reset(); | ||
| 541 | let n = r.rxd.amount.read().bits() as usize; | ||
| 542 | return Poll::Ready(Ok(Command::WriteRead(n))); | ||
| 543 | } | ||
| 544 | Poll::Pending | ||
| 545 | }) | ||
| 546 | } | ||
| 547 | |||
| 548 | fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { | ||
| 549 | let r = T::regs(); | ||
| 550 | |||
| 551 | compiler_fence(SeqCst); | ||
| 552 | |||
| 553 | // Set up the DMA write. | ||
| 554 | unsafe { self.set_tx_buffer(buffer)? }; | ||
| 555 | |||
| 556 | // Clear events | ||
| 557 | r.events_stopped.reset(); | ||
| 558 | r.events_error.reset(); | ||
| 559 | self.clear_errorsrc(); | ||
| 560 | |||
| 561 | if inten { | ||
| 562 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 563 | } else { | ||
| 564 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | ||
| 565 | } | ||
| 566 | |||
| 567 | // Start write operation. | ||
| 568 | r.tasks_preparetx.write(|w| unsafe { w.bits(1) }); | ||
| 569 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 570 | Ok(()) | ||
| 571 | } | ||
| 572 | |||
| 573 | fn setup_respond(&mut self, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { | ||
| 574 | match self.setup_respond_from_ram(wr_buffer, inten) { | ||
| 575 | Ok(_) => Ok(()), | ||
| 576 | Err(Error::BufferNotInRAM) => { | ||
| 577 | trace!("Copying TWIS tx buffer into RAM for DMA"); | ||
| 578 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | ||
| 579 | tx_ram_buf.copy_from_slice(wr_buffer); | ||
| 580 | self.setup_respond_from_ram(&tx_ram_buf, inten) | ||
| 581 | } | ||
| 582 | Err(error) => Err(error), | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> { | ||
| 587 | let r = T::regs(); | ||
| 588 | compiler_fence(SeqCst); | ||
| 589 | |||
| 590 | // Set up the DMA read. | ||
| 591 | unsafe { self.set_rx_buffer(buffer)? }; | ||
| 592 | |||
| 593 | // Clear events | ||
| 594 | r.events_read.reset(); | ||
| 595 | r.events_write.reset(); | ||
| 596 | r.events_stopped.reset(); | ||
| 597 | r.events_error.reset(); | ||
| 598 | self.clear_errorsrc(); | ||
| 599 | |||
| 600 | if inten { | ||
| 601 | r.intenset | ||
| 602 | .write(|w| w.stopped().set().error().set().read().set().write().set()); | ||
| 603 | } else { | ||
| 604 | r.intenclr | ||
| 605 | .write(|w| w.stopped().clear().error().clear().read().clear().write().clear()); | ||
| 606 | } | ||
| 607 | |||
| 608 | // Start read operation. | ||
| 609 | r.tasks_preparerx.write(|w| unsafe { w.bits(1) }); | ||
| 610 | |||
| 611 | Ok(()) | ||
| 612 | } | ||
| 613 | |||
| 614 | fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> { | ||
| 615 | let r = T::regs(); | ||
| 616 | compiler_fence(SeqCst); | ||
| 617 | |||
| 618 | // Clear events | ||
| 619 | r.events_read.reset(); | ||
| 620 | r.events_write.reset(); | ||
| 621 | r.events_stopped.reset(); | ||
| 622 | r.events_error.reset(); | ||
| 623 | self.clear_errorsrc(); | ||
| 624 | |||
| 625 | if inten { | ||
| 626 | r.intenset.write(|w| w.stopped().set().error().set().read().set()); | ||
| 627 | } else { | ||
| 628 | r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear()); | ||
| 629 | } | ||
| 630 | |||
| 631 | Ok(()) | ||
| 632 | } | ||
| 633 | |||
| 634 | /// Wait for commands from an I2C master. | ||
| 635 | /// `buffer` is provided in case master does a 'write' and is unused for 'read'. | ||
| 636 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 637 | /// and at most 65535 bytes on the nRF52840. | ||
| 638 | /// To know which one of the addresses were matched, call `address_match` or `address_match_index` | ||
| 639 | pub fn blocking_listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { | ||
| 640 | self.setup_listen(buffer, false)?; | ||
| 641 | let status = self.blocking_listen_wait()?; | ||
| 642 | if status == Status::Write { | ||
| 643 | self.setup_listen_end(false)?; | ||
| 644 | let command = self.blocking_listen_wait_end(status)?; | ||
| 645 | return Ok(command); | ||
| 646 | } | ||
| 647 | Ok(Command::Read) | ||
| 648 | } | ||
| 649 | |||
| 650 | /// Respond to an I2C master READ command. | ||
| 651 | /// Returns the number of bytes written. | ||
| 652 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 653 | /// and at most 65535 bytes on the nRF52840. | ||
| 654 | pub fn blocking_respond_to_read(&mut self, buffer: &[u8]) -> Result<usize, Error> { | ||
| 655 | self.setup_respond(buffer, false)?; | ||
| 656 | self.blocking_wait() | ||
| 657 | } | ||
| 658 | |||
| 659 | /// Same as [`blocking_respond_to_read`](Twis::blocking_respond_to_read) but will fail instead of copying data into RAM. | ||
| 660 | /// Consult the module level documentation to learn more. | ||
| 661 | pub fn blocking_respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result<usize, Error> { | ||
| 662 | self.setup_respond_from_ram(buffer, false)?; | ||
| 663 | self.blocking_wait() | ||
| 664 | } | ||
| 665 | |||
| 666 | // =========================================== | ||
| 667 | |||
| 668 | /// Wait for commands from an I2C master, with timeout. | ||
| 669 | /// `buffer` is provided in case master does a 'write' and is unused for 'read'. | ||
| 670 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 671 | /// and at most 65535 bytes on the nRF52840. | ||
| 672 | /// To know which one of the addresses were matched, call `address_match` or `address_match_index` | ||
| 673 | #[cfg(feature = "time")] | ||
| 674 | pub fn blocking_listen_timeout(&mut self, buffer: &mut [u8], timeout: Duration) -> Result<Command, Error> { | ||
| 675 | self.setup_listen(buffer, false)?; | ||
| 676 | let status = self.blocking_listen_wait_timeout(timeout)?; | ||
| 677 | if status == Status::Write { | ||
| 678 | self.setup_listen_end(false)?; | ||
| 679 | let command = self.blocking_listen_wait_end_timeout(status, timeout)?; | ||
| 680 | return Ok(command); | ||
| 681 | } | ||
| 682 | Ok(Command::Read) | ||
| 683 | } | ||
| 684 | |||
| 685 | /// Respond to an I2C master READ command with timeout. | ||
| 686 | /// Returns the number of bytes written. | ||
| 687 | /// See [`blocking_respond_to_read`]. | ||
| 688 | #[cfg(feature = "time")] | ||
| 689 | pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<usize, Error> { | ||
| 690 | self.setup_respond(buffer, false)?; | ||
| 691 | self.blocking_wait_timeout(timeout) | ||
| 692 | } | ||
| 693 | |||
| 694 | /// Same as [`blocking_respond_to_read_timeout`](Twis::blocking_respond_to_read_timeout) but will fail instead of copying data into RAM. | ||
| 695 | /// Consult the module level documentation to learn more. | ||
| 696 | #[cfg(feature = "time")] | ||
| 697 | pub fn blocking_respond_to_read_from_ram_timeout( | ||
| 698 | &mut self, | ||
| 699 | buffer: &[u8], | ||
| 700 | timeout: Duration, | ||
| 701 | ) -> Result<usize, Error> { | ||
| 702 | self.setup_respond_from_ram(buffer, false)?; | ||
| 703 | self.blocking_wait_timeout(timeout) | ||
| 704 | } | ||
| 705 | |||
| 706 | // =========================================== | ||
| 707 | |||
| 708 | /// Wait asynchronously for commands from an I2C master. | ||
| 709 | /// `buffer` is provided in case master does a 'write' and is unused for 'read'. | ||
| 710 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 711 | /// and at most 65535 bytes on the nRF52840. | ||
| 712 | /// To know which one of the addresses were matched, call `address_match` or `address_match_index` | ||
| 713 | pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { | ||
| 714 | self.setup_listen(buffer, true)?; | ||
| 715 | let status = self.async_listen_wait().await?; | ||
| 716 | if status == Status::Write { | ||
| 717 | self.setup_listen_end(true)?; | ||
| 718 | let command = self.async_listen_wait_end(status).await?; | ||
| 719 | return Ok(command); | ||
| 720 | } | ||
| 721 | Ok(Command::Read) | ||
| 722 | } | ||
| 723 | |||
| 724 | /// Respond to an I2C master READ command, asynchronously. | ||
| 725 | /// Returns the number of bytes written. | ||
| 726 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 727 | /// and at most 65535 bytes on the nRF52840. | ||
| 728 | pub async fn respond_to_read(&mut self, buffer: &[u8]) -> Result<usize, Error> { | ||
| 729 | self.setup_respond(buffer, true)?; | ||
| 730 | self.async_wait().await | ||
| 731 | } | ||
| 732 | |||
| 733 | /// Same as [`respond_to_read`](Twis::respond_to_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 734 | pub async fn respond_to_read_from_ram(&mut self, buffer: &[u8]) -> Result<usize, Error> { | ||
| 735 | self.setup_respond_from_ram(buffer, true)?; | ||
| 736 | self.async_wait().await | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 740 | impl<'a, T: Instance> Drop for Twis<'a, T> { | ||
| 741 | fn drop(&mut self) { | ||
| 742 | trace!("twis drop"); | ||
| 743 | |||
| 744 | // TODO: check for abort | ||
| 745 | |||
| 746 | // disable! | ||
| 747 | let r = T::regs(); | ||
| 748 | r.enable.write(|w| w.enable().disabled()); | ||
| 749 | |||
| 750 | gpio::deconfigure_pin(r.psel.sda.read().bits()); | ||
| 751 | gpio::deconfigure_pin(r.psel.scl.read().bits()); | ||
| 752 | |||
| 753 | trace!("twis drop: done"); | ||
| 754 | } | ||
| 755 | } | ||
| 756 | |||
| 757 | pub(crate) mod sealed { | ||
| 758 | use super::*; | ||
| 759 | |||
| 760 | pub struct State { | ||
| 761 | pub waker: AtomicWaker, | ||
| 762 | } | ||
| 763 | |||
| 764 | impl State { | ||
| 765 | pub const fn new() -> Self { | ||
| 766 | Self { | ||
| 767 | waker: AtomicWaker::new(), | ||
| 768 | } | ||
| 769 | } | ||
| 770 | } | ||
| 771 | |||
| 772 | pub trait Instance { | ||
| 773 | fn regs() -> &'static pac::twis0::RegisterBlock; | ||
| 774 | fn state() -> &'static State; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 | /// TWIS peripheral instance. | ||
| 779 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | ||
| 780 | /// Interrupt for this peripheral. | ||
| 781 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 782 | } | ||
| 783 | |||
| 784 | macro_rules! impl_twis { | ||
| 785 | ($type:ident, $pac_type:ident, $irq:ident) => { | ||
| 786 | impl crate::twis::sealed::Instance for peripherals::$type { | ||
| 787 | fn regs() -> &'static pac::twis0::RegisterBlock { | ||
| 788 | unsafe { &*pac::$pac_type::ptr() } | ||
| 789 | } | ||
| 790 | fn state() -> &'static crate::twis::sealed::State { | ||
| 791 | static STATE: crate::twis::sealed::State = crate::twis::sealed::State::new(); | ||
| 792 | &STATE | ||
| 793 | } | ||
| 794 | } | ||
| 795 | impl crate::twis::Instance for peripherals::$type { | ||
| 796 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 797 | } | ||
| 798 | }; | ||
| 799 | } | ||
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 4347ea558..48d57fea4 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | //! Universal Asynchronous Receiver Transmitter (UART) driver. |
| 2 | |||
| 3 | //! Async UART | ||
| 4 | //! | 2 | //! |
| 5 | //! Async UART is provided in two flavors - this one and also [crate::buffered_uarte::BufferedUarte]. | 3 | //! The UART driver is provided in two flavors - this one and also [crate::buffered_uarte::BufferedUarte]. |
| 6 | //! The [Uarte] here is useful for those use-cases where reading the UARTE peripheral is | 4 | //! The [Uarte] here is useful for those use-cases where reading the UARTE peripheral is |
| 7 | //! exclusively awaited on. If the [Uarte] is required to be awaited on with some other future, | 5 | //! exclusively awaited on. If the [Uarte] is required to be awaited on with some other future, |
| 8 | //! for example when using `futures_util::future::select`, then you should consider | 6 | //! for example when using `futures_util::future::select`, then you should consider |
| @@ -13,12 +11,15 @@ | |||
| 13 | //! memory may be used given that buffers are passed in directly to its read and write | 11 | //! memory may be used given that buffers are passed in directly to its read and write |
| 14 | //! methods. | 12 | //! methods. |
| 15 | 13 | ||
| 14 | #![macro_use] | ||
| 15 | |||
| 16 | use core::future::poll_fn; | ||
| 17 | use core::marker::PhantomData; | ||
| 16 | use core::sync::atomic::{compiler_fence, Ordering}; | 18 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 17 | use core::task::Poll; | 19 | use core::task::Poll; |
| 18 | 20 | ||
| 19 | use embassy_hal_common::drop::OnDrop; | 21 | use embassy_hal_common::drop::OnDrop; |
| 20 | use embassy_hal_common::{into_ref, PeripheralRef}; | 22 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 21 | use futures::future::poll_fn; | ||
| 22 | use pac::uarte0::RegisterBlock; | 23 | use pac::uarte0::RegisterBlock; |
| 23 | // Re-export SVD variants to allow user to directly set values. | 24 | // Re-export SVD variants to allow user to directly set values. |
| 24 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 25 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| @@ -26,16 +27,19 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari | |||
| 26 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 27 | use crate::gpio::sealed::Pin as _; | 28 | use crate::gpio::sealed::Pin as _; |
| 28 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; |
| 29 | use crate::interrupt::{Interrupt, InterruptExt}; | 30 | use crate::interrupt::typelevel::Interrupt; |
| 30 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 31 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| 32 | use crate::util::slice_in_ram_or; | 33 | use crate::util::slice_in_ram_or; |
| 33 | use crate::{pac, Peripheral}; | 34 | use crate::{interrupt, pac, Peripheral}; |
| 34 | 35 | ||
| 36 | /// UARTE config. | ||
| 35 | #[derive(Clone)] | 37 | #[derive(Clone)] |
| 36 | #[non_exhaustive] | 38 | #[non_exhaustive] |
| 37 | pub struct Config { | 39 | pub struct Config { |
| 40 | /// Parity bit. | ||
| 38 | pub parity: Parity, | 41 | pub parity: Parity, |
| 42 | /// Baud rate. | ||
| 39 | pub baudrate: Baudrate, | 43 | pub baudrate: Baudrate, |
| 40 | } | 44 | } |
| 41 | 45 | ||
| @@ -48,32 +52,54 @@ impl Default for Config { | |||
| 48 | } | 52 | } |
| 49 | } | 53 | } |
| 50 | 54 | ||
| 55 | /// UART error. | ||
| 51 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 56 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 52 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 57 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 53 | #[non_exhaustive] | 58 | #[non_exhaustive] |
| 54 | pub enum Error { | 59 | pub enum Error { |
| 60 | /// Buffer was too long. | ||
| 55 | BufferTooLong, | 61 | BufferTooLong, |
| 56 | BufferZeroLength, | 62 | /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. |
| 57 | DMABufferNotInDataMemory, | 63 | BufferNotInRAM, |
| 58 | // TODO: add other error variants. | ||
| 59 | } | 64 | } |
| 60 | 65 | ||
| 61 | /// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload. | 66 | /// Interrupt handler. |
| 62 | /// | 67 | pub struct InterruptHandler<T: Instance> { |
| 63 | /// For more details about EasyDMA, consult the module documentation. | 68 | _phantom: PhantomData<T>, |
| 69 | } | ||
| 70 | |||
| 71 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 72 | unsafe fn on_interrupt() { | ||
| 73 | let r = T::regs(); | ||
| 74 | let s = T::state(); | ||
| 75 | |||
| 76 | if r.events_endrx.read().bits() != 0 { | ||
| 77 | s.endrx_waker.wake(); | ||
| 78 | r.intenclr.write(|w| w.endrx().clear()); | ||
| 79 | } | ||
| 80 | if r.events_endtx.read().bits() != 0 { | ||
| 81 | s.endtx_waker.wake(); | ||
| 82 | r.intenclr.write(|w| w.endtx().clear()); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | /// UARTE driver. | ||
| 64 | pub struct Uarte<'d, T: Instance> { | 88 | pub struct Uarte<'d, T: Instance> { |
| 65 | tx: UarteTx<'d, T>, | 89 | tx: UarteTx<'d, T>, |
| 66 | rx: UarteRx<'d, T>, | 90 | rx: UarteRx<'d, T>, |
| 67 | } | 91 | } |
| 68 | 92 | ||
| 69 | /// Transmitter interface to the UARTE peripheral obtained | 93 | /// Transmitter part of the UARTE driver. |
| 70 | /// via [Uarte]::split. | 94 | /// |
| 95 | /// This can be obtained via [`Uarte::split`], or created directly. | ||
| 71 | pub struct UarteTx<'d, T: Instance> { | 96 | pub struct UarteTx<'d, T: Instance> { |
| 72 | _p: PeripheralRef<'d, T>, | 97 | _p: PeripheralRef<'d, T>, |
| 73 | } | 98 | } |
| 74 | 99 | ||
| 75 | /// Receiver interface to the UARTE peripheral obtained | 100 | /// Receiver part of the UARTE driver. |
| 76 | /// via [Uarte]::split. | 101 | /// |
| 102 | /// This can be obtained via [`Uarte::split`], or created directly. | ||
| 77 | pub struct UarteRx<'d, T: Instance> { | 103 | pub struct UarteRx<'d, T: Instance> { |
| 78 | _p: PeripheralRef<'d, T>, | 104 | _p: PeripheralRef<'d, T>, |
| 79 | } | 105 | } |
| @@ -82,19 +108,19 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 82 | /// Create a new UARTE without hardware flow control | 108 | /// Create a new UARTE without hardware flow control |
| 83 | pub fn new( | 109 | pub fn new( |
| 84 | uarte: impl Peripheral<P = T> + 'd, | 110 | uarte: impl Peripheral<P = T> + 'd, |
| 85 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 111 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 86 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 112 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 87 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 113 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 88 | config: Config, | 114 | config: Config, |
| 89 | ) -> Self { | 115 | ) -> Self { |
| 90 | into_ref!(rxd, txd); | 116 | into_ref!(rxd, txd); |
| 91 | Self::new_inner(uarte, irq, rxd.map_into(), txd.map_into(), None, None, config) | 117 | Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config) |
| 92 | } | 118 | } |
| 93 | 119 | ||
| 94 | /// Create a new UARTE with hardware flow control (RTS/CTS) | 120 | /// Create a new UARTE with hardware flow control (RTS/CTS) |
| 95 | pub fn new_with_rtscts( | 121 | pub fn new_with_rtscts( |
| 96 | uarte: impl Peripheral<P = T> + 'd, | 122 | uarte: impl Peripheral<P = T> + 'd, |
| 97 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 123 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 98 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 124 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 99 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 125 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 100 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 126 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -104,7 +130,6 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 104 | into_ref!(rxd, txd, cts, rts); | 130 | into_ref!(rxd, txd, cts, rts); |
| 105 | Self::new_inner( | 131 | Self::new_inner( |
| 106 | uarte, | 132 | uarte, |
| 107 | irq, | ||
| 108 | rxd.map_into(), | 133 | rxd.map_into(), |
| 109 | txd.map_into(), | 134 | txd.map_into(), |
| 110 | Some(cts.map_into()), | 135 | Some(cts.map_into()), |
| @@ -115,14 +140,13 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 115 | 140 | ||
| 116 | fn new_inner( | 141 | fn new_inner( |
| 117 | uarte: impl Peripheral<P = T> + 'd, | 142 | uarte: impl Peripheral<P = T> + 'd, |
| 118 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 119 | rxd: PeripheralRef<'d, AnyPin>, | 143 | rxd: PeripheralRef<'d, AnyPin>, |
| 120 | txd: PeripheralRef<'d, AnyPin>, | 144 | txd: PeripheralRef<'d, AnyPin>, |
| 121 | cts: Option<PeripheralRef<'d, AnyPin>>, | 145 | cts: Option<PeripheralRef<'d, AnyPin>>, |
| 122 | rts: Option<PeripheralRef<'d, AnyPin>>, | 146 | rts: Option<PeripheralRef<'d, AnyPin>>, |
| 123 | config: Config, | 147 | config: Config, |
| 124 | ) -> Self { | 148 | ) -> Self { |
| 125 | into_ref!(uarte, irq); | 149 | into_ref!(uarte); |
| 126 | 150 | ||
| 127 | let r = T::regs(); | 151 | let r = T::regs(); |
| 128 | 152 | ||
| @@ -144,9 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 144 | } | 168 | } |
| 145 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | 169 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); |
| 146 | 170 | ||
| 147 | irq.set_handler(Self::on_interrupt); | 171 | T::Interrupt::unpend(); |
| 148 | irq.unpend(); | 172 | unsafe { T::Interrupt::enable() }; |
| 149 | irq.enable(); | ||
| 150 | 173 | ||
| 151 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { | 174 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { |
| 152 | (false, false) => false, | 175 | (false, false) => false, |
| @@ -166,37 +189,37 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 166 | } | 189 | } |
| 167 | } | 190 | } |
| 168 | 191 | ||
| 169 | /// Split the Uarte into a transmitter and receiver, which is | 192 | /// Split the Uarte into the transmitter and receiver parts. |
| 170 | /// particuarly useful when having two tasks correlating to | 193 | /// |
| 171 | /// transmitting and receiving. | 194 | /// This is useful to concurrently transmit and receive from independent tasks. |
| 172 | pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { | 195 | pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { |
| 173 | (self.tx, self.rx) | 196 | (self.tx, self.rx) |
| 174 | } | 197 | } |
| 175 | 198 | ||
| 199 | /// Split the Uarte into the transmitter and receiver with idle support parts. | ||
| 200 | /// | ||
| 201 | /// This is useful to concurrently transmit and receive from independent tasks. | ||
| 202 | pub fn split_with_idle<U: TimerInstance>( | ||
| 203 | self, | ||
| 204 | timer: impl Peripheral<P = U> + 'd, | ||
| 205 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 206 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 207 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { | ||
| 208 | (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) | ||
| 209 | } | ||
| 210 | |||
| 176 | /// Return the endtx event for use with PPI | 211 | /// Return the endtx event for use with PPI |
| 177 | pub fn event_endtx(&self) -> Event { | 212 | pub fn event_endtx(&self) -> Event { |
| 178 | let r = T::regs(); | 213 | let r = T::regs(); |
| 179 | Event::from_reg(&r.events_endtx) | 214 | Event::from_reg(&r.events_endtx) |
| 180 | } | 215 | } |
| 181 | 216 | ||
| 182 | fn on_interrupt(_: *mut ()) { | 217 | /// Read bytes until the buffer is filled. |
| 183 | let r = T::regs(); | ||
| 184 | let s = T::state(); | ||
| 185 | |||
| 186 | if r.events_endrx.read().bits() != 0 { | ||
| 187 | s.endrx_waker.wake(); | ||
| 188 | r.intenclr.write(|w| w.endrx().clear()); | ||
| 189 | } | ||
| 190 | if r.events_endtx.read().bits() != 0 { | ||
| 191 | s.endtx_waker.wake(); | ||
| 192 | r.intenclr.write(|w| w.endtx().clear()); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 218 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 197 | self.rx.read(buffer).await | 219 | self.rx.read(buffer).await |
| 198 | } | 220 | } |
| 199 | 221 | ||
| 222 | /// Write all bytes in the buffer. | ||
| 200 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 223 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 201 | self.tx.write(buffer).await | 224 | self.tx.write(buffer).await |
| 202 | } | 225 | } |
| @@ -206,10 +229,12 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 206 | self.tx.write_from_ram(buffer).await | 229 | self.tx.write_from_ram(buffer).await |
| 207 | } | 230 | } |
| 208 | 231 | ||
| 232 | /// Read bytes until the buffer is filled. | ||
| 209 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 233 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 210 | self.rx.blocking_read(buffer) | 234 | self.rx.blocking_read(buffer) |
| 211 | } | 235 | } |
| 212 | 236 | ||
| 237 | /// Write all bytes in the buffer. | ||
| 213 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 238 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 214 | self.tx.blocking_write(buffer) | 239 | self.tx.blocking_write(buffer) |
| 215 | } | 240 | } |
| @@ -245,34 +270,33 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 245 | /// Create a new tx-only UARTE without hardware flow control | 270 | /// Create a new tx-only UARTE without hardware flow control |
| 246 | pub fn new( | 271 | pub fn new( |
| 247 | uarte: impl Peripheral<P = T> + 'd, | 272 | uarte: impl Peripheral<P = T> + 'd, |
| 248 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 273 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 249 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 274 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 250 | config: Config, | 275 | config: Config, |
| 251 | ) -> Self { | 276 | ) -> Self { |
| 252 | into_ref!(txd); | 277 | into_ref!(txd); |
| 253 | Self::new_inner(uarte, irq, txd.map_into(), None, config) | 278 | Self::new_inner(uarte, txd.map_into(), None, config) |
| 254 | } | 279 | } |
| 255 | 280 | ||
| 256 | /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) | 281 | /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) |
| 257 | pub fn new_with_rtscts( | 282 | pub fn new_with_rtscts( |
| 258 | uarte: impl Peripheral<P = T> + 'd, | 283 | uarte: impl Peripheral<P = T> + 'd, |
| 259 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 284 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 260 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 285 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| 261 | cts: impl Peripheral<P = impl GpioPin> + 'd, | 286 | cts: impl Peripheral<P = impl GpioPin> + 'd, |
| 262 | config: Config, | 287 | config: Config, |
| 263 | ) -> Self { | 288 | ) -> Self { |
| 264 | into_ref!(txd, cts); | 289 | into_ref!(txd, cts); |
| 265 | Self::new_inner(uarte, irq, txd.map_into(), Some(cts.map_into()), config) | 290 | Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config) |
| 266 | } | 291 | } |
| 267 | 292 | ||
| 268 | fn new_inner( | 293 | fn new_inner( |
| 269 | uarte: impl Peripheral<P = T> + 'd, | 294 | uarte: impl Peripheral<P = T> + 'd, |
| 270 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 271 | txd: PeripheralRef<'d, AnyPin>, | 295 | txd: PeripheralRef<'d, AnyPin>, |
| 272 | cts: Option<PeripheralRef<'d, AnyPin>>, | 296 | cts: Option<PeripheralRef<'d, AnyPin>>, |
| 273 | config: Config, | 297 | config: Config, |
| 274 | ) -> Self { | 298 | ) -> Self { |
| 275 | into_ref!(uarte, irq); | 299 | into_ref!(uarte); |
| 276 | 300 | ||
| 277 | let r = T::regs(); | 301 | let r = T::regs(); |
| 278 | 302 | ||
| @@ -291,9 +315,8 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 291 | let hardware_flow_control = cts.is_some(); | 315 | let hardware_flow_control = cts.is_some(); |
| 292 | configure(r, config, hardware_flow_control); | 316 | configure(r, config, hardware_flow_control); |
| 293 | 317 | ||
| 294 | irq.set_handler(Uarte::<T>::on_interrupt); | 318 | T::Interrupt::unpend(); |
| 295 | irq.unpend(); | 319 | unsafe { T::Interrupt::enable() }; |
| 296 | irq.enable(); | ||
| 297 | 320 | ||
| 298 | let s = T::state(); | 321 | let s = T::state(); |
| 299 | s.tx_rx_refcount.store(1, Ordering::Relaxed); | 322 | s.tx_rx_refcount.store(1, Ordering::Relaxed); |
| @@ -301,10 +324,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 301 | Self { _p: uarte } | 324 | Self { _p: uarte } |
| 302 | } | 325 | } |
| 303 | 326 | ||
| 327 | /// Write all bytes in the buffer. | ||
| 304 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 328 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 305 | match self.write_from_ram(buffer).await { | 329 | match self.write_from_ram(buffer).await { |
| 306 | Ok(_) => Ok(()), | 330 | Ok(_) => Ok(()), |
| 307 | Err(Error::DMABufferNotInDataMemory) => { | 331 | Err(Error::BufferNotInRAM) => { |
| 308 | trace!("Copying UARTE tx buffer into RAM for DMA"); | 332 | trace!("Copying UARTE tx buffer into RAM for DMA"); |
| 309 | let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; | 333 | let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; |
| 310 | ram_buf.copy_from_slice(buffer); | 334 | ram_buf.copy_from_slice(buffer); |
| @@ -314,11 +338,13 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 314 | } | 338 | } |
| 315 | } | 339 | } |
| 316 | 340 | ||
| 341 | /// Same as [`write`](Self::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 317 | pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { | 342 | pub async fn write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 318 | slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; | ||
| 319 | if buffer.len() == 0 { | 343 | if buffer.len() == 0 { |
| 320 | return Err(Error::BufferZeroLength); | 344 | return Ok(()); |
| 321 | } | 345 | } |
| 346 | |||
| 347 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||
| 322 | if buffer.len() > EASY_DMA_SIZE { | 348 | if buffer.len() > EASY_DMA_SIZE { |
| 323 | return Err(Error::BufferTooLong); | 349 | return Err(Error::BufferTooLong); |
| 324 | } | 350 | } |
| @@ -368,10 +394,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 368 | Ok(()) | 394 | Ok(()) |
| 369 | } | 395 | } |
| 370 | 396 | ||
| 397 | /// Write all bytes in the buffer. | ||
| 371 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 398 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 372 | match self.blocking_write_from_ram(buffer) { | 399 | match self.blocking_write_from_ram(buffer) { |
| 373 | Ok(_) => Ok(()), | 400 | Ok(_) => Ok(()), |
| 374 | Err(Error::DMABufferNotInDataMemory) => { | 401 | Err(Error::BufferNotInRAM) => { |
| 375 | trace!("Copying UARTE tx buffer into RAM for DMA"); | 402 | trace!("Copying UARTE tx buffer into RAM for DMA"); |
| 376 | let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; | 403 | let ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..buffer.len()]; |
| 377 | ram_buf.copy_from_slice(buffer); | 404 | ram_buf.copy_from_slice(buffer); |
| @@ -381,11 +408,13 @@ impl<'d, T: Instance> UarteTx<'d, T> { | |||
| 381 | } | 408 | } |
| 382 | } | 409 | } |
| 383 | 410 | ||
| 411 | /// Same as [`write_from_ram`](Self::write_from_ram) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 384 | pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { | 412 | pub fn blocking_write_from_ram(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 385 | slice_in_ram_or(buffer, Error::DMABufferNotInDataMemory)?; | ||
| 386 | if buffer.len() == 0 { | 413 | if buffer.len() == 0 { |
| 387 | return Err(Error::BufferZeroLength); | 414 | return Ok(()); |
| 388 | } | 415 | } |
| 416 | |||
| 417 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | ||
| 389 | if buffer.len() > EASY_DMA_SIZE { | 418 | if buffer.len() > EASY_DMA_SIZE { |
| 390 | return Err(Error::BufferTooLong); | 419 | return Err(Error::BufferTooLong); |
| 391 | } | 420 | } |
| @@ -437,34 +466,33 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 437 | /// Create a new rx-only UARTE without hardware flow control | 466 | /// Create a new rx-only UARTE without hardware flow control |
| 438 | pub fn new( | 467 | pub fn new( |
| 439 | uarte: impl Peripheral<P = T> + 'd, | 468 | uarte: impl Peripheral<P = T> + 'd, |
| 440 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 469 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 441 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 470 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 442 | config: Config, | 471 | config: Config, |
| 443 | ) -> Self { | 472 | ) -> Self { |
| 444 | into_ref!(rxd); | 473 | into_ref!(rxd); |
| 445 | Self::new_inner(uarte, irq, rxd.map_into(), None, config) | 474 | Self::new_inner(uarte, rxd.map_into(), None, config) |
| 446 | } | 475 | } |
| 447 | 476 | ||
| 448 | /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) | 477 | /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) |
| 449 | pub fn new_with_rtscts( | 478 | pub fn new_with_rtscts( |
| 450 | uarte: impl Peripheral<P = T> + 'd, | 479 | uarte: impl Peripheral<P = T> + 'd, |
| 451 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 480 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 452 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 481 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 453 | rts: impl Peripheral<P = impl GpioPin> + 'd, | 482 | rts: impl Peripheral<P = impl GpioPin> + 'd, |
| 454 | config: Config, | 483 | config: Config, |
| 455 | ) -> Self { | 484 | ) -> Self { |
| 456 | into_ref!(rxd, rts); | 485 | into_ref!(rxd, rts); |
| 457 | Self::new_inner(uarte, irq, rxd.map_into(), Some(rts.map_into()), config) | 486 | Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) |
| 458 | } | 487 | } |
| 459 | 488 | ||
| 460 | fn new_inner( | 489 | fn new_inner( |
| 461 | uarte: impl Peripheral<P = T> + 'd, | 490 | uarte: impl Peripheral<P = T> + 'd, |
| 462 | irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 463 | rxd: PeripheralRef<'d, AnyPin>, | 491 | rxd: PeripheralRef<'d, AnyPin>, |
| 464 | rts: Option<PeripheralRef<'d, AnyPin>>, | 492 | rts: Option<PeripheralRef<'d, AnyPin>>, |
| 465 | config: Config, | 493 | config: Config, |
| 466 | ) -> Self { | 494 | ) -> Self { |
| 467 | into_ref!(uarte, irq); | 495 | into_ref!(uarte); |
| 468 | 496 | ||
| 469 | let r = T::regs(); | 497 | let r = T::regs(); |
| 470 | 498 | ||
| @@ -480,9 +508,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 480 | r.psel.txd.write(|w| w.connect().disconnected()); | 508 | r.psel.txd.write(|w| w.connect().disconnected()); |
| 481 | r.psel.cts.write(|w| w.connect().disconnected()); | 509 | r.psel.cts.write(|w| w.connect().disconnected()); |
| 482 | 510 | ||
| 483 | irq.set_handler(Uarte::<T>::on_interrupt); | 511 | T::Interrupt::unpend(); |
| 484 | irq.unpend(); | 512 | unsafe { T::Interrupt::enable() }; |
| 485 | irq.enable(); | ||
| 486 | 513 | ||
| 487 | let hardware_flow_control = rts.is_some(); | 514 | let hardware_flow_control = rts.is_some(); |
| 488 | configure(r, config, hardware_flow_control); | 515 | configure(r, config, hardware_flow_control); |
| @@ -493,9 +520,60 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 493 | Self { _p: uarte } | 520 | Self { _p: uarte } |
| 494 | } | 521 | } |
| 495 | 522 | ||
| 523 | /// Upgrade to an instance that supports idle line detection. | ||
| 524 | pub fn with_idle<U: TimerInstance>( | ||
| 525 | self, | ||
| 526 | timer: impl Peripheral<P = U> + 'd, | ||
| 527 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 528 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 529 | ) -> UarteRxWithIdle<'d, T, U> { | ||
| 530 | let timer = Timer::new(timer); | ||
| 531 | |||
| 532 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 533 | |||
| 534 | let r = T::regs(); | ||
| 535 | |||
| 536 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 537 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 538 | // | ||
| 539 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 540 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 541 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 542 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 543 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 544 | |||
| 545 | timer.set_frequency(Frequency::F16MHz); | ||
| 546 | timer.cc(0).write(timeout); | ||
| 547 | timer.cc(0).short_compare_clear(); | ||
| 548 | timer.cc(0).short_compare_stop(); | ||
| 549 | |||
| 550 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 551 | ppi_ch1.map_into(), | ||
| 552 | Event::from_reg(&r.events_rxdrdy), | ||
| 553 | timer.task_clear(), | ||
| 554 | timer.task_start(), | ||
| 555 | ); | ||
| 556 | ppi_ch1.enable(); | ||
| 557 | |||
| 558 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 559 | ppi_ch2.map_into(), | ||
| 560 | timer.cc(0).event_compare(), | ||
| 561 | Task::from_reg(&r.tasks_stoprx), | ||
| 562 | ); | ||
| 563 | ppi_ch2.enable(); | ||
| 564 | |||
| 565 | UarteRxWithIdle { | ||
| 566 | rx: self, | ||
| 567 | timer, | ||
| 568 | ppi_ch1: ppi_ch1, | ||
| 569 | _ppi_ch2: ppi_ch2, | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /// Read bytes until the buffer is filled. | ||
| 496 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 574 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 497 | if buffer.len() == 0 { | 575 | if buffer.len() == 0 { |
| 498 | return Err(Error::BufferZeroLength); | 576 | return Ok(()); |
| 499 | } | 577 | } |
| 500 | if buffer.len() > EASY_DMA_SIZE { | 578 | if buffer.len() > EASY_DMA_SIZE { |
| 501 | return Err(Error::BufferTooLong); | 579 | return Err(Error::BufferTooLong); |
| @@ -546,9 +624,10 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 546 | Ok(()) | 624 | Ok(()) |
| 547 | } | 625 | } |
| 548 | 626 | ||
| 627 | /// Read bytes until the buffer is filled. | ||
| 549 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 628 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 550 | if buffer.len() == 0 { | 629 | if buffer.len() == 0 { |
| 551 | return Err(Error::BufferZeroLength); | 630 | return Ok(()); |
| 552 | } | 631 | } |
| 553 | if buffer.len() > EASY_DMA_SIZE { | 632 | if buffer.len() > EASY_DMA_SIZE { |
| 554 | return Err(Error::BufferTooLong); | 633 | return Err(Error::BufferTooLong); |
| @@ -597,249 +676,35 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { | |||
| 597 | } | 676 | } |
| 598 | } | 677 | } |
| 599 | 678 | ||
| 600 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | 679 | /// Receiver part of the UARTE driver, with `read_until_idle` support. |
| 601 | pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | 680 | /// |
| 602 | // Do nothing | 681 | /// This can be obtained via [`Uarte::split_with_idle`]. |
| 603 | } | 682 | pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> { |
| 604 | 683 | rx: UarteRx<'d, T>, | |
| 605 | #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] | 684 | timer: Timer<'d, U>, |
| 606 | pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||
| 607 | use core::ops::Deref; | ||
| 608 | |||
| 609 | // Apply workaround for anomalies: | ||
| 610 | // - nRF9160 - anomaly 23 | ||
| 611 | // - nRF5340 - anomaly 44 | ||
| 612 | let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; | ||
| 613 | let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; | ||
| 614 | |||
| 615 | // NB Safety: This is taken from Nordic's driver - | ||
| 616 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 617 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 618 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 619 | } | ||
| 620 | |||
| 621 | // NB Safety: This is taken from Nordic's driver - | ||
| 622 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 623 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 624 | r.enable.write(|w| w.enable().enabled()); | ||
| 625 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 626 | |||
| 627 | let mut workaround_succeded = false; | ||
| 628 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 629 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 630 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 631 | for _ in 0..40000 { | ||
| 632 | // NB Safety: This is taken from Nordic's driver - | ||
| 633 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 634 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 635 | workaround_succeded = true; | ||
| 636 | break; | ||
| 637 | } else { | ||
| 638 | // Need to sleep for 1us here | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | if !workaround_succeded { | ||
| 643 | panic!("Failed to apply workaround for UART"); | ||
| 644 | } | ||
| 645 | |||
| 646 | let errors = r.errorsrc.read().bits(); | ||
| 647 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 648 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 649 | r.enable.write(|w| w.enable().disabled()); | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | ||
| 654 | if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||
| 655 | // Finally we can disable, and we do so for the peripheral | ||
| 656 | // i.e. not just rx concerns. | ||
| 657 | r.enable.write(|w| w.enable().disabled()); | ||
| 658 | |||
| 659 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 660 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 661 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 662 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 663 | |||
| 664 | trace!("uarte tx and rx drop: done"); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, | ||
| 669 | /// allowing it to implement the ReadUntilIdle trait. | ||
| 670 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { | ||
| 671 | tx: UarteTx<'d, U>, | ||
| 672 | rx: UarteRxWithIdle<'d, U, T>, | ||
| 673 | } | ||
| 674 | |||
| 675 | impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> { | ||
| 676 | /// Create a new UARTE without hardware flow control | ||
| 677 | pub fn new( | ||
| 678 | uarte: impl Peripheral<P = U> + 'd, | ||
| 679 | timer: impl Peripheral<P = T> + 'd, | ||
| 680 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 681 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 682 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 683 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 684 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 685 | config: Config, | ||
| 686 | ) -> Self { | ||
| 687 | into_ref!(rxd, txd); | ||
| 688 | Self::new_inner( | ||
| 689 | uarte, | ||
| 690 | timer, | ||
| 691 | ppi_ch1, | ||
| 692 | ppi_ch2, | ||
| 693 | irq, | ||
| 694 | rxd.map_into(), | ||
| 695 | txd.map_into(), | ||
| 696 | None, | ||
| 697 | None, | ||
| 698 | config, | ||
| 699 | ) | ||
| 700 | } | ||
| 701 | |||
| 702 | /// Create a new UARTE with hardware flow control (RTS/CTS) | ||
| 703 | pub fn new_with_rtscts( | ||
| 704 | uarte: impl Peripheral<P = U> + 'd, | ||
| 705 | timer: impl Peripheral<P = T> + 'd, | ||
| 706 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 707 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 708 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 709 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 710 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 711 | cts: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 712 | rts: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 713 | config: Config, | ||
| 714 | ) -> Self { | ||
| 715 | into_ref!(rxd, txd, cts, rts); | ||
| 716 | Self::new_inner( | ||
| 717 | uarte, | ||
| 718 | timer, | ||
| 719 | ppi_ch1, | ||
| 720 | ppi_ch2, | ||
| 721 | irq, | ||
| 722 | rxd.map_into(), | ||
| 723 | txd.map_into(), | ||
| 724 | Some(cts.map_into()), | ||
| 725 | Some(rts.map_into()), | ||
| 726 | config, | ||
| 727 | ) | ||
| 728 | } | ||
| 729 | |||
| 730 | fn new_inner( | ||
| 731 | uarte: impl Peripheral<P = U> + 'd, | ||
| 732 | timer: impl Peripheral<P = T> + 'd, | ||
| 733 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 734 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 735 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 736 | rxd: PeripheralRef<'d, AnyPin>, | ||
| 737 | txd: PeripheralRef<'d, AnyPin>, | ||
| 738 | cts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 739 | rts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 740 | config: Config, | ||
| 741 | ) -> Self { | ||
| 742 | let baudrate = config.baudrate; | ||
| 743 | let (tx, rx) = Uarte::new_inner(uarte, irq, rxd, txd, cts, rts, config).split(); | ||
| 744 | |||
| 745 | let mut timer = Timer::new(timer); | ||
| 746 | |||
| 747 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 748 | |||
| 749 | let r = U::regs(); | ||
| 750 | |||
| 751 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 752 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 753 | // | ||
| 754 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 755 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 756 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 757 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 758 | |||
| 759 | timer.set_frequency(Frequency::F16MHz); | ||
| 760 | timer.cc(0).write(timeout); | ||
| 761 | timer.cc(0).short_compare_clear(); | ||
| 762 | timer.cc(0).short_compare_stop(); | ||
| 763 | |||
| 764 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 765 | ppi_ch1.map_into(), | ||
| 766 | Event::from_reg(&r.events_rxdrdy), | ||
| 767 | timer.task_clear(), | ||
| 768 | timer.task_start(), | ||
| 769 | ); | ||
| 770 | ppi_ch1.enable(); | ||
| 771 | |||
| 772 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 773 | ppi_ch2.map_into(), | ||
| 774 | timer.cc(0).event_compare(), | ||
| 775 | Task::from_reg(&r.tasks_stoprx), | ||
| 776 | ); | ||
| 777 | ppi_ch2.enable(); | ||
| 778 | |||
| 779 | Self { | ||
| 780 | tx, | ||
| 781 | rx: UarteRxWithIdle { | ||
| 782 | rx, | ||
| 783 | timer, | ||
| 784 | ppi_ch1: ppi_ch1, | ||
| 785 | _ppi_ch2: ppi_ch2, | ||
| 786 | }, | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | /// Split the Uarte into a transmitter and receiver, which is | ||
| 791 | /// particuarly useful when having two tasks correlating to | ||
| 792 | /// transmitting and receiving. | ||
| 793 | pub fn split(self) -> (UarteTx<'d, U>, UarteRxWithIdle<'d, U, T>) { | ||
| 794 | (self.tx, self.rx) | ||
| 795 | } | ||
| 796 | |||
| 797 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 798 | self.rx.read(buffer).await | ||
| 799 | } | ||
| 800 | |||
| 801 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 802 | self.tx.write(buffer).await | ||
| 803 | } | ||
| 804 | |||
| 805 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 806 | self.rx.blocking_read(buffer) | ||
| 807 | } | ||
| 808 | |||
| 809 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | ||
| 810 | self.tx.blocking_write(buffer) | ||
| 811 | } | ||
| 812 | |||
| 813 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 814 | self.rx.read_until_idle(buffer).await | ||
| 815 | } | ||
| 816 | |||
| 817 | pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | ||
| 818 | self.rx.blocking_read_until_idle(buffer) | ||
| 819 | } | ||
| 820 | } | ||
| 821 | |||
| 822 | pub struct UarteRxWithIdle<'d, U: Instance, T: TimerInstance> { | ||
| 823 | rx: UarteRx<'d, U>, | ||
| 824 | timer: Timer<'d, T>, | ||
| 825 | ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, | 685 | ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, |
| 826 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, | 686 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, |
| 827 | } | 687 | } |
| 828 | 688 | ||
| 829 | impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | 689 | impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { |
| 690 | /// Read bytes until the buffer is filled. | ||
| 830 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 691 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 831 | self.ppi_ch1.disable(); | 692 | self.ppi_ch1.disable(); |
| 832 | self.rx.read(buffer).await | 693 | self.rx.read(buffer).await |
| 833 | } | 694 | } |
| 834 | 695 | ||
| 696 | /// Read bytes until the buffer is filled. | ||
| 835 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 697 | pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 836 | self.ppi_ch1.disable(); | 698 | self.ppi_ch1.disable(); |
| 837 | self.rx.blocking_read(buffer) | 699 | self.rx.blocking_read(buffer) |
| 838 | } | 700 | } |
| 839 | 701 | ||
| 702 | /// Read bytes until the buffer is filled, or the line becomes idle. | ||
| 703 | /// | ||
| 704 | /// Returns the amount of bytes read. | ||
| 840 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 705 | pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 841 | if buffer.len() == 0 { | 706 | if buffer.len() == 0 { |
| 842 | return Err(Error::BufferZeroLength); | 707 | return Ok(0); |
| 843 | } | 708 | } |
| 844 | if buffer.len() > EASY_DMA_SIZE { | 709 | if buffer.len() > EASY_DMA_SIZE { |
| 845 | return Err(Error::BufferTooLong); | 710 | return Err(Error::BufferTooLong); |
| @@ -848,8 +713,8 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 848 | let ptr = buffer.as_ptr(); | 713 | let ptr = buffer.as_ptr(); |
| 849 | let len = buffer.len(); | 714 | let len = buffer.len(); |
| 850 | 715 | ||
| 851 | let r = U::regs(); | 716 | let r = T::regs(); |
| 852 | let s = U::state(); | 717 | let s = T::state(); |
| 853 | 718 | ||
| 854 | self.ppi_ch1.enable(); | 719 | self.ppi_ch1.enable(); |
| 855 | 720 | ||
| @@ -893,9 +758,12 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 893 | Ok(n) | 758 | Ok(n) |
| 894 | } | 759 | } |
| 895 | 760 | ||
| 761 | /// Read bytes until the buffer is filled, or the line becomes idle. | ||
| 762 | /// | ||
| 763 | /// Returns the amount of bytes read. | ||
| 896 | pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 764 | pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 897 | if buffer.len() == 0 { | 765 | if buffer.len() == 0 { |
| 898 | return Err(Error::BufferZeroLength); | 766 | return Ok(0); |
| 899 | } | 767 | } |
| 900 | if buffer.len() > EASY_DMA_SIZE { | 768 | if buffer.len() > EASY_DMA_SIZE { |
| 901 | return Err(Error::BufferTooLong); | 769 | return Err(Error::BufferTooLong); |
| @@ -904,7 +772,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 904 | let ptr = buffer.as_ptr(); | 772 | let ptr = buffer.as_ptr(); |
| 905 | let len = buffer.len(); | 773 | let len = buffer.len(); |
| 906 | 774 | ||
| 907 | let r = U::regs(); | 775 | let r = T::regs(); |
| 908 | 776 | ||
| 909 | self.ppi_ch1.enable(); | 777 | self.ppi_ch1.enable(); |
| 910 | 778 | ||
| @@ -929,6 +797,73 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { | |||
| 929 | Ok(n) | 797 | Ok(n) |
| 930 | } | 798 | } |
| 931 | } | 799 | } |
| 800 | |||
| 801 | #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] | ||
| 802 | pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | ||
| 803 | // Do nothing | ||
| 804 | } | ||
| 805 | |||
| 806 | #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] | ||
| 807 | pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||
| 808 | // Apply workaround for anomalies: | ||
| 809 | // - nRF9160 - anomaly 23 | ||
| 810 | // - nRF5340 - anomaly 44 | ||
| 811 | let rxenable_reg: *const u32 = ((r as *const _ as usize) + 0x564) as *const u32; | ||
| 812 | let txenable_reg: *const u32 = ((r as *const _ as usize) + 0x568) as *const u32; | ||
| 813 | |||
| 814 | // NB Safety: This is taken from Nordic's driver - | ||
| 815 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 816 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 817 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 818 | } | ||
| 819 | |||
| 820 | // NB Safety: This is taken from Nordic's driver - | ||
| 821 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 822 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 823 | r.enable.write(|w| w.enable().enabled()); | ||
| 824 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 825 | |||
| 826 | let mut workaround_succeded = false; | ||
| 827 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 828 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 829 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 830 | for _ in 0..40000 { | ||
| 831 | // NB Safety: This is taken from Nordic's driver - | ||
| 832 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 833 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 834 | workaround_succeded = true; | ||
| 835 | break; | ||
| 836 | } else { | ||
| 837 | // Need to sleep for 1us here | ||
| 838 | } | ||
| 839 | } | ||
| 840 | |||
| 841 | if !workaround_succeded { | ||
| 842 | panic!("Failed to apply workaround for UART"); | ||
| 843 | } | ||
| 844 | |||
| 845 | let errors = r.errorsrc.read().bits(); | ||
| 846 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 847 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 848 | r.enable.write(|w| w.enable().disabled()); | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | ||
| 853 | if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { | ||
| 854 | // Finally we can disable, and we do so for the peripheral | ||
| 855 | // i.e. not just rx concerns. | ||
| 856 | r.enable.write(|w| w.enable().disabled()); | ||
| 857 | |||
| 858 | gpio::deconfigure_pin(r.psel.rxd.read().bits()); | ||
| 859 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | ||
| 860 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | ||
| 861 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | ||
| 862 | |||
| 863 | trace!("uarte tx and rx drop: done"); | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 932 | pub(crate) mod sealed { | 867 | pub(crate) mod sealed { |
| 933 | use core::sync::atomic::AtomicU8; | 868 | use core::sync::atomic::AtomicU8; |
| 934 | 869 | ||
| @@ -954,11 +889,14 @@ pub(crate) mod sealed { | |||
| 954 | pub trait Instance { | 889 | pub trait Instance { |
| 955 | fn regs() -> &'static pac::uarte0::RegisterBlock; | 890 | fn regs() -> &'static pac::uarte0::RegisterBlock; |
| 956 | fn state() -> &'static State; | 891 | fn state() -> &'static State; |
| 892 | fn buffered_state() -> &'static crate::buffered_uarte::State; | ||
| 957 | } | 893 | } |
| 958 | } | 894 | } |
| 959 | 895 | ||
| 896 | /// UARTE peripheral instance. | ||
| 960 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 897 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 961 | type Interrupt: Interrupt; | 898 | /// Interrupt for this peripheral. |
| 899 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 962 | } | 900 | } |
| 963 | 901 | ||
| 964 | macro_rules! impl_uarte { | 902 | macro_rules! impl_uarte { |
| @@ -971,9 +909,13 @@ macro_rules! impl_uarte { | |||
| 971 | static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); | 909 | static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); |
| 972 | &STATE | 910 | &STATE |
| 973 | } | 911 | } |
| 912 | fn buffered_state() -> &'static crate::buffered_uarte::State { | ||
| 913 | static STATE: crate::buffered_uarte::State = crate::buffered_uarte::State::new(); | ||
| 914 | &STATE | ||
| 915 | } | ||
| 974 | } | 916 | } |
| 975 | impl crate::uarte::Instance for peripherals::$type { | 917 | impl crate::uarte::Instance for peripherals::$type { |
| 976 | type Interrupt = crate::interrupt::$irq; | 918 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 977 | } | 919 | } |
| 978 | }; | 920 | }; |
| 979 | } | 921 | } |
| @@ -1006,18 +948,6 @@ mod eh02 { | |||
| 1006 | Ok(()) | 948 | Ok(()) |
| 1007 | } | 949 | } |
| 1008 | } | 950 | } |
| 1009 | |||
| 1010 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_02::blocking::serial::Write<u8> for UarteWithIdle<'d, U, T> { | ||
| 1011 | type Error = Error; | ||
| 1012 | |||
| 1013 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 1014 | self.blocking_write(buffer) | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | fn bflush(&mut self) -> Result<(), Self::Error> { | ||
| 1018 | Ok(()) | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | } | 951 | } |
| 1022 | 952 | ||
| 1023 | #[cfg(feature = "unstable-traits")] | 953 | #[cfg(feature = "unstable-traits")] |
| @@ -1028,8 +958,7 @@ mod eh1 { | |||
| 1028 | fn kind(&self) -> embedded_hal_1::serial::ErrorKind { | 958 | fn kind(&self) -> embedded_hal_1::serial::ErrorKind { |
| 1029 | match *self { | 959 | match *self { |
| 1030 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | 960 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, |
| 1031 | Self::BufferZeroLength => embedded_hal_1::serial::ErrorKind::Other, | 961 | Self::BufferNotInRAM => embedded_hal_1::serial::ErrorKind::Other, |
| 1032 | Self::DMABufferNotInDataMemory => embedded_hal_1::serial::ErrorKind::Other, | ||
| 1033 | } | 962 | } |
| 1034 | } | 963 | } |
| 1035 | } | 964 | } |
| @@ -1040,7 +969,7 @@ mod eh1 { | |||
| 1040 | type Error = Error; | 969 | type Error = Error; |
| 1041 | } | 970 | } |
| 1042 | 971 | ||
| 1043 | impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for Uarte<'d, T> { | 972 | impl<'d, T: Instance> embedded_hal_1::serial::Write for Uarte<'d, T> { |
| 1044 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 973 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 1045 | self.blocking_write(buffer) | 974 | self.blocking_write(buffer) |
| 1046 | } | 975 | } |
| @@ -1054,7 +983,7 @@ mod eh1 { | |||
| 1054 | type Error = Error; | 983 | type Error = Error; |
| 1055 | } | 984 | } |
| 1056 | 985 | ||
| 1057 | impl<'d, T: Instance> embedded_hal_1::serial::blocking::Write for UarteTx<'d, T> { | 986 | impl<'d, T: Instance> embedded_hal_1::serial::Write for UarteTx<'d, T> { |
| 1058 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 987 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| 1059 | self.blocking_write(buffer) | 988 | self.blocking_write(buffer) |
| 1060 | } | 989 | } |
| @@ -1067,84 +996,4 @@ mod eh1 { | |||
| 1067 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { | 996 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { |
| 1068 | type Error = Error; | 997 | type Error = Error; |
| 1069 | } | 998 | } |
| 1070 | |||
| 1071 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType for UarteWithIdle<'d, U, T> { | ||
| 1072 | type Error = Error; | ||
| 1073 | } | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | cfg_if::cfg_if! { | ||
| 1077 | if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] { | ||
| 1078 | use core::future::Future; | ||
| 1079 | |||
| 1080 | impl<'d, T: Instance> embedded_hal_async::serial::Read for Uarte<'d, T> { | ||
| 1081 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1082 | |||
| 1083 | fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 1084 | self.read(buffer) | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | impl<'d, T: Instance> embedded_hal_async::serial::Write for Uarte<'d, T> { | ||
| 1089 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1090 | |||
| 1091 | fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 1092 | self.write(buffer) | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1096 | |||
| 1097 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 1098 | async move { Ok(()) } | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | impl<'d, T: Instance> embedded_hal_async::serial::Write for UarteTx<'d, T> { | ||
| 1103 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1104 | |||
| 1105 | fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 1106 | self.write(buffer) | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1110 | |||
| 1111 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 1112 | async move { Ok(()) } | ||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | impl<'d, T: Instance> embedded_hal_async::serial::Read for UarteRx<'d, T> { | ||
| 1117 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1118 | |||
| 1119 | fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 1120 | self.read(buffer) | ||
| 1121 | } | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read | ||
| 1125 | for UarteWithIdle<'d, U, T> | ||
| 1126 | { | ||
| 1127 | type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1128 | |||
| 1129 | fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> { | ||
| 1130 | self.read(buffer) | ||
| 1131 | } | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write | ||
| 1135 | for UarteWithIdle<'d, U, T> | ||
| 1136 | { | ||
| 1137 | type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1138 | |||
| 1139 | fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> { | ||
| 1140 | self.write(buffer) | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a; | ||
| 1144 | |||
| 1145 | fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { | ||
| 1146 | async move { Ok(()) } | ||
| 1147 | } | ||
| 1148 | } | ||
| 1149 | } | ||
| 1150 | } | 999 | } |
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb/mod.rs index 688326e9c..76cf40ac7 100644 --- a/embassy-nrf/src/usb.rs +++ b/embassy-nrf/src/usb/mod.rs | |||
| @@ -1,23 +1,26 @@ | |||
| 1 | //! Universal Serial Bus (USB) driver. | ||
| 2 | |||
| 1 | #![macro_use] | 3 | #![macro_use] |
| 2 | 4 | ||
| 5 | pub mod vbus_detect; | ||
| 6 | |||
| 7 | use core::future::poll_fn; | ||
| 3 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 4 | use core::mem::MaybeUninit; | 9 | use core::mem::MaybeUninit; |
| 5 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | 10 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 6 | use core::task::Poll; | 11 | use core::task::Poll; |
| 7 | 12 | ||
| 8 | use cortex_m::peripheral::NVIC; | 13 | use cortex_m::peripheral::NVIC; |
| 9 | use embassy_hal_common::{into_ref, PeripheralRef}; | 14 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 15 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | pub use embassy_usb; | 16 | use embassy_usb_driver as driver; |
| 12 | use embassy_usb::driver::{self, EndpointError, Event, Unsupported}; | 17 | use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; |
| 13 | use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; | ||
| 14 | use futures::future::poll_fn; | ||
| 15 | use futures::Future; | ||
| 16 | use pac::usbd::RegisterBlock; | 18 | use pac::usbd::RegisterBlock; |
| 17 | 19 | ||
| 18 | use crate::interrupt::{Interrupt, InterruptExt}; | 20 | use self::vbus_detect::VbusDetect; |
| 21 | use crate::interrupt::typelevel::Interrupt; | ||
| 19 | use crate::util::slice_in_ram; | 22 | use crate::util::slice_in_ram; |
| 20 | use crate::{pac, Peripheral}; | 23 | use crate::{interrupt, pac, Peripheral}; |
| 21 | 24 | ||
| 22 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 25 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 23 | static BUS_WAKER: AtomicWaker = NEW_AW; | 26 | static BUS_WAKER: AtomicWaker = NEW_AW; |
| @@ -26,161 +29,13 @@ static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | |||
| 26 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; | 29 | static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; |
| 27 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); | 30 | static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); |
| 28 | 31 | ||
| 29 | /// There are multiple ways to detect USB power. The behavior | 32 | /// Interrupt handler. |
| 30 | /// here provides a hook into determining whether it is. | 33 | pub struct InterruptHandler<T: Instance> { |
| 31 | pub trait UsbSupply { | 34 | _phantom: PhantomData<T>, |
| 32 | fn is_usb_detected(&self) -> bool; | ||
| 33 | |||
| 34 | type UsbPowerReadyFuture<'a>: Future<Output = Result<(), ()>> + 'a | ||
| 35 | where | ||
| 36 | Self: 'a; | ||
| 37 | fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_>; | ||
| 38 | } | ||
| 39 | |||
| 40 | pub struct Driver<'d, T: Instance, P: UsbSupply> { | ||
| 41 | _p: PeripheralRef<'d, T>, | ||
| 42 | alloc_in: Allocator, | ||
| 43 | alloc_out: Allocator, | ||
| 44 | usb_supply: P, | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Uses the POWER peripheral to detect when power is available | ||
| 48 | /// for USB. Unsuitable for usage with the nRF softdevice. | ||
| 49 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 50 | pub struct PowerUsb { | ||
| 51 | _private: (), | ||
| 52 | } | ||
| 53 | |||
| 54 | /// Can be used to signal that power is available. Particularly suited for | ||
| 55 | /// use with the nRF softdevice. | ||
| 56 | pub struct SignalledSupply { | ||
| 57 | usb_detected: AtomicBool, | ||
| 58 | power_ready: AtomicBool, | ||
| 59 | } | ||
| 60 | |||
| 61 | static POWER_WAKER: AtomicWaker = NEW_AW; | ||
| 62 | |||
| 63 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 64 | impl PowerUsb { | ||
| 65 | pub fn new(power_irq: impl Interrupt) -> Self { | ||
| 66 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 67 | |||
| 68 | power_irq.set_handler(Self::on_interrupt); | ||
| 69 | power_irq.unpend(); | ||
| 70 | power_irq.enable(); | ||
| 71 | |||
| 72 | regs.intenset | ||
| 73 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||
| 74 | |||
| 75 | Self { _private: () } | ||
| 76 | } | ||
| 77 | |||
| 78 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 79 | fn on_interrupt(_: *mut ()) { | ||
| 80 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 81 | |||
| 82 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 83 | regs.events_usbdetected.reset(); | ||
| 84 | BUS_WAKER.wake(); | ||
| 85 | } | ||
| 86 | |||
| 87 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 88 | regs.events_usbremoved.reset(); | ||
| 89 | BUS_WAKER.wake(); | ||
| 90 | POWER_WAKER.wake(); | ||
| 91 | } | ||
| 92 | |||
| 93 | if regs.events_usbpwrrdy.read().bits() != 0 { | ||
| 94 | regs.events_usbpwrrdy.reset(); | ||
| 95 | POWER_WAKER.wake(); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | #[cfg(not(feature = "_nrf5340-app"))] | ||
| 101 | impl UsbSupply for PowerUsb { | ||
| 102 | fn is_usb_detected(&self) -> bool { | ||
| 103 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 104 | regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||
| 105 | } | ||
| 106 | |||
| 107 | type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a; | ||
| 108 | fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> { | ||
| 109 | poll_fn(move |cx| { | ||
| 110 | POWER_WAKER.register(cx.waker()); | ||
| 111 | let regs = unsafe { &*pac::POWER::ptr() }; | ||
| 112 | |||
| 113 | if regs.usbregstatus.read().outputrdy().is_ready() { | ||
| 114 | Poll::Ready(Ok(())) | ||
| 115 | } else if !self.is_usb_detected() { | ||
| 116 | Poll::Ready(Err(())) | ||
| 117 | } else { | ||
| 118 | Poll::Pending | ||
| 119 | } | ||
| 120 | }) | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | impl SignalledSupply { | ||
| 125 | pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||
| 126 | BUS_WAKER.wake(); | ||
| 127 | |||
| 128 | Self { | ||
| 129 | usb_detected: AtomicBool::new(usb_detected), | ||
| 130 | power_ready: AtomicBool::new(power_ready), | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn detected(&self, detected: bool) { | ||
| 135 | self.usb_detected.store(detected, Ordering::Relaxed); | ||
| 136 | self.power_ready.store(false, Ordering::Relaxed); | ||
| 137 | BUS_WAKER.wake(); | ||
| 138 | POWER_WAKER.wake(); | ||
| 139 | } | ||
| 140 | |||
| 141 | pub fn ready(&self) { | ||
| 142 | self.power_ready.store(true, Ordering::Relaxed); | ||
| 143 | POWER_WAKER.wake(); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | impl UsbSupply for &SignalledSupply { | ||
| 148 | fn is_usb_detected(&self) -> bool { | ||
| 149 | self.usb_detected.load(Ordering::Relaxed) | ||
| 150 | } | ||
| 151 | |||
| 152 | type UsbPowerReadyFuture<'a> = impl Future<Output = Result<(), ()>> + 'a where Self: 'a; | ||
| 153 | fn wait_power_ready(&mut self) -> Self::UsbPowerReadyFuture<'_> { | ||
| 154 | poll_fn(move |cx| { | ||
| 155 | POWER_WAKER.register(cx.waker()); | ||
| 156 | |||
| 157 | if self.power_ready.load(Ordering::Relaxed) { | ||
| 158 | Poll::Ready(Ok(())) | ||
| 159 | } else if !self.usb_detected.load(Ordering::Relaxed) { | ||
| 160 | Poll::Ready(Err(())) | ||
| 161 | } else { | ||
| 162 | Poll::Pending | ||
| 163 | } | ||
| 164 | }) | ||
| 165 | } | ||
| 166 | } | 35 | } |
| 167 | 36 | ||
| 168 | impl<'d, T: Instance, P: UsbSupply> Driver<'d, T, P> { | 37 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { |
| 169 | pub fn new(usb: impl Peripheral<P = T> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd, usb_supply: P) -> Self { | 38 | unsafe fn on_interrupt() { |
| 170 | into_ref!(usb, irq); | ||
| 171 | irq.set_handler(Self::on_interrupt); | ||
| 172 | irq.unpend(); | ||
| 173 | irq.enable(); | ||
| 174 | |||
| 175 | Self { | ||
| 176 | _p: usb, | ||
| 177 | alloc_in: Allocator::new(), | ||
| 178 | alloc_out: Allocator::new(), | ||
| 179 | usb_supply, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | fn on_interrupt(_: *mut ()) { | ||
| 184 | let regs = T::regs(); | 39 | let regs = T::regs(); |
| 185 | 40 | ||
| 186 | if regs.events_usbreset.read().bits() != 0 { | 41 | if regs.events_usbreset.read().bits() != 0 { |
| @@ -231,25 +86,54 @@ impl<'d, T: Instance, P: UsbSupply> Driver<'d, T, P> { | |||
| 231 | } | 86 | } |
| 232 | } | 87 | } |
| 233 | 88 | ||
| 234 | impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> { | 89 | /// USB driver. |
| 90 | pub struct Driver<'d, T: Instance, V: VbusDetect> { | ||
| 91 | _p: PeripheralRef<'d, T>, | ||
| 92 | alloc_in: Allocator, | ||
| 93 | alloc_out: Allocator, | ||
| 94 | vbus_detect: V, | ||
| 95 | } | ||
| 96 | |||
| 97 | impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { | ||
| 98 | /// Create a new USB driver. | ||
| 99 | pub fn new( | ||
| 100 | usb: impl Peripheral<P = T> + 'd, | ||
| 101 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 102 | vbus_detect: V, | ||
| 103 | ) -> Self { | ||
| 104 | into_ref!(usb); | ||
| 105 | |||
| 106 | T::Interrupt::unpend(); | ||
| 107 | unsafe { T::Interrupt::enable() }; | ||
| 108 | |||
| 109 | Self { | ||
| 110 | _p: usb, | ||
| 111 | alloc_in: Allocator::new(), | ||
| 112 | alloc_out: Allocator::new(), | ||
| 113 | vbus_detect, | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> { | ||
| 235 | type EndpointOut = Endpoint<'d, T, Out>; | 119 | type EndpointOut = Endpoint<'d, T, Out>; |
| 236 | type EndpointIn = Endpoint<'d, T, In>; | 120 | type EndpointIn = Endpoint<'d, T, In>; |
| 237 | type ControlPipe = ControlPipe<'d, T>; | 121 | type ControlPipe = ControlPipe<'d, T>; |
| 238 | type Bus = Bus<'d, T, P>; | 122 | type Bus = Bus<'d, T, V>; |
| 239 | 123 | ||
| 240 | fn alloc_endpoint_in( | 124 | fn alloc_endpoint_in( |
| 241 | &mut self, | 125 | &mut self, |
| 242 | ep_type: EndpointType, | 126 | ep_type: EndpointType, |
| 243 | packet_size: u16, | 127 | packet_size: u16, |
| 244 | interval: u8, | 128 | interval_ms: u8, |
| 245 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { | 129 | ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { |
| 246 | let index = self.alloc_in.allocate(ep_type)?; | 130 | let index = self.alloc_in.allocate(ep_type)?; |
| 247 | let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In); | 131 | let ep_addr = EndpointAddress::from_parts(index, Direction::In); |
| 248 | Ok(Endpoint::new(EndpointInfo { | 132 | Ok(Endpoint::new(EndpointInfo { |
| 249 | addr: ep_addr, | 133 | addr: ep_addr, |
| 250 | ep_type, | 134 | ep_type, |
| 251 | max_packet_size: packet_size, | 135 | max_packet_size: packet_size, |
| 252 | interval, | 136 | interval_ms, |
| 253 | })) | 137 | })) |
| 254 | } | 138 | } |
| 255 | 139 | ||
| @@ -257,24 +141,24 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> | |||
| 257 | &mut self, | 141 | &mut self, |
| 258 | ep_type: EndpointType, | 142 | ep_type: EndpointType, |
| 259 | packet_size: u16, | 143 | packet_size: u16, |
| 260 | interval: u8, | 144 | interval_ms: u8, |
| 261 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { | 145 | ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { |
| 262 | let index = self.alloc_out.allocate(ep_type)?; | 146 | let index = self.alloc_out.allocate(ep_type)?; |
| 263 | let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out); | 147 | let ep_addr = EndpointAddress::from_parts(index, Direction::Out); |
| 264 | Ok(Endpoint::new(EndpointInfo { | 148 | Ok(Endpoint::new(EndpointInfo { |
| 265 | addr: ep_addr, | 149 | addr: ep_addr, |
| 266 | ep_type, | 150 | ep_type, |
| 267 | max_packet_size: packet_size, | 151 | max_packet_size: packet_size, |
| 268 | interval, | 152 | interval_ms, |
| 269 | })) | 153 | })) |
| 270 | } | 154 | } |
| 271 | 155 | ||
| 272 | fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { | 156 | fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { |
| 273 | ( | 157 | ( |
| 274 | Bus { | 158 | Bus { |
| 275 | _p: unsafe { self._p.clone_unchecked() }, | 159 | _p: unsafe { self._p.clone_unchecked() }, |
| 276 | power_available: false, | 160 | power_available: false, |
| 277 | usb_supply: self.usb_supply, | 161 | vbus_detect: self.vbus_detect, |
| 278 | }, | 162 | }, |
| 279 | ControlPipe { | 163 | ControlPipe { |
| 280 | _p: self._p, | 164 | _p: self._p, |
| @@ -284,68 +168,60 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P> | |||
| 284 | } | 168 | } |
| 285 | } | 169 | } |
| 286 | 170 | ||
| 287 | pub struct Bus<'d, T: Instance, P: UsbSupply> { | 171 | /// USB bus. |
| 172 | pub struct Bus<'d, T: Instance, V: VbusDetect> { | ||
| 288 | _p: PeripheralRef<'d, T>, | 173 | _p: PeripheralRef<'d, T>, |
| 289 | power_available: bool, | 174 | power_available: bool, |
| 290 | usb_supply: P, | 175 | vbus_detect: V, |
| 291 | } | 176 | } |
| 292 | 177 | ||
| 293 | impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | 178 | impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { |
| 294 | type EnableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | 179 | async fn enable(&mut self) { |
| 295 | type DisableFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | 180 | let regs = T::regs(); |
| 296 | type PollFuture<'a> = impl Future<Output = Event> + 'a where Self: 'a; | ||
| 297 | type RemoteWakeupFuture<'a> = impl Future<Output = Result<(), Unsupported>> + 'a where Self: 'a; | ||
| 298 | |||
| 299 | fn enable(&mut self) -> Self::EnableFuture<'_> { | ||
| 300 | async move { | ||
| 301 | let regs = T::regs(); | ||
| 302 | |||
| 303 | errata::pre_enable(); | ||
| 304 | |||
| 305 | regs.enable.write(|w| w.enable().enabled()); | ||
| 306 | |||
| 307 | // Wait until the peripheral is ready. | ||
| 308 | regs.intenset.write(|w| w.usbevent().set_bit()); | ||
| 309 | poll_fn(|cx| { | ||
| 310 | BUS_WAKER.register(cx.waker()); | ||
| 311 | if regs.eventcause.read().ready().is_ready() { | ||
| 312 | Poll::Ready(()) | ||
| 313 | } else { | ||
| 314 | Poll::Pending | ||
| 315 | } | ||
| 316 | }) | ||
| 317 | .await; | ||
| 318 | regs.eventcause.write(|w| w.ready().set_bit()); // Write 1 to clear. | ||
| 319 | |||
| 320 | errata::post_enable(); | ||
| 321 | 181 | ||
| 322 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; | 182 | errata::pre_enable(); |
| 323 | 183 | ||
| 324 | regs.intenset.write(|w| { | 184 | regs.enable.write(|w| w.enable().enabled()); |
| 325 | w.usbreset().set_bit(); | ||
| 326 | w.usbevent().set_bit(); | ||
| 327 | w.epdata().set_bit(); | ||
| 328 | w | ||
| 329 | }); | ||
| 330 | 185 | ||
| 331 | if self.usb_supply.wait_power_ready().await.is_ok() { | 186 | // Wait until the peripheral is ready. |
| 332 | // Enable the USB pullup, allowing enumeration. | 187 | regs.intenset.write(|w| w.usbevent().set_bit()); |
| 333 | regs.usbpullup.write(|w| w.connect().enabled()); | 188 | poll_fn(|cx| { |
| 334 | trace!("enabled"); | 189 | BUS_WAKER.register(cx.waker()); |
| 190 | if regs.eventcause.read().ready().is_ready() { | ||
| 191 | Poll::Ready(()) | ||
| 335 | } else { | 192 | } else { |
| 336 | trace!("usb power not ready due to usb removal"); | 193 | Poll::Pending |
| 337 | } | 194 | } |
| 195 | }) | ||
| 196 | .await; | ||
| 197 | regs.eventcause.write(|w| w.ready().clear_bit_by_one()); | ||
| 198 | |||
| 199 | errata::post_enable(); | ||
| 200 | |||
| 201 | unsafe { NVIC::unmask(pac::Interrupt::USBD) }; | ||
| 202 | |||
| 203 | regs.intenset.write(|w| { | ||
| 204 | w.usbreset().set_bit(); | ||
| 205 | w.usbevent().set_bit(); | ||
| 206 | w.epdata().set_bit(); | ||
| 207 | w | ||
| 208 | }); | ||
| 209 | |||
| 210 | if self.vbus_detect.wait_power_ready().await.is_ok() { | ||
| 211 | // Enable the USB pullup, allowing enumeration. | ||
| 212 | regs.usbpullup.write(|w| w.connect().enabled()); | ||
| 213 | trace!("enabled"); | ||
| 214 | } else { | ||
| 215 | trace!("usb power not ready due to usb removal"); | ||
| 338 | } | 216 | } |
| 339 | } | 217 | } |
| 340 | 218 | ||
| 341 | fn disable(&mut self) -> Self::DisableFuture<'_> { | 219 | async fn disable(&mut self) { |
| 342 | async move { | 220 | let regs = T::regs(); |
| 343 | let regs = T::regs(); | 221 | regs.enable.write(|x| x.enable().disabled()); |
| 344 | regs.enable.write(|x| x.enable().disabled()); | ||
| 345 | } | ||
| 346 | } | 222 | } |
| 347 | 223 | ||
| 348 | fn poll<'a>(&'a mut self) -> Self::PollFuture<'a> { | 224 | async fn poll(&mut self) -> Event { |
| 349 | poll_fn(move |cx| { | 225 | poll_fn(move |cx| { |
| 350 | BUS_WAKER.register(cx.waker()); | 226 | BUS_WAKER.register(cx.waker()); |
| 351 | let regs = T::regs(); | 227 | let regs = T::regs(); |
| @@ -369,28 +245,28 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 369 | let r = regs.eventcause.read(); | 245 | let r = regs.eventcause.read(); |
| 370 | 246 | ||
| 371 | if r.isooutcrc().bit() { | 247 | if r.isooutcrc().bit() { |
| 372 | regs.eventcause.write(|w| w.isooutcrc().set_bit()); | 248 | regs.eventcause.write(|w| w.isooutcrc().detected()); |
| 373 | trace!("USB event: isooutcrc"); | 249 | trace!("USB event: isooutcrc"); |
| 374 | } | 250 | } |
| 375 | if r.usbwuallowed().bit() { | 251 | if r.usbwuallowed().bit() { |
| 376 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | 252 | regs.eventcause.write(|w| w.usbwuallowed().allowed()); |
| 377 | trace!("USB event: usbwuallowed"); | 253 | trace!("USB event: usbwuallowed"); |
| 378 | } | 254 | } |
| 379 | if r.suspend().bit() { | 255 | if r.suspend().bit() { |
| 380 | regs.eventcause.write(|w| w.suspend().set_bit()); | 256 | regs.eventcause.write(|w| w.suspend().detected()); |
| 381 | regs.lowpower.write(|w| w.lowpower().low_power()); | 257 | regs.lowpower.write(|w| w.lowpower().low_power()); |
| 382 | return Poll::Ready(Event::Suspend); | 258 | return Poll::Ready(Event::Suspend); |
| 383 | } | 259 | } |
| 384 | if r.resume().bit() { | 260 | if r.resume().bit() { |
| 385 | regs.eventcause.write(|w| w.resume().set_bit()); | 261 | regs.eventcause.write(|w| w.resume().detected()); |
| 386 | return Poll::Ready(Event::Resume); | 262 | return Poll::Ready(Event::Resume); |
| 387 | } | 263 | } |
| 388 | if r.ready().bit() { | 264 | if r.ready().bit() { |
| 389 | regs.eventcause.write(|w| w.ready().set_bit()); | 265 | regs.eventcause.write(|w| w.ready().ready()); |
| 390 | trace!("USB event: ready"); | 266 | trace!("USB event: ready"); |
| 391 | } | 267 | } |
| 392 | 268 | ||
| 393 | if self.usb_supply.is_usb_detected() != self.power_available { | 269 | if self.vbus_detect.is_usb_detected() != self.power_available { |
| 394 | self.power_available = !self.power_available; | 270 | self.power_available = !self.power_available; |
| 395 | if self.power_available { | 271 | if self.power_available { |
| 396 | trace!("Power event: available"); | 272 | trace!("Power event: available"); |
| @@ -403,11 +279,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 403 | 279 | ||
| 404 | Poll::Pending | 280 | Poll::Pending |
| 405 | }) | 281 | }) |
| 406 | } | 282 | .await |
| 407 | |||
| 408 | #[inline] | ||
| 409 | fn set_address(&mut self, _addr: u8) { | ||
| 410 | // Nothing to do, the peripheral handles this. | ||
| 411 | } | 283 | } |
| 412 | 284 | ||
| 413 | fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { | 285 | fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { |
| @@ -429,8 +301,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 429 | let regs = T::regs(); | 301 | let regs = T::regs(); |
| 430 | let i = ep_addr.index(); | 302 | let i = ep_addr.index(); |
| 431 | match ep_addr.direction() { | 303 | match ep_addr.direction() { |
| 432 | UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(), | 304 | Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(), |
| 433 | UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(), | 305 | Direction::In => regs.halted.epin[i].read().getstatus().is_halted(), |
| 434 | } | 306 | } |
| 435 | } | 307 | } |
| 436 | 308 | ||
| @@ -443,7 +315,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 443 | debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); | 315 | debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); |
| 444 | 316 | ||
| 445 | match ep_addr.direction() { | 317 | match ep_addr.direction() { |
| 446 | UsbDirection::In => { | 318 | Direction::In => { |
| 447 | let mut was_enabled = false; | 319 | let mut was_enabled = false; |
| 448 | regs.epinen.modify(|r, w| { | 320 | regs.epinen.modify(|r, w| { |
| 449 | let mut bits = r.bits(); | 321 | let mut bits = r.bits(); |
| @@ -467,7 +339,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 467 | 339 | ||
| 468 | In::waker(i).wake(); | 340 | In::waker(i).wake(); |
| 469 | } | 341 | } |
| 470 | UsbDirection::Out => { | 342 | Direction::Out => { |
| 471 | regs.epouten.modify(|r, w| { | 343 | regs.epouten.modify(|r, w| { |
| 472 | let mut bits = r.bits(); | 344 | let mut bits = r.bits(); |
| 473 | if enabled { | 345 | if enabled { |
| @@ -495,46 +367,47 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> { | |||
| 495 | } | 367 | } |
| 496 | 368 | ||
| 497 | #[inline] | 369 | #[inline] |
| 498 | fn remote_wakeup(&mut self) -> Self::RemoteWakeupFuture<'_> { | 370 | async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { |
| 499 | async move { | 371 | let regs = T::regs(); |
| 500 | let regs = T::regs(); | ||
| 501 | 372 | ||
| 502 | if regs.lowpower.read().lowpower().is_low_power() { | 373 | if regs.lowpower.read().lowpower().is_low_power() { |
| 503 | errata::pre_wakeup(); | 374 | errata::pre_wakeup(); |
| 504 | 375 | ||
| 505 | regs.lowpower.write(|w| w.lowpower().force_normal()); | 376 | regs.lowpower.write(|w| w.lowpower().force_normal()); |
| 506 | 377 | ||
| 507 | poll_fn(|cx| { | 378 | poll_fn(|cx| { |
| 508 | BUS_WAKER.register(cx.waker()); | 379 | BUS_WAKER.register(cx.waker()); |
| 509 | let regs = T::regs(); | 380 | let regs = T::regs(); |
| 510 | let r = regs.eventcause.read(); | 381 | let r = regs.eventcause.read(); |
| 511 | 382 | ||
| 512 | if regs.events_usbreset.read().bits() != 0 { | 383 | if regs.events_usbreset.read().bits() != 0 { |
| 513 | Poll::Ready(()) | 384 | Poll::Ready(()) |
| 514 | } else if r.resume().bit() { | 385 | } else if r.resume().bit() { |
| 515 | Poll::Ready(()) | 386 | Poll::Ready(()) |
| 516 | } else if r.usbwuallowed().bit() { | 387 | } else if r.usbwuallowed().bit() { |
| 517 | regs.eventcause.write(|w| w.usbwuallowed().set_bit()); | 388 | regs.eventcause.write(|w| w.usbwuallowed().allowed()); |
| 518 | 389 | ||
| 519 | regs.dpdmvalue.write(|w| w.state().resume()); | 390 | regs.dpdmvalue.write(|w| w.state().resume()); |
| 520 | regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); | 391 | regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); |
| 521 | 392 | ||
| 522 | Poll::Ready(()) | 393 | Poll::Ready(()) |
| 523 | } else { | 394 | } else { |
| 524 | Poll::Pending | 395 | Poll::Pending |
| 525 | } | 396 | } |
| 526 | }) | 397 | }) |
| 527 | .await; | 398 | .await; |
| 528 | |||
| 529 | errata::post_wakeup(); | ||
| 530 | } | ||
| 531 | 399 | ||
| 532 | Ok(()) | 400 | errata::post_wakeup(); |
| 533 | } | 401 | } |
| 402 | |||
| 403 | Ok(()) | ||
| 534 | } | 404 | } |
| 535 | } | 405 | } |
| 536 | 406 | ||
| 407 | /// Type-level marker for OUT endpoints. | ||
| 537 | pub enum Out {} | 408 | pub enum Out {} |
| 409 | |||
| 410 | /// Type-level marker for IN endpoints. | ||
| 538 | pub enum In {} | 411 | pub enum In {} |
| 539 | 412 | ||
| 540 | trait EndpointDir { | 413 | trait EndpointDir { |
| @@ -577,6 +450,7 @@ impl EndpointDir for Out { | |||
| 577 | } | 450 | } |
| 578 | } | 451 | } |
| 579 | 452 | ||
| 453 | /// USB endpoint. | ||
| 580 | pub struct Endpoint<'d, T: Instance, Dir> { | 454 | pub struct Endpoint<'d, T: Instance, Dir> { |
| 581 | _phantom: PhantomData<(&'d mut T, Dir)>, | 455 | _phantom: PhantomData<(&'d mut T, Dir)>, |
| 582 | info: EndpointInfo, | 456 | info: EndpointInfo, |
| @@ -596,9 +470,7 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir | |||
| 596 | &self.info | 470 | &self.info |
| 597 | } | 471 | } |
| 598 | 472 | ||
| 599 | type WaitEnabledFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | 473 | async fn wait_enabled(&mut self) { |
| 600 | |||
| 601 | fn wait_enabled(&mut self) -> Self::WaitEnabledFuture<'_> { | ||
| 602 | let i = self.info.addr.index(); | 474 | let i = self.info.addr.index(); |
| 603 | assert!(i != 0); | 475 | assert!(i != 0); |
| 604 | 476 | ||
| @@ -610,6 +482,7 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir | |||
| 610 | Poll::Pending | 482 | Poll::Pending |
| 611 | } | 483 | } |
| 612 | }) | 484 | }) |
| 485 | .await | ||
| 613 | } | 486 | } |
| 614 | } | 487 | } |
| 615 | 488 | ||
| @@ -714,173 +587,155 @@ unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) { | |||
| 714 | } | 587 | } |
| 715 | 588 | ||
| 716 | impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { | 589 | impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { |
| 717 | type ReadFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a; | 590 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { |
| 718 | 591 | let i = self.info.addr.index(); | |
| 719 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { | 592 | assert!(i != 0); |
| 720 | async move { | ||
| 721 | let i = self.info.addr.index(); | ||
| 722 | assert!(i != 0); | ||
| 723 | 593 | ||
| 724 | self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; | 594 | self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; |
| 725 | 595 | ||
| 726 | unsafe { read_dma::<T>(i, buf) } | 596 | unsafe { read_dma::<T>(i, buf) } |
| 727 | } | ||
| 728 | } | 597 | } |
| 729 | } | 598 | } |
| 730 | 599 | ||
| 731 | impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { | 600 | impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { |
| 732 | type WriteFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a; | 601 | async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { |
| 733 | 602 | let i = self.info.addr.index(); | |
| 734 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { | 603 | assert!(i != 0); |
| 735 | async move { | ||
| 736 | let i = self.info.addr.index(); | ||
| 737 | assert!(i != 0); | ||
| 738 | 604 | ||
| 739 | self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; | 605 | self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; |
| 740 | 606 | ||
| 741 | unsafe { write_dma::<T>(i, buf) } | 607 | unsafe { write_dma::<T>(i, buf) } |
| 742 | 608 | ||
| 743 | Ok(()) | 609 | Ok(()) |
| 744 | } | ||
| 745 | } | 610 | } |
| 746 | } | 611 | } |
| 747 | 612 | ||
| 613 | /// USB control pipe. | ||
| 748 | pub struct ControlPipe<'d, T: Instance> { | 614 | pub struct ControlPipe<'d, T: Instance> { |
| 749 | _p: PeripheralRef<'d, T>, | 615 | _p: PeripheralRef<'d, T>, |
| 750 | max_packet_size: u16, | 616 | max_packet_size: u16, |
| 751 | } | 617 | } |
| 752 | 618 | ||
| 753 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { | 619 | impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { |
| 754 | type SetupFuture<'a> = impl Future<Output = [u8;8]> + 'a where Self: 'a; | ||
| 755 | type DataOutFuture<'a> = impl Future<Output = Result<usize, EndpointError>> + 'a where Self: 'a; | ||
| 756 | type DataInFuture<'a> = impl Future<Output = Result<(), EndpointError>> + 'a where Self: 'a; | ||
| 757 | type AcceptFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | ||
| 758 | type RejectFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; | ||
| 759 | |||
| 760 | fn max_packet_size(&self) -> usize { | 620 | fn max_packet_size(&self) -> usize { |
| 761 | usize::from(self.max_packet_size) | 621 | usize::from(self.max_packet_size) |
| 762 | } | 622 | } |
| 763 | 623 | ||
| 764 | fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { | 624 | async fn setup(&mut self) -> [u8; 8] { |
| 765 | async move { | 625 | let regs = T::regs(); |
| 766 | let regs = T::regs(); | ||
| 767 | 626 | ||
| 768 | // Reset shorts | 627 | // Reset shorts |
| 769 | regs.shorts.write(|w| w); | 628 | regs.shorts.write(|w| w); |
| 770 | 629 | ||
| 771 | // Wait for SETUP packet | 630 | // Wait for SETUP packet |
| 772 | regs.intenset.write(|w| w.ep0setup().set()); | 631 | regs.intenset.write(|w| w.ep0setup().set()); |
| 773 | poll_fn(|cx| { | 632 | poll_fn(|cx| { |
| 774 | EP0_WAKER.register(cx.waker()); | 633 | EP0_WAKER.register(cx.waker()); |
| 775 | let regs = T::regs(); | 634 | let regs = T::regs(); |
| 776 | if regs.events_ep0setup.read().bits() != 0 { | 635 | if regs.events_ep0setup.read().bits() != 0 { |
| 777 | Poll::Ready(()) | 636 | Poll::Ready(()) |
| 778 | } else { | 637 | } else { |
| 779 | Poll::Pending | 638 | Poll::Pending |
| 780 | } | 639 | } |
| 781 | }) | 640 | }) |
| 782 | .await; | 641 | .await; |
| 783 | 642 | ||
| 784 | regs.events_ep0setup.reset(); | 643 | regs.events_ep0setup.reset(); |
| 785 | 644 | ||
| 786 | let mut buf = [0; 8]; | 645 | let mut buf = [0; 8]; |
| 787 | buf[0] = regs.bmrequesttype.read().bits() as u8; | 646 | buf[0] = regs.bmrequesttype.read().bits() as u8; |
| 788 | buf[1] = regs.brequest.read().brequest().bits(); | 647 | buf[1] = regs.brequest.read().brequest().bits(); |
| 789 | buf[2] = regs.wvaluel.read().wvaluel().bits(); | 648 | buf[2] = regs.wvaluel.read().wvaluel().bits(); |
| 790 | buf[3] = regs.wvalueh.read().wvalueh().bits(); | 649 | buf[3] = regs.wvalueh.read().wvalueh().bits(); |
| 791 | buf[4] = regs.windexl.read().windexl().bits(); | 650 | buf[4] = regs.windexl.read().windexl().bits(); |
| 792 | buf[5] = regs.windexh.read().windexh().bits(); | 651 | buf[5] = regs.windexh.read().windexh().bits(); |
| 793 | buf[6] = regs.wlengthl.read().wlengthl().bits(); | 652 | buf[6] = regs.wlengthl.read().wlengthl().bits(); |
| 794 | buf[7] = regs.wlengthh.read().wlengthh().bits(); | 653 | buf[7] = regs.wlengthh.read().wlengthh().bits(); |
| 795 | 654 | ||
| 796 | buf | 655 | buf |
| 797 | } | ||
| 798 | } | 656 | } |
| 799 | 657 | ||
| 800 | fn data_out<'a>(&'a mut self, buf: &'a mut [u8], _first: bool, _last: bool) -> Self::DataOutFuture<'a> { | 658 | async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> { |
| 801 | async move { | 659 | let regs = T::regs(); |
| 802 | let regs = T::regs(); | ||
| 803 | 660 | ||
| 804 | regs.events_ep0datadone.reset(); | 661 | regs.events_ep0datadone.reset(); |
| 805 | 662 | ||
| 806 | // This starts a RX on EP0. events_ep0datadone notifies when done. | 663 | // This starts a RX on EP0. events_ep0datadone notifies when done. |
| 807 | regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit()); | 664 | regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit()); |
| 808 | 665 | ||
| 809 | // Wait until ready | 666 | // Wait until ready |
| 810 | regs.intenset.write(|w| { | 667 | regs.intenset.write(|w| { |
| 811 | w.usbreset().set(); | 668 | w.usbreset().set(); |
| 812 | w.ep0setup().set(); | 669 | w.ep0setup().set(); |
| 813 | w.ep0datadone().set() | 670 | w.ep0datadone().set() |
| 814 | }); | 671 | }); |
| 815 | poll_fn(|cx| { | 672 | poll_fn(|cx| { |
| 816 | EP0_WAKER.register(cx.waker()); | 673 | EP0_WAKER.register(cx.waker()); |
| 817 | let regs = T::regs(); | 674 | let regs = T::regs(); |
| 818 | if regs.events_ep0datadone.read().bits() != 0 { | 675 | if regs.events_ep0datadone.read().bits() != 0 { |
| 819 | Poll::Ready(Ok(())) | 676 | Poll::Ready(Ok(())) |
| 820 | } else if regs.events_usbreset.read().bits() != 0 { | 677 | } else if regs.events_usbreset.read().bits() != 0 { |
| 821 | trace!("aborted control data_out: usb reset"); | 678 | trace!("aborted control data_out: usb reset"); |
| 822 | Poll::Ready(Err(EndpointError::Disabled)) | 679 | Poll::Ready(Err(EndpointError::Disabled)) |
| 823 | } else if regs.events_ep0setup.read().bits() != 0 { | 680 | } else if regs.events_ep0setup.read().bits() != 0 { |
| 824 | trace!("aborted control data_out: received another SETUP"); | 681 | trace!("aborted control data_out: received another SETUP"); |
| 825 | Poll::Ready(Err(EndpointError::Disabled)) | 682 | Poll::Ready(Err(EndpointError::Disabled)) |
| 826 | } else { | 683 | } else { |
| 827 | Poll::Pending | 684 | Poll::Pending |
| 828 | } | 685 | } |
| 829 | }) | 686 | }) |
| 830 | .await?; | 687 | .await?; |
| 831 | 688 | ||
| 832 | unsafe { read_dma::<T>(0, buf) } | 689 | unsafe { read_dma::<T>(0, buf) } |
| 833 | } | ||
| 834 | } | 690 | } |
| 835 | 691 | ||
| 836 | fn data_in<'a>(&'a mut self, buf: &'a [u8], _first: bool, last: bool) -> Self::DataInFuture<'a> { | 692 | async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { |
| 837 | async move { | 693 | let regs = T::regs(); |
| 838 | let regs = T::regs(); | 694 | regs.events_ep0datadone.reset(); |
| 839 | regs.events_ep0datadone.reset(); | ||
| 840 | 695 | ||
| 841 | regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last)); | 696 | regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last)); |
| 842 | 697 | ||
| 843 | // This starts a TX on EP0. events_ep0datadone notifies when done. | 698 | // This starts a TX on EP0. events_ep0datadone notifies when done. |
| 844 | unsafe { write_dma::<T>(0, buf) } | 699 | unsafe { write_dma::<T>(0, buf) } |
| 845 | 700 | ||
| 846 | regs.intenset.write(|w| { | 701 | regs.intenset.write(|w| { |
| 847 | w.usbreset().set(); | 702 | w.usbreset().set(); |
| 848 | w.ep0setup().set(); | 703 | w.ep0setup().set(); |
| 849 | w.ep0datadone().set() | 704 | w.ep0datadone().set() |
| 850 | }); | 705 | }); |
| 851 | 706 | ||
| 852 | poll_fn(|cx| { | 707 | poll_fn(|cx| { |
| 853 | cx.waker().wake_by_ref(); | 708 | cx.waker().wake_by_ref(); |
| 854 | EP0_WAKER.register(cx.waker()); | 709 | EP0_WAKER.register(cx.waker()); |
| 855 | let regs = T::regs(); | 710 | let regs = T::regs(); |
| 856 | if regs.events_ep0datadone.read().bits() != 0 { | 711 | if regs.events_ep0datadone.read().bits() != 0 { |
| 857 | Poll::Ready(Ok(())) | 712 | Poll::Ready(Ok(())) |
| 858 | } else if regs.events_usbreset.read().bits() != 0 { | 713 | } else if regs.events_usbreset.read().bits() != 0 { |
| 859 | trace!("aborted control data_in: usb reset"); | 714 | trace!("aborted control data_in: usb reset"); |
| 860 | Poll::Ready(Err(EndpointError::Disabled)) | 715 | Poll::Ready(Err(EndpointError::Disabled)) |
| 861 | } else if regs.events_ep0setup.read().bits() != 0 { | 716 | } else if regs.events_ep0setup.read().bits() != 0 { |
| 862 | trace!("aborted control data_in: received another SETUP"); | 717 | trace!("aborted control data_in: received another SETUP"); |
| 863 | Poll::Ready(Err(EndpointError::Disabled)) | 718 | Poll::Ready(Err(EndpointError::Disabled)) |
| 864 | } else { | 719 | } else { |
| 865 | Poll::Pending | 720 | Poll::Pending |
| 866 | } | 721 | } |
| 867 | }) | 722 | }) |
| 868 | .await | 723 | .await |
| 869 | } | ||
| 870 | } | 724 | } |
| 871 | 725 | ||
| 872 | fn accept<'a>(&'a mut self) -> Self::AcceptFuture<'a> { | 726 | async fn accept(&mut self) { |
| 873 | async move { | 727 | let regs = T::regs(); |
| 874 | let regs = T::regs(); | 728 | regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true)); |
| 875 | regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true)); | ||
| 876 | } | ||
| 877 | } | 729 | } |
| 878 | 730 | ||
| 879 | fn reject<'a>(&'a mut self) -> Self::RejectFuture<'a> { | 731 | async fn reject(&mut self) { |
| 880 | async move { | 732 | let regs = T::regs(); |
| 881 | let regs = T::regs(); | 733 | regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); |
| 882 | regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); | 734 | } |
| 883 | } | 735 | |
| 736 | async fn accept_set_address(&mut self, _addr: u8) { | ||
| 737 | self.accept().await; | ||
| 738 | // Nothing to do, the peripheral handles this. | ||
| 884 | } | 739 | } |
| 885 | } | 740 | } |
| 886 | 741 | ||
| @@ -946,8 +801,10 @@ pub(crate) mod sealed { | |||
| 946 | } | 801 | } |
| 947 | } | 802 | } |
| 948 | 803 | ||
| 804 | /// USB peripheral instance. | ||
| 949 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 805 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { |
| 950 | type Interrupt: Interrupt; | 806 | /// Interrupt for this peripheral. |
| 807 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 951 | } | 808 | } |
| 952 | 809 | ||
| 953 | macro_rules! impl_usb { | 810 | macro_rules! impl_usb { |
| @@ -958,7 +815,7 @@ macro_rules! impl_usb { | |||
| 958 | } | 815 | } |
| 959 | } | 816 | } |
| 960 | impl crate::usb::Instance for peripherals::$type { | 817 | impl crate::usb::Instance for peripherals::$type { |
| 961 | type Interrupt = crate::interrupt::$irq; | 818 | type Interrupt = crate::interrupt::typelevel::$irq; |
| 962 | } | 819 | } |
| 963 | }; | 820 | }; |
| 964 | } | 821 | } |
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs new file mode 100644 index 000000000..a05e5aa52 --- /dev/null +++ b/embassy-nrf/src/usb/vbus_detect.rs | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | //! Trait and implementations for performing VBUS detection. | ||
| 2 | |||
| 3 | use core::future::poll_fn; | ||
| 4 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 5 | use core::task::Poll; | ||
| 6 | |||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 8 | |||
| 9 | use super::BUS_WAKER; | ||
| 10 | use crate::interrupt::typelevel::Interrupt; | ||
| 11 | use crate::{interrupt, pac}; | ||
| 12 | |||
| 13 | /// Trait for detecting USB VBUS power. | ||
| 14 | /// | ||
| 15 | /// There are multiple ways to detect USB power. The behavior | ||
| 16 | /// here provides a hook into determining whether it is. | ||
| 17 | pub trait VbusDetect { | ||
| 18 | /// Report whether power is detected. | ||
| 19 | /// | ||
| 20 | /// This is indicated by the `USBREGSTATUS.VBUSDETECT` register, or the | ||
| 21 | /// `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 22 | fn is_usb_detected(&self) -> bool; | ||
| 23 | |||
| 24 | /// Wait until USB power is ready. | ||
| 25 | /// | ||
| 26 | /// USB power ready is indicated by the `USBREGSTATUS.OUTPUTRDY` register, or the | ||
| 27 | /// `USBPWRRDY` event from the `POWER` peripheral. | ||
| 28 | async fn wait_power_ready(&mut self) -> Result<(), ()>; | ||
| 29 | } | ||
| 30 | |||
| 31 | #[cfg(not(feature = "_nrf5340"))] | ||
| 32 | type UsbRegIrq = interrupt::typelevel::POWER_CLOCK; | ||
| 33 | #[cfg(feature = "_nrf5340")] | ||
| 34 | type UsbRegIrq = interrupt::typelevel::USBREGULATOR; | ||
| 35 | |||
| 36 | #[cfg(not(feature = "_nrf5340"))] | ||
| 37 | type UsbRegPeri = pac::POWER; | ||
| 38 | #[cfg(feature = "_nrf5340")] | ||
| 39 | type UsbRegPeri = pac::USBREGULATOR; | ||
| 40 | |||
| 41 | /// Interrupt handler. | ||
| 42 | pub struct InterruptHandler { | ||
| 43 | _private: (), | ||
| 44 | } | ||
| 45 | |||
| 46 | impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler { | ||
| 47 | unsafe fn on_interrupt() { | ||
| 48 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 49 | |||
| 50 | if regs.events_usbdetected.read().bits() != 0 { | ||
| 51 | regs.events_usbdetected.reset(); | ||
| 52 | BUS_WAKER.wake(); | ||
| 53 | } | ||
| 54 | |||
| 55 | if regs.events_usbremoved.read().bits() != 0 { | ||
| 56 | regs.events_usbremoved.reset(); | ||
| 57 | BUS_WAKER.wake(); | ||
| 58 | POWER_WAKER.wake(); | ||
| 59 | } | ||
| 60 | |||
| 61 | if regs.events_usbpwrrdy.read().bits() != 0 { | ||
| 62 | regs.events_usbpwrrdy.reset(); | ||
| 63 | POWER_WAKER.wake(); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// [`VbusDetect`] implementation using the native hardware POWER peripheral. | ||
| 69 | /// | ||
| 70 | /// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces | ||
| 71 | /// to POWER. In that case, use [`VbusDetectSignal`]. | ||
| 72 | pub struct HardwareVbusDetect { | ||
| 73 | _private: (), | ||
| 74 | } | ||
| 75 | |||
| 76 | static POWER_WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 77 | |||
| 78 | impl HardwareVbusDetect { | ||
| 79 | /// Create a new `VbusDetectNative`. | ||
| 80 | pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self { | ||
| 81 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 82 | |||
| 83 | UsbRegIrq::unpend(); | ||
| 84 | unsafe { UsbRegIrq::enable() }; | ||
| 85 | |||
| 86 | regs.intenset | ||
| 87 | .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); | ||
| 88 | |||
| 89 | Self { _private: () } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | impl VbusDetect for HardwareVbusDetect { | ||
| 94 | fn is_usb_detected(&self) -> bool { | ||
| 95 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 96 | regs.usbregstatus.read().vbusdetect().is_vbus_present() | ||
| 97 | } | ||
| 98 | |||
| 99 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 100 | poll_fn(move |cx| { | ||
| 101 | POWER_WAKER.register(cx.waker()); | ||
| 102 | let regs = unsafe { &*UsbRegPeri::ptr() }; | ||
| 103 | |||
| 104 | if regs.usbregstatus.read().outputrdy().is_ready() { | ||
| 105 | Poll::Ready(Ok(())) | ||
| 106 | } else if !self.is_usb_detected() { | ||
| 107 | Poll::Ready(Err(())) | ||
| 108 | } else { | ||
| 109 | Poll::Pending | ||
| 110 | } | ||
| 111 | }) | ||
| 112 | .await | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Software-backed [`VbusDetect`] implementation. | ||
| 117 | /// | ||
| 118 | /// This implementation does not interact with the hardware, it allows user code | ||
| 119 | /// to notify the power events by calling functions instead. | ||
| 120 | /// | ||
| 121 | /// This is suitable for use with the nRF softdevice, by calling the functions | ||
| 122 | /// when the softdevice reports power-related events. | ||
| 123 | pub struct SoftwareVbusDetect { | ||
| 124 | usb_detected: AtomicBool, | ||
| 125 | power_ready: AtomicBool, | ||
| 126 | } | ||
| 127 | |||
| 128 | impl SoftwareVbusDetect { | ||
| 129 | /// Create a new `SoftwareVbusDetect`. | ||
| 130 | pub fn new(usb_detected: bool, power_ready: bool) -> Self { | ||
| 131 | BUS_WAKER.wake(); | ||
| 132 | |||
| 133 | Self { | ||
| 134 | usb_detected: AtomicBool::new(usb_detected), | ||
| 135 | power_ready: AtomicBool::new(power_ready), | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /// Report whether power was detected. | ||
| 140 | /// | ||
| 141 | /// Equivalent to the `USBDETECTED`, `USBREMOVED` events from the `POWER` peripheral. | ||
| 142 | pub fn detected(&self, detected: bool) { | ||
| 143 | self.usb_detected.store(detected, Ordering::Relaxed); | ||
| 144 | self.power_ready.store(false, Ordering::Relaxed); | ||
| 145 | BUS_WAKER.wake(); | ||
| 146 | POWER_WAKER.wake(); | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Report when USB power is ready. | ||
| 150 | /// | ||
| 151 | /// Equivalent to the `USBPWRRDY` event from the `POWER` peripheral. | ||
| 152 | pub fn ready(&self) { | ||
| 153 | self.power_ready.store(true, Ordering::Relaxed); | ||
| 154 | POWER_WAKER.wake(); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | impl VbusDetect for &SoftwareVbusDetect { | ||
| 159 | fn is_usb_detected(&self) -> bool { | ||
| 160 | self.usb_detected.load(Ordering::Relaxed) | ||
| 161 | } | ||
| 162 | |||
| 163 | async fn wait_power_ready(&mut self) -> Result<(), ()> { | ||
| 164 | poll_fn(move |cx| { | ||
| 165 | POWER_WAKER.register(cx.waker()); | ||
| 166 | |||
| 167 | if self.power_ready.load(Ordering::Relaxed) { | ||
| 168 | Poll::Ready(Ok(())) | ||
| 169 | } else if !self.usb_detected.load(Ordering::Relaxed) { | ||
| 170 | Poll::Ready(Err(())) | ||
| 171 | } else { | ||
| 172 | Poll::Pending | ||
| 173 | } | ||
| 174 | }) | ||
| 175 | .await | ||
| 176 | } | ||
| 177 | } | ||
diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index 8760aa301..40a674424 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! HAL interface to the WDT peripheral. | 1 | //! Watchdog Timer (WDT) driver. |
| 2 | //! | 2 | //! |
| 3 | //! This HAL implements a basic watchdog timer with 1..=8 handles. | 3 | //! This HAL implements a basic watchdog timer with 1..=8 handles. |
| 4 | //! Once the watchdog has been started, it cannot be stopped. | 4 | //! Once the watchdog has been started, it cannot be stopped. |
| @@ -8,6 +8,7 @@ use crate::peripherals; | |||
| 8 | 8 | ||
| 9 | const MIN_TICKS: u32 = 15; | 9 | const MIN_TICKS: u32 = 15; |
| 10 | 10 | ||
| 11 | /// WDT configuration. | ||
| 11 | #[non_exhaustive] | 12 | #[non_exhaustive] |
| 12 | pub struct Config { | 13 | pub struct Config { |
| 13 | /// Number of 32768 Hz ticks in each watchdog period. | 14 | /// Number of 32768 Hz ticks in each watchdog period. |
| @@ -23,6 +24,30 @@ pub struct Config { | |||
| 23 | pub run_during_debug_halt: bool, | 24 | pub run_during_debug_halt: bool, |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 27 | impl Config { | ||
| 28 | /// Create a config structure from the current configuration of the WDT | ||
| 29 | /// peripheral. | ||
| 30 | pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> { | ||
| 31 | let r = unsafe { &*WDT::ptr() }; | ||
| 32 | |||
| 33 | #[cfg(not(feature = "_nrf9160"))] | ||
| 34 | let runstatus = r.runstatus.read().runstatus().bit(); | ||
| 35 | #[cfg(feature = "_nrf9160")] | ||
| 36 | let runstatus = r.runstatus.read().runstatuswdt().bit(); | ||
| 37 | |||
| 38 | if runstatus { | ||
| 39 | let config = r.config.read(); | ||
| 40 | Some(Self { | ||
| 41 | timeout_ticks: r.crv.read().bits(), | ||
| 42 | run_during_sleep: config.sleep().bit(), | ||
| 43 | run_during_debug_halt: config.halt().bit(), | ||
| 44 | }) | ||
| 45 | } else { | ||
| 46 | None | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 26 | impl Default for Config { | 51 | impl Default for Config { |
| 27 | fn default() -> Self { | 52 | fn default() -> Self { |
| 28 | Self { | 53 | Self { |
| @@ -33,13 +58,13 @@ impl Default for Config { | |||
| 33 | } | 58 | } |
| 34 | } | 59 | } |
| 35 | 60 | ||
| 36 | /// An interface to the Watchdog. | 61 | /// Watchdog driver. |
| 37 | pub struct Watchdog { | 62 | pub struct Watchdog { |
| 38 | _private: (), | 63 | _private: (), |
| 39 | } | 64 | } |
| 40 | 65 | ||
| 41 | impl Watchdog { | 66 | impl Watchdog { |
| 42 | /// Try to create a new watchdog instance from the peripheral. | 67 | /// Try to create a new watchdog driver. |
| 43 | /// | 68 | /// |
| 44 | /// This function will return an error if the watchdog is already active | 69 | /// This function will return an error if the watchdog is already active |
| 45 | /// with a `config` different to the requested one, or a different number of | 70 | /// with a `config` different to the requested one, or a different number of |
| @@ -131,6 +156,7 @@ impl Watchdog { | |||
| 131 | } | 156 | } |
| 132 | } | 157 | } |
| 133 | 158 | ||
| 159 | /// Watchdog handle. | ||
| 134 | pub struct WatchdogHandle { | 160 | pub struct WatchdogHandle { |
| 135 | index: u8, | 161 | index: u8, |
| 136 | } | 162 | } |
