aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-03-04 05:27:29 +0100
committerDario Nieuwenhuis <[email protected]>2023-03-04 15:12:49 +0100
commitccc224c81ff1a56296576f4a249fe91a37c03fd8 (patch)
tree694360261ff6d07bbc4f61835f6f1ec1b631bdc4 /embassy-nrf
parent51478caad843e4b0be1d1baf83d1f0e8c0d96a30 (diff)
nrf/buffered_uarte: remove PeripheralMutex, make it work without rts/cts.
> dirbaio: so I was checking how zephyr does UARTE RX on nRF > dirbaio: because currently we have the ugly "restart DMA on line idle to flush it" hack > dirbaio: because according to the docs "For each byte received over the RXD line, an RXDRDY event will be generated. This event is likely to occur before the corresponding data has been transferred to Data RAM." > dirbaio: so as I understood it, the only way to guarantee the data is actually transferred to RAM is to stop+restart DMA > dirbaio: well, guess what? > dirbaio: they just count RXDRDY's, and process that amount of data without restarting DMA > dirbaio: with a timer configured as counter https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/serial/uart_nrfx_uarte.c#L650-L692 > dirbaio: 🤔🤷⁉️ > dirbaio: someone saying you can do the "hook up rxdrdy to a counter" trick, someone else saying it's wrong 🤪 https://devzone.nordicsemi.com/f/nordic-q-a/28420/uarte-in-circular-mode So we're going to do just that! - BufferedUarte is lock-free now. No PeripheralMutex. - The "restart DMA on line idle to flush it" hack is GONE. This means - It'll work correctly without RTS/CTS now. - It'll have better throughput when using RTS/CTS.
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/buffered_uarte.rs672
-rw-r--r--embassy-nrf/src/uarte.rs5
2 files changed, 378 insertions, 299 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
16use core::cell::RefCell;
17use core::cmp::min; 11use core::cmp::min;
18use core::future::poll_fn; 12use core::future::poll_fn;
19use core::sync::atomic::{compiler_fence, Ordering}; 13use core::slice;
14use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
20use core::task::Poll; 15use core::task::Poll;
21 16
22use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; 17use embassy_cortex_m::interrupt::Interrupt;
23use embassy_hal_common::ring_buffer::RingBuffer; 18use embassy_hal_common::atomic_ring_buffer::RingBuffer;
24use embassy_hal_common::{into_ref, PeripheralRef}; 19use embassy_hal_common::{into_ref, PeripheralRef};
25use embassy_sync::waitqueue::WakerRegistration; 20use 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
27pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 22pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
28 23
29use crate::gpio::{self, Pin as GpioPin}; 24use crate::gpio::sealed::Pin;
25use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
30use crate::interrupt::InterruptExt; 26use crate::interrupt::InterruptExt;
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 27use crate::ppi::{
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 28 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
29};
30use crate::timer::{Instance as TimerInstance, Timer};
33use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; 31use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
34use crate::{pac, Peripheral}; 32use crate::{pac, Peripheral};
35 33
36#[derive(Copy, Clone, Debug, PartialEq)] 34mod sealed {
37enum RxState { 35 use super::*;
38 Idle,
39 Receiving,
40}
41 36
42#[derive(Copy, Clone, Debug, PartialEq)] 37 pub struct State {
43enum 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,
49pub struct State<'d, U: UarteInstance, T: TimerInstance>(StateStorage<StateInner<'d, U, T>>); 43 pub rx_buf: RingBuffer,
50impl<'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
57struct StateInner<'d, U: UarteInstance, T: TimerInstance> { 49pub(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>, 51impl 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.
73pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 67pub 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
77impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} 75impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {}
78 76
79impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { 77impl<'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
400impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> { 571impl<'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
424impl<'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;