diff options
| author | James Munns <[email protected]> | 2023-12-20 17:06:57 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2024-01-19 14:02:17 +0100 |
| commit | 94290981c359cfc4bb2355055a8a5d1497cf09aa (patch) | |
| tree | dfb535fcd8d8d456b3f747461d74f2ea42137f91 /embassy-rp/src | |
| parent | fe172109be8644b1e0d86735f4bd267ef7180c36 (diff) | |
Debugging RSR
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 128 |
1 files changed, 80 insertions, 48 deletions
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 998f7ccac..61d3af5de 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -116,10 +116,16 @@ 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 | 119 | } |
| 120 | /// in an aborted DMA transaction. This is likely an error in the | 120 | |
| 121 | /// driver implementation, please open an embassy issue. | 121 | /// Read To Break error |
| 122 | Calculation, | 122 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
| 123 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 124 | #[non_exhaustive] | ||
| 125 | pub enum ReadToBreakError { | ||
| 126 | /// Read this many bytes, but never received a line break. | ||
| 127 | MissingBreak(usize), | ||
| 128 | Other(Error), | ||
| 123 | } | 129 | } |
| 124 | 130 | ||
| 125 | /// Internal DMA state of UART RX. | 131 | /// Internal DMA state of UART RX. |
| @@ -432,12 +438,10 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 432 | ) | 438 | ) |
| 433 | .await; | 439 | .await; |
| 434 | 440 | ||
| 435 | let mut did_finish = false; | ||
| 436 | let errors = match transfer_result { | 441 | let errors = match transfer_result { |
| 437 | Either::First(()) => { | 442 | Either::First(()) => { |
| 438 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 443 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 439 | // byte, then we may still need to grab the error state! | 444 | // byte, then we may still need to grab the error state! |
| 440 | did_finish = true; | ||
| 441 | Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) | 445 | Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) |
| 442 | } | 446 | } |
| 443 | Either::Second(e) => { | 447 | Either::Second(e) => { |
| @@ -452,12 +456,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 452 | return Ok(()); | 456 | return Ok(()); |
| 453 | } | 457 | } |
| 454 | 458 | ||
| 455 | // If we DID get an error, and DID finish, we'll have one error byte left in the FIFO. | 459 | // If we DID get an error, we need to figure out which one it was. |
| 456 | // Pop it since we are reporting the error on THIS transaction. | ||
| 457 | if did_finish { | ||
| 458 | let _ = T::regs().uartdr().read(); | ||
| 459 | } | ||
| 460 | |||
| 461 | if errors.oeris() { | 460 | if errors.oeris() { |
| 462 | return Err(Error::Overrun); | 461 | return Err(Error::Overrun); |
| 463 | } else if errors.beris() { | 462 | } else if errors.beris() { |
| @@ -470,15 +469,27 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 470 | unreachable!("unrecognized rx error"); | 469 | unreachable!("unrecognized rx error"); |
| 471 | } | 470 | } |
| 472 | 471 | ||
| 473 | /// Read from the UART, until one of the following occurs: | 472 | /// Read from the UART, waiting for a line break. |
| 473 | /// | ||
| 474 | /// We read until one of the following occurs: | ||
| 474 | /// | 475 | /// |
| 475 | /// * We read `buffer.len()` bytes without a line break | 476 | /// * We read `buffer.len()` bytes without a line break |
| 476 | /// * returns `Ok(buffer)` | 477 | /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))` |
| 477 | /// * We read `n` bytes then a line break occurs | 478 | /// * We read `n` bytes then a line break occurs |
| 478 | /// * returns `Ok(&mut buffer[..n])` | 479 | /// * returns `Ok(n)` |
| 479 | /// * We encounter some error OTHER than a line break | 480 | /// * We encounter some error OTHER than a line break |
| 480 | /// * returns `Err(Error)` | 481 | /// * returns `Err(ReadToBreakError::Other(error))` |
| 481 | pub async fn read_to_break<'a>(&mut self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], Error> { | 482 | /// |
| 483 | /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected | ||
| 484 | /// message to reliably detect the framing on one single call to `read_to_break()`. | ||
| 485 | /// | ||
| 486 | /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer: | ||
| 487 | /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))` | ||
| 488 | /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break | ||
| 489 | /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer: | ||
| 490 | /// * The first call to `read_to_break()` will return `Ok(20)`. | ||
| 491 | /// * The next call to `read_to_break()` will work as expected | ||
| 492 | pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> { | ||
| 482 | // clear error flags before we drain the fifo. errors that have accumulated | 493 | // clear error flags before we drain the fifo. errors that have accumulated |
| 483 | // in the flags will also be present in the fifo. | 494 | // in the flags will also be present in the fifo. |
| 484 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); | 495 | T::dma_state().rx_errs.store(0, Ordering::Relaxed); |
| @@ -498,11 +509,11 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 498 | // Drained fifo, still some room left! | 509 | // Drained fifo, still some room left! |
| 499 | Ok(len) if len < buffer.len() => &mut buffer[len..], | 510 | Ok(len) if len < buffer.len() => &mut buffer[len..], |
| 500 | // Drained (some/all of the fifo), no room left | 511 | // Drained (some/all of the fifo), no room left |
| 501 | Ok(_) => return Ok(buffer), | 512 | Ok(len) => return Err(ReadToBreakError::MissingBreak(len)), |
| 502 | // We got a break WHILE draining the FIFO, return what we did get before the break | 513 | // We got a break WHILE draining the FIFO, return what we did get before the break |
| 503 | Err((i, Error::Break)) => return Ok(&mut buffer[..i]), | 514 | Err((i, Error::Break)) => return Ok(i), |
| 504 | // Some other error, just return the error | 515 | // Some other error, just return the error |
| 505 | Err((_i, e)) => return Err(e), | 516 | Err((_i, e)) => return Err(ReadToBreakError::Other(e)), |
| 506 | }; | 517 | }; |
| 507 | 518 | ||
| 508 | // start a dma transfer. if errors have happened in the interim some error | 519 | // start a dma transfer. if errors have happened in the interim some error |
| @@ -538,14 +549,11 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 538 | ) | 549 | ) |
| 539 | .await; | 550 | .await; |
| 540 | 551 | ||
| 541 | let mut did_finish = false; | ||
| 542 | |||
| 543 | // Figure out our error state | 552 | // Figure out our error state |
| 544 | let errors = match transfer_result { | 553 | let errors = match transfer_result { |
| 545 | Either::First(()) => { | 554 | Either::First(()) => { |
| 546 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 555 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 547 | // byte, then we may still need to grab the error state! | 556 | // byte, then we may still need to grab the error state! |
| 548 | did_finish = true; | ||
| 549 | Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) | 557 | Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) |
| 550 | } | 558 | } |
| 551 | Either::Second(e) => { | 559 | Either::Second(e) => { |
| @@ -557,7 +565,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 557 | 565 | ||
| 558 | if errors.0 == 0 { | 566 | if errors.0 == 0 { |
| 559 | // No errors? That means we filled the buffer without a line break. | 567 | // No errors? That means we filled the buffer without a line break. |
| 560 | return Ok(buffer); | 568 | // For THIS function, that's a problem. |
| 569 | return Err(ReadToBreakError::MissingBreak(buffer.len())); | ||
| 561 | } else if errors.beris() { | 570 | } else if errors.beris() { |
| 562 | // We got a Line Break! By this point, we've finished/aborted the DMA | 571 | // We got a Line Break! By this point, we've finished/aborted the DMA |
| 563 | // transaction, which means that we need to figure out where it left off | 572 | // transaction, which means that we need to figure out where it left off |
| @@ -568,36 +577,60 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { | |||
| 568 | let sval = buffer.as_ptr() as usize; | 577 | let sval = buffer.as_ptr() as usize; |
| 569 | let eval = sval + buffer.len(); | 578 | let eval = sval + buffer.len(); |
| 570 | 579 | ||
| 571 | // Note: the `write_addr()` is where the NEXT write would be. | 580 | // Note: the `write_addr()` is where the NEXT write would be, but we ALSO |
| 572 | let mut last_written = ch.regs().write_addr().read() as usize; | 581 | // got a line break, so take an offset of 1 |
| 582 | let mut next_addr = ch.regs().write_addr().read() as usize; | ||
| 573 | 583 | ||
| 574 | // Did we finish the whole DMA transfer? | 584 | // If we DON'T end up inside the range, something has gone really wrong. |
| 575 | if !did_finish { | 585 | if (next_addr < sval) || (next_addr > eval) { |
| 576 | // No, we did not! We stopped because we got a line break. That means the | 586 | unreachable!("UART DMA reported invalid `write_addr`"); |
| 577 | // DMA transferred one "garbage byte" from the FIFO that held an error. | 587 | } |
| 578 | last_written -= 1; | 588 | |
| 579 | } else { | 589 | // If we finished the full DMA, AND the FIFO is not-empty, AND that |
| 580 | // We did finish and got a "late break", where the interrupt error fired AFTER | 590 | // byte reports a break error, THAT byte caused the error, and not data |
| 581 | // we got the last byte. Pop that from the FIFO so we don't trip on it next time. | 591 | // in the DMA transfer! Otherwise: our DMA grabbed one "bad" byte. |
| 582 | let dr = T::regs().uartdr().read(); | 592 | // |
| 583 | if !dr.be() { | 593 | // Note: even though we COULD detect this and return `Ok(buffer.len())`, |
| 584 | // Got an error after DMA but no error in the FIFO? | 594 | // we DON'T, as that is racy: if we read the error state AFTER the data |
| 585 | return Err(Error::Calculation); | 595 | // was transferred but BEFORE the line break interrupt fired, we'd return |
| 596 | // `MissingBreak`. Ignoring the fact that there's a line break in the FIFO | ||
| 597 | // means callers consistently see the same error regardless of | ||
| 598 | let regs = T::regs(); | ||
| 599 | let is_end = next_addr == eval; | ||
| 600 | let not_empty = !regs.uartfr().read().rxfe(); | ||
| 601 | let is_break = regs.uartrsr().read().be(); | ||
| 602 | let last_good = is_end && not_empty && is_break; | ||
| 603 | |||
| 604 | defmt::println!("next: {=usize}, sval: {=usize}, eval: {=usize}", next_addr, sval, eval); | ||
| 605 | defmt::println!("lg: {=bool}, is_end: {=bool}, not_empty: {=bool}, is_break: {=bool}", last_good, is_end, not_empty, is_break); | ||
| 606 | |||
| 607 | if is_end && not_empty && !is_break { | ||
| 608 | let val = regs.uartdr().read(); | ||
| 609 | let tb = regs.uartrsr().read().be(); | ||
| 610 | let te = regs.uartfr().read().rxfe(); | ||
| 611 | defmt::println!("THEN: {=bool}, {=bool}", tb, te); | ||
| 612 | if val.be() { | ||
| 613 | panic!("Oh what the hell"); | ||
| 586 | } | 614 | } |
| 587 | } | 615 | } |
| 588 | 616 | ||
| 589 | // If we DON'T end up inside the range, something has gone really wrong. | 617 | if !last_good { |
| 590 | if (last_written < sval) || (last_written > eval) { | 618 | defmt::println!("Last not good!"); |
| 591 | return Err(Error::Calculation); | 619 | // The last is NOT good (it's the line-break `0x00`), so elide it |
| 620 | next_addr -= 1; | ||
| 621 | } else { | ||
| 622 | defmt::println!("last good!"); | ||
| 592 | } | 623 | } |
| 593 | let taken = last_written - sval; | 624 | |
| 594 | return Ok(&mut buffer[..taken]); | 625 | defmt::println!("->{=usize}", next_addr - sval); |
| 626 | |||
| 627 | return Ok(next_addr - sval); | ||
| 595 | } else if errors.oeris() { | 628 | } else if errors.oeris() { |
| 596 | return Err(Error::Overrun); | 629 | return Err(ReadToBreakError::Other(Error::Overrun)); |
| 597 | } else if errors.peris() { | 630 | } else if errors.peris() { |
| 598 | return Err(Error::Parity); | 631 | return Err(ReadToBreakError::Other(Error::Parity)); |
| 599 | } else if errors.feris() { | 632 | } else if errors.feris() { |
| 600 | return Err(Error::Framing); | 633 | return Err(ReadToBreakError::Other(Error::Framing)); |
| 601 | } | 634 | } |
| 602 | unreachable!("unrecognized rx error"); | 635 | unreachable!("unrecognized rx error"); |
| 603 | } | 636 | } |
| @@ -902,7 +935,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> { | |||
| 902 | self.rx.read(buffer).await | 935 | self.rx.read(buffer).await |
| 903 | } | 936 | } |
| 904 | 937 | ||
| 905 | pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a mut [u8], Error> { | 938 | pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> { |
| 906 | self.rx.read_to_break(buf).await | 939 | self.rx.read_to_break(buf).await |
| 907 | } | 940 | } |
| 908 | } | 941 | } |
| @@ -1004,7 +1037,6 @@ impl embedded_hal_nb::serial::Error for Error { | |||
| 1004 | Self::Break => embedded_hal_nb::serial::ErrorKind::Other, | 1037 | Self::Break => embedded_hal_nb::serial::ErrorKind::Other, |
| 1005 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, | 1038 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, |
| 1006 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, | 1039 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, |
| 1007 | Self::Calculation => embedded_hal_nb::serial::ErrorKind::Other, | ||
| 1008 | } | 1040 | } |
| 1009 | } | 1041 | } |
| 1010 | } | 1042 | } |
