aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2023-12-20 14:14:14 +0100
committerJames Munns <[email protected]>2024-01-19 14:02:17 +0100
commit24fc12667dc3b929d4fef633cdf0c1ada9765484 (patch)
tree208c410dcda2d42ecb7ae344c604e10187f7f874
parent9fd49fb9d675f858691491a57ab50dd049168def (diff)
Update with more docs and less panics
-rw-r--r--embassy-rp/src/uart/mod.rs118
1 files changed, 95 insertions, 23 deletions
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 3488d6c73..a89cb5932 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -116,6 +116,10 @@ pub enum Error {
116 Parity, 116 Parity,
117 /// Triggered when the received character didn't have a valid stop bit. 117 /// Triggered when the received character didn't have a valid stop bit.
118 Framing, 118 Framing,
119 /// There was an issue when calculating the number of transferred items
120 /// in an aborted DMA transaction. This is likely an error in the
121 /// driver implementation, please open an embassy issue.
122 Calculation,
119} 123}
120 124
121/// Internal DMA state of UART RX. 125/// Internal DMA state of UART RX.
@@ -275,13 +279,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
275 /// Read from UART RX blocking execution until done. 279 /// Read from UART RX blocking execution until done.
276 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 280 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
277 while buffer.len() > 0 { 281 while buffer.len() > 0 {
278 let received = self.drain_fifo(buffer)?; 282 let received = self.drain_fifo(buffer).map_err(|(_i, e)| e)?;
279 buffer = &mut buffer[received..]; 283 buffer = &mut buffer[received..];
280 } 284 }
281 Ok(()) 285 Ok(())
282 } 286 }
283 287
284 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 288 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
285 let r = T::regs(); 289 let r = T::regs();
286 for (i, b) in buffer.iter_mut().enumerate() { 290 for (i, b) in buffer.iter_mut().enumerate() {
287 if r.uartfr().read().rxfe() { 291 if r.uartfr().read().rxfe() {
@@ -291,13 +295,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
291 let dr = r.uartdr().read(); 295 let dr = r.uartdr().read();
292 296
293 if dr.oe() { 297 if dr.oe() {
294 return Err(Error::Overrun); 298 return Err((i, Error::Overrun));
295 } else if dr.be() { 299 } else if dr.be() {
296 return Err(Error::Break); 300 return Err((i, Error::Break));
297 } else if dr.pe() { 301 } else if dr.pe() {
298 return Err(Error::Parity); 302 return Err((i, Error::Parity));
299 } else if dr.fe() { 303 } else if dr.fe() {
300 return Err(Error::Framing); 304 return Err((i, Error::Framing));
301 } else { 305 } else {
302 *b = dr.data(); 306 *b = dr.data();
303 } 307 }
@@ -389,7 +393,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
389 } { 393 } {
390 Ok(len) if len < buffer.len() => &mut buffer[len..], 394 Ok(len) if len < buffer.len() => &mut buffer[len..],
391 Ok(_) => return Ok(()), 395 Ok(_) => return Ok(()),
392 Err(e) => return Err(e), 396 Err((_i, e)) => return Err(e),
393 }; 397 };
394 398
395 // start a dma transfer. if errors have happened in the interim some error 399 // start a dma transfer. if errors have happened in the interim some error
@@ -425,14 +429,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
425 ) 429 )
426 .await; 430 .await;
427 431
432 let mut did_finish = false;
428 let errors = match transfer_result { 433 let errors = match transfer_result {
429 Either::First(()) => return Ok(()), 434 Either::First(()) => {
430 Either::Second(e) => e, 435 // We're here because the DMA finished, BUT if an error occurred on the LAST
436 // byte, then we may still need to grab the error state!
437 did_finish = true;
438 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
439 }
440 Either::Second(e) => {
441 // We're here because we errored, which means this is the error that
442 // was problematic.
443 e
444 }
431 }; 445 };
432 446
447 // If we got no error, just return at this point
433 if errors.0 == 0 { 448 if errors.0 == 0 {
434 return Ok(()); 449 return Ok(());
435 } else if errors.oeris() { 450 }
451
452 // If we DID get an error, and DID finish, we'll have one error byte left in the FIFO.
453 // Pop it since we are reporting the error on THIS transaction.
454 if did_finish {
455 let _ = T::regs().uartdr().read();
456 }
457
458 if errors.oeris() {
436 return Err(Error::Overrun); 459 return Err(Error::Overrun);
437 } else if errors.beris() { 460 } else if errors.beris() {
438 return Err(Error::Break); 461 return Err(Error::Break);
@@ -444,6 +467,14 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
444 unreachable!("unrecognized rx error"); 467 unreachable!("unrecognized rx error");
445 } 468 }
446 469
470 /// Read from the UART, until one of the following occurs:
471 ///
472 /// * We read `buffer.len()` bytes without a line break
473 /// * returns `Ok(buffer)`
474 /// * We read `n` bytes then a line break occurs
475 /// * returns `Ok(&mut buffer[..n])`
476 /// * We encounter some error OTHER than a line break
477 /// * returns `Err(Error)`
447 pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> { 478 pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> {
448 // clear error flags before we drain the fifo. errors that have accumulated 479 // clear error flags before we drain the fifo. errors that have accumulated
449 // in the flags will also be present in the fifo. 480 // in the flags will also be present in the fifo.
@@ -461,9 +492,14 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
461 let limit = buffer.len().min(32); 492 let limit = buffer.len().min(32);
462 self.drain_fifo(&mut buffer[0..limit]) 493 self.drain_fifo(&mut buffer[0..limit])
463 } { 494 } {
495 // Drained fifo, still some room left!
464 Ok(len) if len < buffer.len() => &mut buffer[len..], 496 Ok(len) if len < buffer.len() => &mut buffer[len..],
497 // Drained (some/all of the fifo), no room left
465 Ok(_) => return Ok(buffer), 498 Ok(_) => return Ok(buffer),
466 Err(e) => return Err(e), 499 // We got a break WHILE draining the FIFO, return what we did get before the break
500 Err((i, Error::Break)) => return Ok(&mut buffer[..i]),
501 // Some other error, just return the error
502 Err((_i, e)) => return Err(e),
467 }; 503 };
468 504
469 // start a dma transfer. if errors have happened in the interim some error 505 // start a dma transfer. if errors have happened in the interim some error
@@ -499,27 +535,62 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
499 ) 535 )
500 .await; 536 .await;
501 537
538 let mut did_finish = false;
539
540 // Figure out our error state
502 let errors = match transfer_result { 541 let errors = match transfer_result {
503 Either::First(()) => return Ok(buffer), 542 Either::First(()) => {
504 Either::Second(e) => e, 543 // We're here because the DMA finished, BUT if an error occurred on the LAST
544 // byte, then we may still need to grab the error state!
545 did_finish = true;
546 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
547 }
548 Either::Second(e) => {
549 // We're here because we errored, which means this is the error that
550 // was problematic.
551 e
552 }
505 }; 553 };
506 554
507 if errors.0 == 0 { 555 if errors.0 == 0 {
556 // No errors? That means we filled the buffer without a line break.
508 return Ok(buffer); 557 return Ok(buffer);
509 } else if errors.oeris() {
510 return Err(Error::Overrun);
511 } else if errors.beris() { 558 } else if errors.beris() {
512 // Begin "James is a chicken" region - I'm not certain if there is ever 559 // We got a Line Break! By this point, we've finished/aborted the DMA
513 // a case where the write addr WOULDN'T exist between the start and end. 560 // transaction, which means that we need to figure out where it left off
514 // This assert checks that and hasn't fired (yet). 561 // by looking at the write_addr.
562 //
563 // First, we do a sanity check to make sure the write value is within the
564 // range of DMA we just did.
515 let sval = buffer.as_ptr() as usize; 565 let sval = buffer.as_ptr() as usize;
516 let eval = sval + buffer.len(); 566 let eval = sval + buffer.len();
517 // Note: the `write_addr()` is where the NEXT write would be, BUT we also 567
518 // received one extra byte that represents the line break. 568 // Note: the `write_addr()` is where the NEXT write would be.
519 let val = ch.regs().write_addr().read() as usize - 1; 569 let mut last_written = ch.regs().write_addr().read() as usize;
520 assert!((val >= sval) && (val <= eval)); 570
521 let taken = val - sval; 571 // Did we finish the whole DMA transfer?
572 if !did_finish {
573 // No, we did not! We stopped because we got a line break. That means the
574 // DMA transferred one "garbage byte" from the FIFO that held an error.
575 last_written -= 1;
576 } else {
577 // We did finish and got a "late break", where the interrupt error fired AFTER
578 // we got the last byte. Pop that from the FIFO so we don't trip on it next time.
579 let dr = T::regs().uartdr().read();
580 if !dr.be() {
581 // Got an error after DMA but no error in the FIFO?
582 return Err(Error::Calculation);
583 }
584 }
585
586 // If we DON'T end up inside the range, something has gone really wrong.
587 if (last_written < sval) || (last_written > eval) {
588 return Err(Error::Calculation);
589 }
590 let taken = last_written - sval;
522 return Ok(&mut buffer[..taken]); 591 return Ok(&mut buffer[..taken]);
592 } else if errors.oeris() {
593 return Err(Error::Overrun);
523 } else if errors.peris() { 594 } else if errors.peris() {
524 return Err(Error::Parity); 595 return Err(Error::Parity);
525 } else if errors.feris() { 596 } else if errors.feris() {
@@ -930,6 +1001,7 @@ impl embedded_hal_nb::serial::Error for Error {
930 Self::Break => embedded_hal_nb::serial::ErrorKind::Other, 1001 Self::Break => embedded_hal_nb::serial::ErrorKind::Other,
931 Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, 1002 Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
932 Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, 1003 Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
1004 Self::Calculation => embedded_hal_nb::serial::ErrorKind::Other,
933 } 1005 }
934 } 1006 }
935} 1007}