aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-01-14 00:07:02 +0000
committerGitHub <[email protected]>2023-01-14 00:07:02 +0000
commitb6c8505697f198b95545f352f6a94af24276b128 (patch)
tree301135a48027fe8f22ec74f65950e291a2dacd5a
parentb0c8c688c7458785826c60a3afb05c3338d70427 (diff)
parent539f97da535edaf7607890658b21223ff6e02cdf (diff)
Merge #1142
1142: More rp2040 BufferedUart fixes r=Dirbaio a=timokroeger * Refactor init code * Make it possible to drop RX without breaking TX (or vice versa) * Correctly handle RX buffer full scenario Co-authored-by: Timo Kröger <[email protected]>
-rw-r--r--embassy-hal-common/src/atomic_ring_buffer.rs4
-rw-r--r--embassy-rp/src/uart/buffered.rs339
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
3 files changed, 156 insertions, 189 deletions
diff --git a/embassy-hal-common/src/atomic_ring_buffer.rs b/embassy-hal-common/src/atomic_ring_buffer.rs
index a8a6a2166..4c944d763 100644
--- a/embassy-hal-common/src/atomic_ring_buffer.rs
+++ b/embassy-hal-common/src/atomic_ring_buffer.rs
@@ -81,6 +81,10 @@ impl RingBuffer {
81 Writer(self) 81 Writer(self)
82 } 82 }
83 83
84 pub fn len(&self) -> usize {
85 self.len.load(Ordering::Relaxed)
86 }
87
84 pub fn is_full(&self) -> bool { 88 pub fn is_full(&self) -> bool {
85 let len = self.len.load(Ordering::Relaxed); 89 let len = self.len.load(Ordering::Relaxed);
86 let start = self.start.load(Ordering::Relaxed); 90 let start = self.start.load(Ordering::Relaxed);
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 1d1fe37c2..0da5bfca1 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -7,6 +7,7 @@ use embassy_hal_common::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::*; 9use super::*;
10use crate::RegExt;
10 11
11pub struct State { 12pub struct State {
12 tx_waker: AtomicWaker, 13 tx_waker: AtomicWaker,
@@ -27,7 +28,8 @@ impl State {
27} 28}
28 29
29pub struct BufferedUart<'d, T: Instance> { 30pub struct BufferedUart<'d, T: Instance> {
30 phantom: PhantomData<&'d mut T>, 31 rx: BufferedUartRx<'d, T>,
32 tx: BufferedUartTx<'d, T>,
31} 33}
32 34
33pub struct BufferedUartRx<'d, T: Instance> { 35pub struct BufferedUartRx<'d, T: Instance> {
@@ -38,6 +40,42 @@ pub struct BufferedUartTx<'d, T: Instance> {
38 phantom: PhantomData<&'d mut T>, 40 phantom: PhantomData<&'d mut T>,
39} 41}
40 42
43fn init<'d, T: Instance + 'd>(
44 irq: PeripheralRef<'d, T::Interrupt>,
45 tx: Option<PeripheralRef<'d, AnyPin>>,
46 rx: Option<PeripheralRef<'d, AnyPin>>,
47 rts: Option<PeripheralRef<'d, AnyPin>>,
48 cts: Option<PeripheralRef<'d, AnyPin>>,
49 tx_buffer: &'d mut [u8],
50 rx_buffer: &'d mut [u8],
51 config: Config,
52) {
53 super::Uart::<'d, T, Async>::init(tx, rx, rts, cts, config);
54
55 let state = T::state();
56 let len = tx_buffer.len();
57 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
58 let len = rx_buffer.len();
59 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
60
61 // From the datasheet:
62 // "The transmit interrupt is based on a transition through a level, rather
63 // than on the level itself. When the interrupt and the UART is enabled
64 // before any data is written to the transmit FIFO the interrupt is not set.
65 // The interrupt is only set, after written data leaves the single location
66 // of the transmit FIFO and it becomes empty."
67 //
68 // This means we can leave the interrupt enabled the whole time as long as
69 // we clear it after it happens. The downside is that the we manually have
70 // to pend the ISR when we want data transmission to start.
71 let regs = T::regs();
72 unsafe { regs.uartimsc().write_set(|w| w.set_txim(true)) };
73
74 irq.set_handler(on_interrupt::<T>);
75 irq.unpend();
76 irq.enable();
77}
78
41impl<'d, T: Instance> BufferedUart<'d, T> { 79impl<'d, T: Instance> BufferedUart<'d, T> {
42 pub fn new( 80 pub fn new(
43 _uart: impl Peripheral<P = T> + 'd, 81 _uart: impl Peripheral<P = T> + 'd,
@@ -48,17 +86,21 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
48 rx_buffer: &'d mut [u8], 86 rx_buffer: &'d mut [u8],
49 config: Config, 87 config: Config,
50 ) -> Self { 88 ) -> Self {
51 into_ref!(tx, rx); 89 into_ref!(irq, tx, rx);
52 Self::new_inner( 90 init::<T>(
53 irq, 91 irq,
54 tx.map_into(), 92 Some(tx.map_into()),
55 rx.map_into(), 93 Some(rx.map_into()),
56 None, 94 None,
57 None, 95 None,
58 tx_buffer, 96 tx_buffer,
59 rx_buffer, 97 rx_buffer,
60 config, 98 config,
61 ) 99 );
100 Self {
101 rx: BufferedUartRx { phantom: PhantomData },
102 tx: BufferedUartTx { phantom: PhantomData },
103 }
62 } 104 }
63 105
64 pub fn new_with_rtscts( 106 pub fn new_with_rtscts(
@@ -72,66 +114,25 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
72 rx_buffer: &'d mut [u8], 114 rx_buffer: &'d mut [u8],
73 config: Config, 115 config: Config,
74 ) -> Self { 116 ) -> Self {
75 into_ref!(tx, rx, cts, rts); 117 into_ref!(irq, tx, rx, cts, rts);
76 Self::new_inner( 118 init::<T>(
77 irq, 119 irq,
78 tx.map_into(), 120 Some(tx.map_into()),
79 rx.map_into(), 121 Some(rx.map_into()),
80 Some(rts.map_into()), 122 Some(rts.map_into()),
81 Some(cts.map_into()), 123 Some(cts.map_into()),
82 tx_buffer, 124 tx_buffer,
83 rx_buffer, 125 rx_buffer,
84 config, 126 config,
85 )
86 }
87
88 fn new_inner(
89 irq: impl Peripheral<P = T::Interrupt> + 'd,
90 mut tx: PeripheralRef<'d, AnyPin>,
91 mut rx: PeripheralRef<'d, AnyPin>,
92 mut rts: Option<PeripheralRef<'d, AnyPin>>,
93 mut cts: Option<PeripheralRef<'d, AnyPin>>,
94 tx_buffer: &'d mut [u8],
95 rx_buffer: &'d mut [u8],
96 config: Config,
97 ) -> Self {
98 into_ref!(irq);
99 super::Uart::<'d, T, Async>::init(
100 Some(tx.reborrow()),
101 Some(rx.reborrow()),
102 rts.as_mut().map(|x| x.reborrow()),
103 cts.as_mut().map(|x| x.reborrow()),
104 config,
105 ); 127 );
106 128 Self {
107 let state = T::state(); 129 rx: BufferedUartRx { phantom: PhantomData },
108 let regs = T::regs(); 130 tx: BufferedUartTx { phantom: PhantomData },
109
110 let len = tx_buffer.len();
111 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
112 let len = rx_buffer.len();
113 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
114
115 unsafe {
116 regs.uartimsc().modify(|w| {
117 w.set_rxim(true);
118 w.set_rtim(true);
119 w.set_txim(true);
120 });
121 } 131 }
122
123 irq.set_handler(on_interrupt::<T>);
124 irq.unpend();
125 irq.enable();
126
127 Self { phantom: PhantomData }
128 } 132 }
129 133
130 pub fn split(&mut self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { 134 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) {
131 ( 135 (self.rx, self.tx)
132 BufferedUartRx { phantom: PhantomData },
133 BufferedUartTx { phantom: PhantomData },
134 )
135 } 136 }
136} 137}
137 138
@@ -143,8 +144,9 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
143 rx_buffer: &'d mut [u8], 144 rx_buffer: &'d mut [u8],
144 config: Config, 145 config: Config,
145 ) -> Self { 146 ) -> Self {
146 into_ref!(rx); 147 into_ref!(irq, rx);
147 Self::new_inner(irq, rx.map_into(), None, rx_buffer, config) 148 init::<T>(irq, None, Some(rx.map_into()), None, None, &mut [], rx_buffer, config);
149 Self { phantom: PhantomData }
148 } 150 }
149 151
150 pub fn new_with_rts( 152 pub fn new_with_rts(
@@ -155,43 +157,17 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
155 rx_buffer: &'d mut [u8], 157 rx_buffer: &'d mut [u8],
156 config: Config, 158 config: Config,
157 ) -> Self { 159 ) -> Self {
158 into_ref!(rx, rts); 160 into_ref!(irq, rx, rts);
159 Self::new_inner(irq, rx.map_into(), Some(rts.map_into()), rx_buffer, config) 161 init::<T>(
160 } 162 irq,
161
162 fn new_inner(
163 irq: impl Peripheral<P = T::Interrupt> + 'd,
164 mut rx: PeripheralRef<'d, AnyPin>,
165 mut rts: Option<PeripheralRef<'d, AnyPin>>,
166 rx_buffer: &'d mut [u8],
167 config: Config,
168 ) -> Self {
169 into_ref!(irq);
170 super::Uart::<'d, T, Async>::init(
171 None, 163 None,
172 Some(rx.reborrow()), 164 Some(rx.map_into()),
173 rts.as_mut().map(|x| x.reborrow()), 165 Some(rts.map_into()),
174 None, 166 None,
167 &mut [],
168 rx_buffer,
175 config, 169 config,
176 ); 170 );
177
178 let state = T::state();
179 let regs = T::regs();
180
181 let len = rx_buffer.len();
182 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
183
184 unsafe {
185 regs.uartimsc().modify(|w| {
186 w.set_rxim(true);
187 w.set_rtim(true);
188 });
189 }
190
191 irq.set_handler(on_interrupt::<T>);
192 irq.unpend();
193 irq.enable();
194
195 Self { phantom: PhantomData } 171 Self { phantom: PhantomData }
196 } 172 }
197 173
@@ -209,6 +185,16 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
209 return Poll::Pending; 185 return Poll::Pending;
210 } 186 }
211 187
188 // (Re-)Enable the interrupt to receive more data in case it was
189 // disabled because the buffer was full.
190 let regs = T::regs();
191 unsafe {
192 regs.uartimsc().write_set(|w| {
193 w.set_rxim(true);
194 w.set_rtim(true);
195 });
196 }
197
212 Poll::Ready(Ok(n)) 198 Poll::Ready(Ok(n))
213 }) 199 })
214 } 200 }
@@ -231,7 +217,17 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
231 fn consume(amt: usize) { 217 fn consume(amt: usize) {
232 let state = T::state(); 218 let state = T::state();
233 let mut rx_reader = unsafe { state.rx_buf.reader() }; 219 let mut rx_reader = unsafe { state.rx_buf.reader() };
234 rx_reader.pop_done(amt) 220 rx_reader.pop_done(amt);
221
222 // (Re-)Enable the interrupt to receive more data in case it was
223 // disabled because the buffer was full.
224 let regs = T::regs();
225 unsafe {
226 regs.uartimsc().write_set(|w| {
227 w.set_rxim(true);
228 w.set_rtim(true);
229 });
230 }
235 } 231 }
236} 232}
237 233
@@ -243,8 +239,9 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
243 tx_buffer: &'d mut [u8], 239 tx_buffer: &'d mut [u8],
244 config: Config, 240 config: Config,
245 ) -> Self { 241 ) -> Self {
246 into_ref!(tx); 242 into_ref!(irq, tx);
247 Self::new_inner(irq, tx.map_into(), None, tx_buffer, config) 243 init::<T>(irq, Some(tx.map_into()), None, None, None, tx_buffer, &mut [], config);
244 Self { phantom: PhantomData }
248 } 245 }
249 246
250 pub fn new_with_cts( 247 pub fn new_with_cts(
@@ -255,42 +252,17 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
255 tx_buffer: &'d mut [u8], 252 tx_buffer: &'d mut [u8],
256 config: Config, 253 config: Config,
257 ) -> Self { 254 ) -> Self {
258 into_ref!(tx, cts); 255 into_ref!(irq, tx, cts);
259 Self::new_inner(irq, tx.map_into(), Some(cts.map_into()), tx_buffer, config) 256 init::<T>(
260 } 257 irq,
261 258 Some(tx.map_into()),
262 fn new_inner(
263 irq: impl Peripheral<P = T::Interrupt> + 'd,
264 mut tx: PeripheralRef<'d, AnyPin>,
265 mut cts: Option<PeripheralRef<'d, AnyPin>>,
266 tx_buffer: &'d mut [u8],
267 config: Config,
268 ) -> Self {
269 into_ref!(irq);
270 super::Uart::<'d, T, Async>::init(
271 Some(tx.reborrow()),
272 None, 259 None,
273 None, 260 None,
274 cts.as_mut().map(|x| x.reborrow()), 261 Some(cts.map_into()),
262 tx_buffer,
263 &mut [],
275 config, 264 config,
276 ); 265 );
277
278 let state = T::state();
279 let regs = T::regs();
280
281 let len = tx_buffer.len();
282 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
283
284 unsafe {
285 regs.uartimsc().modify(|w| {
286 w.set_txim(true);
287 });
288 }
289
290 irq.set_handler(on_interrupt::<T>);
291 irq.unpend();
292 irq.enable();
293
294 Self { phantom: PhantomData } 266 Self { phantom: PhantomData }
295 } 267 }
296 268
@@ -306,10 +278,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
306 if n == 0 { 278 if n == 0 {
307 state.tx_waker.register(cx.waker()); 279 state.tx_waker.register(cx.waker());
308 return Poll::Pending; 280 return Poll::Pending;
309 } else {
310 unsafe { T::Interrupt::steal() }.pend();
311 } 281 }
312 282
283 // The TX interrupt only triggers when the there was data in the
284 // FIFO and the number of bytes drops below a threshold. When the
285 // FIFO was empty we have to manually pend the interrupt to shovel
286 // TX data from the buffer into the FIFO.
287 unsafe { T::Interrupt::steal() }.pend();
313 Poll::Ready(Ok(n)) 288 Poll::Ready(Ok(n))
314 }) 289 })
315 } 290 }
@@ -327,80 +302,69 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
327 } 302 }
328} 303}
329 304
330impl<'d, T: Instance> Drop for BufferedUart<'d, T> {
331 fn drop(&mut self) {
332 unsafe {
333 T::Interrupt::steal().disable();
334 let state = T::state();
335 state.tx_buf.deinit();
336 state.rx_buf.deinit();
337 }
338 }
339}
340
341impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 305impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
342 fn drop(&mut self) { 306 fn drop(&mut self) {
307 let state = T::state();
343 unsafe { 308 unsafe {
344 T::Interrupt::steal().disable();
345 let state = T::state();
346 state.tx_buf.deinit();
347 state.rx_buf.deinit(); 309 state.rx_buf.deinit();
310
311 // TX is inactive if the the buffer is not available.
312 // We can now unregister the interrupt handler
313 if state.tx_buf.len() == 0 {
314 T::Interrupt::steal().disable();
315 }
348 } 316 }
349 } 317 }
350} 318}
351 319
352impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { 320impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
353 fn drop(&mut self) { 321 fn drop(&mut self) {
322 let state = T::state();
354 unsafe { 323 unsafe {
355 T::Interrupt::steal().disable();
356 let state = T::state();
357 state.tx_buf.deinit(); 324 state.tx_buf.deinit();
358 state.rx_buf.deinit(); 325
326 // RX is inactive if the the buffer is not available.
327 // We can now unregister the interrupt handler
328 if state.rx_buf.len() == 0 {
329 T::Interrupt::steal().disable();
330 }
359 } 331 }
360 } 332 }
361} 333}
362 334
363pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) { 335pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
364 trace!("on_interrupt");
365
366 let r = T::regs(); 336 let r = T::regs();
367 let s = T::state(); 337 let s = T::state();
368 338
369 unsafe { 339 unsafe {
370 // RX 340 // Clear TX and error interrupt flags
371 341 // RX interrupt flags are cleared by reading from the FIFO.
372 let ris = r.uartris().read(); 342 let ris = r.uartris().read();
373 // Clear interrupt flags
374 r.uarticr().write(|w| { 343 r.uarticr().write(|w| {
375 w.set_rxic(true); 344 w.set_txic(ris.txris());
376 w.set_rtic(true); 345 w.set_feic(ris.feris());
346 w.set_peic(ris.peris());
347 w.set_beic(ris.beris());
348 w.set_oeic(ris.oeris());
377 }); 349 });
378 350
379 if ris.peris() { 351 trace!("on_interrupt ris={:#X}", ris.0);
380 warn!("Parity error"); 352
381 r.uarticr().write(|w| { 353 // Errors
382 w.set_peic(true);
383 });
384 }
385 if ris.feris() { 354 if ris.feris() {
386 warn!("Framing error"); 355 warn!("Framing error");
387 r.uarticr().write(|w| { 356 }
388 w.set_feic(true); 357 if ris.peris() {
389 }); 358 warn!("Parity error");
390 } 359 }
391 if ris.beris() { 360 if ris.beris() {
392 warn!("Break error"); 361 warn!("Break error");
393 r.uarticr().write(|w| {
394 w.set_beic(true);
395 });
396 } 362 }
397 if ris.oeris() { 363 if ris.oeris() {
398 warn!("Overrun error"); 364 warn!("Overrun error");
399 r.uarticr().write(|w| {
400 w.set_oeic(true);
401 });
402 } 365 }
403 366
367 // RX
404 let mut rx_writer = s.rx_buf.writer(); 368 let mut rx_writer = s.rx_buf.writer();
405 let rx_buf = rx_writer.push_slice(); 369 let rx_buf = rx_writer.push_slice();
406 let mut n_read = 0; 370 let mut n_read = 0;
@@ -415,33 +379,32 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
415 rx_writer.push_done(n_read); 379 rx_writer.push_done(n_read);
416 s.rx_waker.wake(); 380 s.rx_waker.wake();
417 } 381 }
382 // Disable any further RX interrupts when the buffer becomes full.
383 if s.rx_buf.is_full() {
384 r.uartimsc().write_clear(|w| {
385 w.set_rxim(true);
386 w.set_rtim(true);
387 });
388 }
418 389
419 // TX 390 // TX
420 let mut tx_reader = s.tx_buf.reader(); 391 let mut tx_reader = s.tx_buf.reader();
421 let tx_buf = tx_reader.pop_slice(); 392 let tx_buf = tx_reader.pop_slice();
422 if tx_buf.len() == 0 { 393 let mut n_written = 0;
423 // Disable interrupt until we have something to transmit again 394 for tx_byte in tx_buf.iter_mut() {
424 r.uartimsc().modify(|w| { 395 if r.uartfr().read().txff() {
425 w.set_txim(false); 396 break;
426 });
427 } else {
428 r.uartimsc().modify(|w| {
429 w.set_txim(true);
430 });
431
432 let mut n_written = 0;
433 for tx_byte in tx_buf.iter_mut() {
434 if r.uartfr().read().txff() {
435 break;
436 }
437 r.uartdr().write(|w| w.set_data(*tx_byte));
438 n_written += 1;
439 }
440 if n_written > 0 {
441 tx_reader.pop_done(n_written);
442 s.tx_waker.wake();
443 } 397 }
398 r.uartdr().write(|w| w.set_data(*tx_byte));
399 n_written += 1;
400 }
401 if n_written > 0 {
402 tx_reader.pop_done(n_written);
403 s.tx_waker.wake();
444 } 404 }
405 // The TX interrupt only triggers once when the FIFO threshold is
406 // crossed. No need to disable it when the buffer becomes empty
407 // as it does re-trigger anymore once we have cleared it.
445 } 408 }
446} 409}
447 410
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index 36f31c906..a8a682274 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -29,7 +29,7 @@ async fn main(spawner: Spawner) {
29 let irq = interrupt::take!(UART0_IRQ); 29 let irq = interrupt::take!(UART0_IRQ);
30 let tx_buf = &mut singleton!([0u8; 16])[..]; 30 let tx_buf = &mut singleton!([0u8; 16])[..];
31 let rx_buf = &mut singleton!([0u8; 16])[..]; 31 let rx_buf = &mut singleton!([0u8; 16])[..];
32 let mut uart = BufferedUart::new(uart, irq, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 32 let uart = BufferedUart::new(uart, irq, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
33 let (rx, mut tx) = uart.split(); 33 let (rx, mut tx) = uart.split();
34 34
35 unwrap!(spawner.spawn(reader(rx))); 35 unwrap!(spawner.spawn(reader(rx)));