diff options
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 672 | ||||
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 5 | ||||
| -rw-r--r-- | examples/nrf52840/src/bin/buffered_uart.rs | 12 |
3 files changed, 381 insertions, 308 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 112f084c1..79f9a1f78 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -1,10 +1,5 @@ | |||
| 1 | //! Async buffered UART driver. | 1 | //! Async buffered UART driver. |
| 2 | //! | 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 | //! | ||
| 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 |
| 10 | //! on the "other" future, you should capture the incomplete future and continue to use | 5 | //! on the "other" future, you should capture the incomplete future and continue to use |
| @@ -13,82 +8,120 @@ | |||
| 13 | //! | 8 | //! |
| 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::cell::RefCell; | ||
| 17 | use core::cmp::min; | 11 | use core::cmp::min; |
| 18 | use core::future::poll_fn; | 12 | use core::future::poll_fn; |
| 19 | use core::sync::atomic::{compiler_fence, Ordering}; | 13 | use core::slice; |
| 14 | use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering}; | ||
| 20 | use core::task::Poll; | 15 | use core::task::Poll; |
| 21 | 16 | ||
| 22 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 17 | use embassy_cortex_m::interrupt::Interrupt; |
| 23 | use embassy_hal_common::ring_buffer::RingBuffer; | 18 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 24 | use embassy_hal_common::{into_ref, PeripheralRef}; | 19 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 25 | use embassy_sync::waitqueue::WakerRegistration; | 20 | use embassy_sync::waitqueue::AtomicWaker; |
| 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::{self, Pin as GpioPin}; | 24 | use crate::gpio::sealed::Pin; |
| 25 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | ||
| 30 | use crate::interrupt::InterruptExt; | 26 | use crate::interrupt::InterruptExt; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 27 | use crate::ppi::{ |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 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::{pac, Peripheral}; |
| 35 | 33 | ||
| 36 | #[derive(Copy, Clone, Debug, PartialEq)] | 34 | mod sealed { |
| 37 | enum RxState { | 35 | use super::*; |
| 38 | Idle, | ||
| 39 | Receiving, | ||
| 40 | } | ||
| 41 | 36 | ||
| 42 | #[derive(Copy, Clone, Debug, PartialEq)] | 37 | pub struct State { |
| 43 | enum TxState { | 38 | pub tx_waker: AtomicWaker, |
| 44 | Idle, | 39 | pub tx_buf: RingBuffer, |
| 45 | Transmitting(usize), | 40 | pub tx_count: AtomicUsize, |
| 46 | } | ||
| 47 | 41 | ||
| 48 | /// A type for storing the state of the UARTE peripheral that can be stored in a static. | 42 | pub rx_waker: AtomicWaker, |
| 49 | pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>); | 43 | pub rx_buf: RingBuffer, |
| 50 | impl<'d, U: UarteInstance, T: TimerInstance> State<'d, U, T> { | 44 | pub rx_bufs: AtomicU8, |
| 51 | /// Create an instance for storing UARTE peripheral state. | 45 | pub rx_ppi_ch: AtomicU8, |
| 52 | pub fn new() -> Self { | ||
| 53 | Self(StateStorage::new()) | ||
| 54 | } | 46 | } |
| 55 | } | 47 | } |
| 56 | 48 | ||
| 57 | struct StateInner<'d, U: UarteInstance, T: TimerInstance> { | 49 | pub(crate) use sealed::State; |
| 58 | _peri: PeripheralRef<'d, U>, | ||
| 59 | timer: Timer<'d, T>, | ||
| 60 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, | ||
| 61 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, | ||
| 62 | |||
| 63 | rx: RingBuffer<'d>, | ||
| 64 | rx_state: RxState, | ||
| 65 | rx_waker: WakerRegistration, | ||
| 66 | 50 | ||
| 67 | tx: RingBuffer<'d>, | 51 | impl State { |
| 68 | tx_state: TxState, | 52 | pub(crate) const fn new() -> Self { |
| 69 | tx_waker: WakerRegistration, | 53 | Self { |
| 54 | tx_waker: AtomicWaker::new(), | ||
| 55 | tx_buf: RingBuffer::new(), | ||
| 56 | tx_count: AtomicUsize::new(0), | ||
| 57 | |||
| 58 | rx_waker: AtomicWaker::new(), | ||
| 59 | rx_buf: RingBuffer::new(), | ||
| 60 | rx_bufs: AtomicU8::new(0), | ||
| 61 | rx_ppi_ch: AtomicU8::new(0), | ||
| 62 | } | ||
| 63 | } | ||
| 70 | } | 64 | } |
| 71 | 65 | ||
| 72 | /// Buffered UARTE driver. | 66 | /// Buffered UARTE driver. |
| 73 | pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { | 67 | pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { |
| 74 | inner: RefCell<PeripheralMutex<'d, StateInner<'d, U, T>>>, | 68 | _peri: PeripheralRef<'d, U>, |
| 69 | timer: Timer<'d, T>, | ||
| 70 | _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, | ||
| 71 | _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, | ||
| 72 | _ppi_group: PpiGroup<'d, AnyGroup>, | ||
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} | 75 | impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} |
| 78 | 76 | ||
| 79 | impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | 77 | impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { |
| 80 | /// Create a new instance of a BufferedUarte. | 78 | /// Create a new BufferedUarte without hardware flow control. |
| 81 | /// | 79 | /// |
| 82 | /// See the [module documentation](crate::buffered_uarte) for more details about the intended use. | 80 | /// # Panics |
| 83 | /// | 81 | /// |
| 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 | 82 | /// Panics if `rx_buffer.len()` is odd. |
| 85 | /// can return early if there is no data to receive. | ||
| 86 | pub fn new( | 83 | pub fn new( |
| 87 | state: &'d mut State<'d, U, T>, | 84 | uarte: impl Peripheral<P = U> + 'd, |
| 88 | peri: impl Peripheral<P = U> + 'd, | 85 | timer: impl Peripheral<P = T> + 'd, |
| 86 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||
| 87 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, | ||
| 88 | ppi_group: impl Peripheral<P = impl Group> + 'd, | ||
| 89 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 90 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 91 | txd: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 92 | config: Config, | ||
| 93 | rx_buffer: &'d mut [u8], | ||
| 94 | tx_buffer: &'d mut [u8], | ||
| 95 | ) -> Self { | ||
| 96 | into_ref!(rxd, txd, ppi_ch1, ppi_ch2, ppi_group); | ||
| 97 | Self::new_inner( | ||
| 98 | uarte, | ||
| 99 | timer, | ||
| 100 | ppi_ch1.map_into(), | ||
| 101 | ppi_ch2.map_into(), | ||
| 102 | ppi_group.map_into(), | ||
| 103 | irq, | ||
| 104 | rxd.map_into(), | ||
| 105 | txd.map_into(), | ||
| 106 | None, | ||
| 107 | None, | ||
| 108 | config, | ||
| 109 | rx_buffer, | ||
| 110 | tx_buffer, | ||
| 111 | ) | ||
| 112 | } | ||
| 113 | |||
| 114 | /// Create a new BufferedUarte with hardware flow control (RTS/CTS) | ||
| 115 | /// | ||
| 116 | /// # Panics | ||
| 117 | /// | ||
| 118 | /// Panics if `rx_buffer.len()` is odd. | ||
| 119 | pub fn new_with_rtscts( | ||
| 120 | uarte: impl Peripheral<P = U> + 'd, | ||
| 89 | timer: impl Peripheral<P = T> + 'd, | 121 | timer: impl Peripheral<P = T> + 'd, |
| 90 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 122 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 91 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 123 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd, |
| 124 | ppi_group: impl Peripheral<P = impl Group> + 'd, | ||
| 92 | irq: impl Peripheral<P = U::Interrupt> + 'd, | 125 | irq: impl Peripheral<P = U::Interrupt> + 'd, |
| 93 | rxd: impl Peripheral<P = impl GpioPin> + 'd, | 126 | rxd: impl Peripheral<P = impl GpioPin> + 'd, |
| 94 | txd: impl Peripheral<P = impl GpioPin> + 'd, | 127 | txd: impl Peripheral<P = impl GpioPin> + 'd, |
| @@ -98,11 +131,44 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 98 | rx_buffer: &'d mut [u8], | 131 | rx_buffer: &'d mut [u8], |
| 99 | tx_buffer: &'d mut [u8], | 132 | tx_buffer: &'d mut [u8], |
| 100 | ) -> Self { | 133 | ) -> Self { |
| 101 | into_ref!(peri, ppi_ch1, ppi_ch2, irq, rxd, txd, cts, rts); | 134 | into_ref!(rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); |
| 135 | Self::new_inner( | ||
| 136 | uarte, | ||
| 137 | timer, | ||
| 138 | ppi_ch1.map_into(), | ||
| 139 | ppi_ch2.map_into(), | ||
| 140 | ppi_group.map_into(), | ||
| 141 | irq, | ||
| 142 | rxd.map_into(), | ||
| 143 | txd.map_into(), | ||
| 144 | Some(cts.map_into()), | ||
| 145 | Some(rts.map_into()), | ||
| 146 | config, | ||
| 147 | rx_buffer, | ||
| 148 | tx_buffer, | ||
| 149 | ) | ||
| 150 | } | ||
| 102 | 151 | ||
| 103 | let r = U::regs(); | 152 | fn new_inner( |
| 153 | peri: impl Peripheral<P = U> + 'd, | ||
| 154 | timer: impl Peripheral<P = T> + 'd, | ||
| 155 | ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, | ||
| 156 | ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, | ||
| 157 | ppi_group: PeripheralRef<'d, AnyGroup>, | ||
| 158 | irq: impl Peripheral<P = U::Interrupt> + 'd, | ||
| 159 | rxd: PeripheralRef<'d, AnyPin>, | ||
| 160 | txd: PeripheralRef<'d, AnyPin>, | ||
| 161 | cts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 162 | rts: Option<PeripheralRef<'d, AnyPin>>, | ||
| 163 | config: Config, | ||
| 164 | rx_buffer: &'d mut [u8], | ||
| 165 | tx_buffer: &'d mut [u8], | ||
| 166 | ) -> Self { | ||
| 167 | into_ref!(peri, timer, irq); | ||
| 168 | |||
| 169 | assert!(rx_buffer.len() % 2 == 0); | ||
| 104 | 170 | ||
| 105 | let mut timer = Timer::new(timer); | 171 | let r = U::regs(); |
| 106 | 172 | ||
| 107 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); | 173 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); |
| 108 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | 174 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); |
| @@ -111,92 +177,200 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 111 | txd.conf().write(|w| w.dir().output().drive().h0h1()); | 177 | txd.conf().write(|w| w.dir().output().drive().h0h1()); |
| 112 | r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | 178 | r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); |
| 113 | 179 | ||
| 114 | cts.conf().write(|w| w.input().connect().drive().h0h1()); | 180 | if let Some(pin) = &cts { |
| 181 | pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 182 | } | ||
| 115 | r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | 183 | r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); |
| 116 | 184 | ||
| 117 | rts.set_high(); | 185 | if let Some(pin) = &rts { |
| 118 | rts.conf().write(|w| w.dir().output().drive().h0h1()); | 186 | pin.set_high(); |
| 187 | pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||
| 188 | } | ||
| 119 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | 189 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); |
| 120 | 190 | ||
| 121 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | 191 | // Initialize state |
| 122 | r.config.write(|w| w.parity().variant(config.parity)); | 192 | let s = U::buffered_state(); |
| 193 | s.tx_count.store(0, Ordering::Relaxed); | ||
| 194 | s.rx_bufs.store(0, Ordering::Relaxed); | ||
| 195 | let len = tx_buffer.len(); | ||
| 196 | unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; | ||
| 197 | let len = rx_buffer.len(); | ||
| 198 | unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; | ||
| 123 | 199 | ||
| 124 | // Configure | 200 | // Configure |
| 125 | r.config.write(|w| { | 201 | r.config.write(|w| { |
| 126 | w.hwfc().bit(true); | 202 | w.hwfc().bit(false); |
| 127 | w.parity().variant(config.parity); | 203 | w.parity().variant(config.parity); |
| 128 | w | 204 | w |
| 129 | }); | 205 | }); |
| 130 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | 206 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); |
| 131 | 207 | ||
| 132 | // Enable interrupts | 208 | // clear errors |
| 133 | r.intenset.write(|w| w.endrx().set().endtx().set()); | 209 | let errors = r.errorsrc.read().bits(); |
| 210 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 134 | 211 | ||
| 135 | // Disable the irq, let the Registration enable it when everything is set up. | 212 | r.events_rxstarted.reset(); |
| 136 | irq.disable(); | 213 | r.events_txstarted.reset(); |
| 137 | irq.pend(); | 214 | r.events_error.reset(); |
| 215 | r.events_endrx.reset(); | ||
| 216 | r.events_endtx.reset(); | ||
| 217 | |||
| 218 | // Enable interrupts | ||
| 219 | r.intenclr.write(|w| unsafe { w.bits(!0) }); | ||
| 220 | r.intenset.write(|w| { | ||
| 221 | w.endtx().set(); | ||
| 222 | w.rxstarted().set(); | ||
| 223 | w.error().set(); | ||
| 224 | w | ||
| 225 | }); | ||
| 138 | 226 | ||
| 139 | // Enable UARTE instance | 227 | // Enable UARTE instance |
| 140 | apply_workaround_for_enable_anomaly(&r); | 228 | apply_workaround_for_enable_anomaly(&r); |
| 141 | r.enable.write(|w| w.enable().enabled()); | 229 | r.enable.write(|w| w.enable().enabled()); |
| 142 | 230 | ||
| 143 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | 231 | // Configure byte counter. |
| 144 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | 232 | let mut timer = Timer::new_counter(timer); |
| 145 | // | 233 | 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 | 234 | timer.cc(1).short_compare_clear(); |
| 147 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | 235 | timer.clear(); |
| 148 | // This gives us the amount of 16M ticks for 20 bits. | 236 | timer.start(); |
| 149 | let timeout = 0x8000_0000 / (config.baudrate as u32 / 40); | ||
| 150 | |||
| 151 | timer.set_frequency(Frequency::F16MHz); | ||
| 152 | timer.cc(0).write(timeout); | ||
| 153 | timer.cc(0).short_compare_clear(); | ||
| 154 | timer.cc(0).short_compare_stop(); | ||
| 155 | 237 | ||
| 156 | let mut ppi_ch1 = Ppi::new_one_to_two( | 238 | let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); |
| 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(); | 239 | ppi_ch1.enable(); |
| 163 | 240 | ||
| 164 | let mut ppi_ch2 = Ppi::new_one_to_one( | 241 | s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); |
| 165 | ppi_ch2.map_into(), | 242 | let mut ppi_group = PpiGroup::new(ppi_group); |
| 166 | timer.cc(0).event_compare(), | 243 | let mut ppi_ch2 = Ppi::new_one_to_two( |
| 167 | Task::from_reg(&r.tasks_stoprx), | 244 | ppi_ch2, |
| 245 | Event::from_reg(&r.events_endrx), | ||
| 246 | Task::from_reg(&r.tasks_startrx), | ||
| 247 | ppi_group.task_disable_all(), | ||
| 168 | ); | 248 | ); |
| 169 | ppi_ch2.enable(); | 249 | ppi_ch2.disable(); |
| 250 | ppi_group.add_channel(&ppi_ch2); | ||
| 251 | |||
| 252 | irq.disable(); | ||
| 253 | irq.set_handler(Self::on_interrupt); | ||
| 254 | irq.pend(); | ||
| 255 | irq.enable(); | ||
| 170 | 256 | ||
| 171 | Self { | 257 | Self { |
| 172 | inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner { | 258 | _peri: peri, |
| 173 | _peri: peri, | 259 | timer, |
| 174 | timer, | 260 | _ppi_ch1: ppi_ch1, |
| 175 | _ppi_ch1: ppi_ch1, | 261 | _ppi_ch2: ppi_ch2, |
| 176 | _ppi_ch2: ppi_ch2, | 262 | _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 | } | 263 | } |
| 187 | } | 264 | } |
| 188 | 265 | ||
| 189 | /// Adjust the baud rate to the provided value. | 266 | fn pend_irq() { |
| 190 | pub fn set_baudrate(&mut self, baudrate: Baudrate) { | 267 | unsafe { <U::Interrupt as Interrupt>::steal() }.pend() |
| 191 | self.inner.borrow_mut().with(|state| { | 268 | } |
| 192 | let r = U::regs(); | ||
| 193 | 269 | ||
| 194 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | 270 | fn on_interrupt(_: *mut ()) { |
| 195 | state.timer.cc(0).write(timeout); | 271 | //trace!("irq: start"); |
| 196 | state.timer.clear(); | 272 | let r = U::regs(); |
| 273 | let s = U::buffered_state(); | ||
| 197 | 274 | ||
| 198 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); | 275 | let buf_len = s.rx_buf.len(); |
| 199 | }); | 276 | let half_len = buf_len / 2; |
| 277 | let mut tx = unsafe { s.tx_buf.reader() }; | ||
| 278 | let mut rx = unsafe { s.rx_buf.writer() }; | ||
| 279 | |||
| 280 | if r.events_error.read().bits() != 0 { | ||
| 281 | r.events_error.reset(); | ||
| 282 | let errs = r.errorsrc.read(); | ||
| 283 | r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); | ||
| 284 | |||
| 285 | if errs.overrun().bit() { | ||
| 286 | panic!("BufferedUarte overrun"); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | // Received some bytes, wake task. | ||
| 291 | if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().events_rxdrdy().bit_is_set() { | ||
| 292 | r.intenclr.write(|w| w.rxdrdy().clear()); | ||
| 293 | r.events_rxdrdy.reset(); | ||
| 294 | s.rx_waker.wake(); | ||
| 295 | } | ||
| 296 | |||
| 297 | // If not RXing, start. | ||
| 298 | if s.rx_bufs.load(Ordering::Relaxed) == 0 { | ||
| 299 | let (ptr, len) = rx.push_buf(); | ||
| 300 | if len >= half_len { | ||
| 301 | //trace!(" irq_rx: starting {:?}", half_len); | ||
| 302 | s.rx_bufs.store(1, Ordering::Relaxed); | ||
| 303 | |||
| 304 | // Set up the DMA read | ||
| 305 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 306 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); | ||
| 307 | |||
| 308 | // Start UARTE Receive transaction | ||
| 309 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 310 | rx.push_done(half_len); | ||
| 311 | r.intenset.write(|w| w.rxstarted().set()); | ||
| 312 | } | ||
| 313 | } | ||
| 314 | |||
| 315 | if r.events_rxstarted.read().bits() != 0 { | ||
| 316 | //trace!(" irq_rx: rxstarted"); | ||
| 317 | let (ptr, len) = rx.push_buf(); | ||
| 318 | if len >= half_len { | ||
| 319 | //trace!(" irq_rx: starting second {:?}", half_len); | ||
| 320 | |||
| 321 | // Set up the DMA read | ||
| 322 | r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 323 | r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); | ||
| 324 | |||
| 325 | let chn = s.rx_ppi_ch.load(Ordering::Relaxed); | ||
| 326 | |||
| 327 | ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); | ||
| 328 | |||
| 329 | rx.push_done(half_len); | ||
| 330 | |||
| 331 | r.events_rxstarted.reset(); | ||
| 332 | } else { | ||
| 333 | //trace!(" irq_rx: rxstarted no buf"); | ||
| 334 | r.intenclr.write(|w| w.rxstarted().clear()); | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | // ============================= | ||
| 339 | |||
| 340 | // TX end | ||
| 341 | if r.events_endtx.read().bits() != 0 { | ||
| 342 | r.events_endtx.reset(); | ||
| 343 | |||
| 344 | let n = s.tx_count.load(Ordering::Relaxed); | ||
| 345 | //trace!(" irq_tx: endtx {:?}", n); | ||
| 346 | tx.pop_done(n); | ||
| 347 | s.tx_waker.wake(); | ||
| 348 | s.tx_count.store(0, Ordering::Relaxed); | ||
| 349 | } | ||
| 350 | |||
| 351 | // If not TXing, start. | ||
| 352 | if s.tx_count.load(Ordering::Relaxed) == 0 { | ||
| 353 | let (ptr, len) = tx.pop_buf(); | ||
| 354 | if len != 0 { | ||
| 355 | //trace!(" irq_tx: starting {:?}", len); | ||
| 356 | s.tx_count.store(len, Ordering::Relaxed); | ||
| 357 | |||
| 358 | // Set up the DMA write | ||
| 359 | r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); | ||
| 360 | r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); | ||
| 361 | |||
| 362 | // Start UARTE Transmit transaction | ||
| 363 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | //trace!("irq: end"); | ||
| 368 | } | ||
| 369 | |||
| 370 | /// Adjust the baud rate to the provided value. | ||
| 371 | pub fn set_baudrate(&mut self, baudrate: Baudrate) { | ||
| 372 | let r = U::regs(); | ||
| 373 | r.baudrate.write(|w| w.baudrate().variant(baudrate)); | ||
| 200 | } | 374 | } |
| 201 | 375 | ||
| 202 | /// Split the UART in reader and writer parts. | 376 | /// Split the UART in reader and writer parts. |
| @@ -206,120 +380,117 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 206 | (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) | 380 | (BufferedUarteRx { inner: self }, BufferedUarteTx { inner: self }) |
| 207 | } | 381 | } |
| 208 | 382 | ||
| 209 | async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, core::convert::Infallible> { | 383 | async fn inner_read(&self, buf: &mut [u8]) -> Result<usize, core::convert::Infallible> { |
| 210 | poll_fn(move |cx| { | 384 | let data = self.inner_fill_buf().await?; |
| 211 | let mut do_pend = false; | 385 | let n = data.len().min(buf.len()); |
| 212 | let mut inner = self.inner.borrow_mut(); | 386 | buf[..n].copy_from_slice(&data[..n]); |
| 213 | let res = inner.with(|state| { | 387 | self.inner_consume(n); |
| 214 | compiler_fence(Ordering::SeqCst); | 388 | Ok(n) |
| 215 | trace!("poll_read"); | ||
| 216 | |||
| 217 | // We have data ready in buffer? Return it. | ||
| 218 | let data = state.rx.pop_buf(); | ||
| 219 | if !data.is_empty() { | ||
| 220 | trace!(" got {:?} {:?}", data.as_ptr() as u32, data.len()); | ||
| 221 | let len = data.len().min(buf.len()); | ||
| 222 | buf[..len].copy_from_slice(&data[..len]); | ||
| 223 | state.rx.pop(len); | ||
| 224 | do_pend = true; | ||
| 225 | return Poll::Ready(Ok(len)); | ||
| 226 | } | ||
| 227 | |||
| 228 | trace!(" empty"); | ||
| 229 | state.rx_waker.register(cx.waker()); | ||
| 230 | Poll::Pending | ||
| 231 | }); | ||
| 232 | if do_pend { | ||
| 233 | inner.pend(); | ||
| 234 | } | ||
| 235 | |||
| 236 | res | ||
| 237 | }) | ||
| 238 | .await | ||
| 239 | } | 389 | } |
| 240 | 390 | ||
| 241 | async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, core::convert::Infallible> { | 391 | async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, core::convert::Infallible> { |
| 242 | poll_fn(move |cx| { | 392 | poll_fn(move |cx| { |
| 243 | let mut inner = self.inner.borrow_mut(); | 393 | //trace!("poll_write: {:?}", buf.len()); |
| 244 | let res = inner.with(|state| { | 394 | let s = U::buffered_state(); |
| 245 | trace!("poll_write: {:?}", buf.len()); | 395 | let mut tx = unsafe { s.tx_buf.writer() }; |
| 246 | 396 | ||
| 247 | let tx_buf = state.tx.push_buf(); | 397 | let tx_buf = tx.push_slice(); |
| 248 | if tx_buf.is_empty() { | 398 | if tx_buf.is_empty() { |
| 249 | trace!("poll_write: pending"); | 399 | //trace!("poll_write: pending"); |
| 250 | state.tx_waker.register(cx.waker()); | 400 | s.tx_waker.register(cx.waker()); |
| 251 | return Poll::Pending; | 401 | return Poll::Pending; |
| 252 | } | 402 | } |
| 253 | |||
| 254 | let n = min(tx_buf.len(), buf.len()); | ||
| 255 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 256 | state.tx.push(n); | ||
| 257 | |||
| 258 | trace!("poll_write: queued {:?}", n); | ||
| 259 | 403 | ||
| 260 | compiler_fence(Ordering::SeqCst); | 404 | let n = min(tx_buf.len(), buf.len()); |
| 405 | tx_buf[..n].copy_from_slice(&buf[..n]); | ||
| 406 | tx.push_done(n); | ||
| 261 | 407 | ||
| 262 | Poll::Ready(Ok(n)) | 408 | //trace!("poll_write: queued {:?}", n); |
| 263 | }); | ||
| 264 | 409 | ||
| 265 | inner.pend(); | 410 | compiler_fence(Ordering::SeqCst); |
| 411 | Self::pend_irq(); | ||
| 266 | 412 | ||
| 267 | res | 413 | Poll::Ready(Ok(n)) |
| 268 | }) | 414 | }) |
| 269 | .await | 415 | .await |
| 270 | } | 416 | } |
| 271 | 417 | ||
| 272 | async fn inner_flush<'a>(&'a self) -> Result<(), core::convert::Infallible> { | 418 | async fn inner_flush<'a>(&'a self) -> Result<(), core::convert::Infallible> { |
| 273 | poll_fn(move |cx| { | 419 | poll_fn(move |cx| { |
| 274 | self.inner.borrow_mut().with(|state| { | 420 | //trace!("poll_flush"); |
| 275 | trace!("poll_flush"); | 421 | let s = U::buffered_state(); |
| 276 | 422 | if !s.tx_buf.is_empty() { | |
| 277 | if !state.tx.is_empty() { | 423 | //trace!("poll_flush: pending"); |
| 278 | trace!("poll_flush: pending"); | 424 | s.tx_waker.register(cx.waker()); |
| 279 | state.tx_waker.register(cx.waker()); | 425 | return Poll::Pending; |
| 280 | return Poll::Pending; | 426 | } |
| 281 | } | ||
| 282 | 427 | ||
| 283 | Poll::Ready(Ok(())) | 428 | Poll::Ready(Ok(())) |
| 284 | }) | ||
| 285 | }) | 429 | }) |
| 286 | .await | 430 | .await |
| 287 | } | 431 | } |
| 288 | 432 | ||
| 289 | async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], core::convert::Infallible> { | 433 | async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], core::convert::Infallible> { |
| 290 | poll_fn(move |cx| { | 434 | poll_fn(move |cx| { |
| 291 | self.inner.borrow_mut().with(|state| { | 435 | compiler_fence(Ordering::SeqCst); |
| 292 | compiler_fence(Ordering::SeqCst); | 436 | //trace!("poll_read"); |
| 293 | trace!("fill_buf"); | 437 | |
| 294 | 438 | let r = U::regs(); | |
| 295 | // We have data ready in buffer? Return it. | 439 | let s = U::buffered_state(); |
| 296 | let buf = state.rx.pop_buf(); | 440 | |
| 297 | if !buf.is_empty() { | 441 | // Read the RXDRDY counter. |
| 298 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | 442 | T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); |
| 299 | let buf: &[u8] = buf; | 443 | let mut end = T::regs().cc[0].read().bits() as usize; |
| 300 | // Safety: buffer lives as long as uart | 444 | //trace!(" rxdrdy count = {:?}", end); |
| 301 | let buf: &[u8] = unsafe { core::mem::transmute(buf) }; | 445 | |
| 302 | return Poll::Ready(Ok(buf)); | 446 | // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. |
| 303 | } | 447 | // However, it's unclear if that's instant, or there's a small window where you can |
| 304 | 448 | // still read `len()*2`. | |
| 305 | trace!(" empty"); | 449 | // This could happen if in one clock cycle the counter is updated, and in the next the |
| 306 | state.rx_waker.register(cx.waker()); | 450 | // clear takes effect. The docs are very sparse, they just say "Task delays: After TIMER |
| 307 | Poll::<Result<&[u8], core::convert::Infallible>>::Pending | 451 | // is started, the CLEAR, COUNT, and STOP tasks are guaranteed to take effect within one |
| 308 | }) | 452 | // clock cycle of the PCLK16M." :shrug: |
| 453 | // So, we wrap the counter ourselves, just in case. | ||
| 454 | if end > s.rx_buf.len() * 2 { | ||
| 455 | end = 0 | ||
| 456 | } | ||
| 457 | |||
| 458 | // This logic mirrors `atomic_ring_buffer::Reader::pop_buf()` | ||
| 459 | let mut start = s.rx_buf.start.load(Ordering::Relaxed); | ||
| 460 | let len = s.rx_buf.len(); | ||
| 461 | if start == end { | ||
| 462 | //trace!(" empty"); | ||
| 463 | s.rx_waker.register(cx.waker()); | ||
| 464 | r.intenset.write(|w| w.rxdrdy().set_bit()); | ||
| 465 | return Poll::Pending; | ||
| 466 | } | ||
| 467 | |||
| 468 | if start >= len { | ||
| 469 | start -= len | ||
| 470 | } | ||
| 471 | if end >= len { | ||
| 472 | end -= len | ||
| 473 | } | ||
| 474 | |||
| 475 | let n = if end > start { end - start } else { len - start }; | ||
| 476 | assert!(n != 0); | ||
| 477 | //trace!(" uarte ringbuf: pop_buf {:?}..{:?}", start, start + n); | ||
| 478 | |||
| 479 | let buf = s.rx_buf.buf.load(Ordering::Relaxed); | ||
| 480 | Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) })) | ||
| 309 | }) | 481 | }) |
| 310 | .await | 482 | .await |
| 311 | } | 483 | } |
| 312 | 484 | ||
| 313 | fn inner_consume(&self, amt: usize) { | 485 | fn inner_consume(&self, amt: usize) { |
| 314 | let mut inner = self.inner.borrow_mut(); | 486 | if amt == 0 { |
| 315 | let signal = inner.with(|state| { | 487 | return; |
| 316 | let full = state.rx.is_full(); | ||
| 317 | state.rx.pop(amt); | ||
| 318 | full | ||
| 319 | }); | ||
| 320 | if signal { | ||
| 321 | inner.pend(); | ||
| 322 | } | 488 | } |
| 489 | |||
| 490 | let s = U::buffered_state(); | ||
| 491 | let mut rx = unsafe { s.rx_buf.reader() }; | ||
| 492 | rx.pop_done(amt); | ||
| 493 | U::regs().intenset.write(|w| w.rxstarted().set()); | ||
| 323 | } | 494 | } |
| 324 | } | 495 | } |
| 325 | 496 | ||
| @@ -397,7 +568,7 @@ impl<'u, 'd: 'u, U: UarteInstance, T: TimerInstance> embedded_io::asynch::Write | |||
| 397 | } | 568 | } |
| 398 | } | 569 | } |
| 399 | 570 | ||
| 400 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { | 571 | impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarte<'a, U, T> { |
| 401 | fn drop(&mut self) { | 572 | fn drop(&mut self) { |
| 402 | let r = U::regs(); | 573 | let r = U::regs(); |
| 403 | 574 | ||
| @@ -418,108 +589,11 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { | |||
| 418 | gpio::deconfigure_pin(r.psel.txd.read().bits()); | 589 | gpio::deconfigure_pin(r.psel.txd.read().bits()); |
| 419 | gpio::deconfigure_pin(r.psel.rts.read().bits()); | 590 | gpio::deconfigure_pin(r.psel.rts.read().bits()); |
| 420 | gpio::deconfigure_pin(r.psel.cts.read().bits()); | 591 | gpio::deconfigure_pin(r.psel.cts.read().bits()); |
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a, U, T> { | ||
| 425 | type Interrupt = U::Interrupt; | ||
| 426 | fn on_interrupt(&mut self) { | ||
| 427 | trace!("irq: start"); | ||
| 428 | let r = U::regs(); | ||
| 429 | 592 | ||
| 430 | loop { | 593 | let s = U::buffered_state(); |
| 431 | match self.rx_state { | 594 | unsafe { |
| 432 | RxState::Idle => { | 595 | s.rx_buf.deinit(); |
| 433 | trace!(" irq_rx: in state idle"); | 596 | s.tx_buf.deinit(); |
| 434 | |||
| 435 | let buf = self.rx.push_buf(); | ||
| 436 | if !buf.is_empty() { | ||
| 437 | trace!(" irq_rx: starting {:?}", buf.len()); | ||
| 438 | self.rx_state = RxState::Receiving; | ||
| 439 | |||
| 440 | // Set up the DMA read | ||
| 441 | r.rxd.ptr.write(|w| | ||
| 442 | // The PTR field is a full 32 bits wide and accepts the full range | ||
| 443 | // of values. | ||
| 444 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | ||
| 445 | r.rxd.maxcnt.write(|w| | ||
| 446 | // We're giving it the length of the buffer, so no danger of | ||
| 447 | // accessing invalid memory. We have verified that the length of the | ||
| 448 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||
| 449 | // | ||
| 450 | // The MAXCNT field is at least 8 bits wide and accepts the full | ||
| 451 | // range of values. | ||
| 452 | unsafe { w.maxcnt().bits(buf.len() as _) }); | ||
| 453 | trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); | ||
| 454 | |||
| 455 | // Start UARTE Receive transaction | ||
| 456 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 457 | } | ||
| 458 | break; | ||
| 459 | } | ||
| 460 | RxState::Receiving => { | ||
| 461 | trace!(" irq_rx: in state receiving"); | ||
| 462 | if r.events_endrx.read().bits() != 0 { | ||
| 463 | self.timer.stop(); | ||
| 464 | |||
| 465 | let n: usize = r.rxd.amount.read().amount().bits() as usize; | ||
| 466 | trace!(" irq_rx: endrx {:?}", n); | ||
| 467 | self.rx.push(n); | ||
| 468 | |||
| 469 | r.events_endrx.reset(); | ||
| 470 | |||
| 471 | self.rx_waker.wake(); | ||
| 472 | self.rx_state = RxState::Idle; | ||
| 473 | } else { | ||
| 474 | break; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 480 | loop { | ||
| 481 | match self.tx_state { | ||
| 482 | TxState::Idle => { | ||
| 483 | trace!(" irq_tx: in state Idle"); | ||
| 484 | let buf = self.tx.pop_buf(); | ||
| 485 | if !buf.is_empty() { | ||
| 486 | trace!(" irq_tx: starting {:?}", buf.len()); | ||
| 487 | self.tx_state = TxState::Transmitting(buf.len()); | ||
| 488 | |||
| 489 | // Set up the DMA write | ||
| 490 | r.txd.ptr.write(|w| | ||
| 491 | // The PTR field is a full 32 bits wide and accepts the full range | ||
| 492 | // of values. | ||
| 493 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | ||
| 494 | r.txd.maxcnt.write(|w| | ||
| 495 | // We're giving it the length of the buffer, so no danger of | ||
| 496 | // accessing invalid memory. We have verified that the length of the | ||
| 497 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | ||
| 498 | // | ||
| 499 | // The MAXCNT field is 8 bits wide and accepts the full range of | ||
| 500 | // values. | ||
| 501 | unsafe { w.maxcnt().bits(buf.len() as _) }); | ||
| 502 | |||
| 503 | // Start UARTE Transmit transaction | ||
| 504 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 505 | } | ||
| 506 | break; | ||
| 507 | } | ||
| 508 | TxState::Transmitting(n) => { | ||
| 509 | trace!(" irq_tx: in state Transmitting"); | ||
| 510 | if r.events_endtx.read().bits() != 0 { | ||
| 511 | r.events_endtx.reset(); | ||
| 512 | |||
| 513 | trace!(" irq_tx: endtx {:?}", n); | ||
| 514 | self.tx.pop(n); | ||
| 515 | self.tx_waker.wake(); | ||
| 516 | self.tx_state = TxState::Idle; | ||
| 517 | } else { | ||
| 518 | break; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | } | ||
| 522 | } | 597 | } |
| 523 | trace!("irq: end"); | ||
| 524 | } | 598 | } |
| 525 | } | 599 | } |
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 48457744b..00afbd059 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -883,6 +883,7 @@ pub(crate) mod sealed { | |||
| 883 | pub trait Instance { | 883 | pub trait Instance { |
| 884 | fn regs() -> &'static pac::uarte0::RegisterBlock; | 884 | fn regs() -> &'static pac::uarte0::RegisterBlock; |
| 885 | fn state() -> &'static State; | 885 | fn state() -> &'static State; |
| 886 | fn buffered_state() -> &'static crate::buffered_uarte::State; | ||
| 886 | } | 887 | } |
| 887 | } | 888 | } |
| 888 | 889 | ||
| @@ -902,6 +903,10 @@ macro_rules! impl_uarte { | |||
| 902 | static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); | 903 | static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); |
| 903 | &STATE | 904 | &STATE |
| 904 | } | 905 | } |
| 906 | fn buffered_state() -> &'static crate::buffered_uarte::State { | ||
| 907 | static STATE: crate::buffered_uarte::State = crate::buffered_uarte::State::new(); | ||
| 908 | &STATE | ||
| 909 | } | ||
| 905 | } | 910 | } |
| 906 | impl crate::uarte::Instance for peripherals::$type { | 911 | impl crate::uarte::Instance for peripherals::$type { |
| 907 | type Interrupt = crate::interrupt::$irq; | 912 | type Interrupt = crate::interrupt::$irq; |
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs index ea566f4b2..584e6b2bc 100644 --- a/examples/nrf52840/src/bin/buffered_uart.rs +++ b/examples/nrf52840/src/bin/buffered_uart.rs | |||
| @@ -4,10 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_nrf::buffered_uarte::{BufferedUarte, State}; | 7 | use embassy_nrf::buffered_uarte::BufferedUarte; |
| 8 | use embassy_nrf::{interrupt, uarte}; | 8 | use embassy_nrf::{interrupt, uarte}; |
| 9 | use embedded_io::asynch::{BufRead, Write}; | 9 | use embedded_io::asynch::{BufRead, Write}; |
| 10 | use futures::pin_mut; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 11 | ||
| 13 | #[embassy_executor::main] | 12 | #[embassy_executor::main] |
| @@ -21,24 +20,19 @@ async fn main(_spawner: Spawner) { | |||
| 21 | let mut rx_buffer = [0u8; 4096]; | 20 | let mut rx_buffer = [0u8; 4096]; |
| 22 | 21 | ||
| 23 | let irq = interrupt::take!(UARTE0_UART0); | 22 | let irq = interrupt::take!(UARTE0_UART0); |
| 24 | let mut state = State::new(); | 23 | let mut u = BufferedUarte::new( |
| 25 | // Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536) | ||
| 26 | let u = BufferedUarte::new( | ||
| 27 | &mut state, | ||
| 28 | p.UARTE0, | 24 | p.UARTE0, |
| 29 | p.TIMER0, | 25 | p.TIMER0, |
| 30 | p.PPI_CH0, | 26 | p.PPI_CH0, |
| 31 | p.PPI_CH1, | 27 | p.PPI_CH1, |
| 28 | p.PPI_GROUP0, | ||
| 32 | irq, | 29 | irq, |
| 33 | p.P0_08, | 30 | p.P0_08, |
| 34 | p.P0_06, | 31 | p.P0_06, |
| 35 | p.P0_07, | ||
| 36 | p.P0_05, | ||
| 37 | config, | 32 | config, |
| 38 | &mut rx_buffer, | 33 | &mut rx_buffer, |
| 39 | &mut tx_buffer, | 34 | &mut tx_buffer, |
| 40 | ); | 35 | ); |
| 41 | pin_mut!(u); | ||
| 42 | 36 | ||
| 43 | info!("uarte initialized!"); | 37 | info!("uarte initialized!"); |
| 44 | 38 | ||
