diff options
| author | James Munns <[email protected]> | 2023-12-20 14:14:14 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2024-01-19 14:02:17 +0100 |
| commit | 24fc12667dc3b929d4fef633cdf0c1ada9765484 (patch) | |
| tree | 208c410dcda2d42ecb7ae344c604e10187f7f874 | |
| parent | 9fd49fb9d675f858691491a57ab50dd049168def (diff) | |
Update with more docs and less panics
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 118 |
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 | } |
