Skip to content

Commit d251a2b

Browse files
committed
Add read_from_break method to STM32 UartRx
1 parent de5dd10 commit d251a2b

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

embassy-stm32/src/usart/mod.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
4141
unsafe fn on_interrupt(r: Regs, s: &'static State) {
4242
let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read());
4343

44-
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
44+
let has_errors = (sr.pe() && cr1.peie()) || ((sr.ne() || sr.ore()) && cr3.eie()) || (sr.fe() && cr3.eie() && cr3.dmar());
4545
if has_errors {
4646
// clear all interrupts and DMA Rx Request
4747
r.cr1().modify(|w| {
@@ -74,6 +74,13 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) {
7474
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
7575

7676
// It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection
77+
} else if sr.fe() && cr3.eie() {
78+
// Break detected (frame error)
79+
if sr.fe() {
80+
r.icr().write(|w| w.set_fe(true)); // clear framing error
81+
unsafe { rdr(r).read_volatile() }; // clear byte so DMA doesn't pick it up
82+
r.cr3().modify(|w| w.set_dmar(true)); // start DMA
83+
}
7784
} else {
7885
return;
7986
}
@@ -692,20 +699,27 @@ impl<'d> UartRx<'d, Async> {
692699

693700
/// Initiate an asynchronous UART read
694701
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
695-
self.inner_read(buffer, false).await?;
702+
self.inner_read(buffer, false, false).await?;
696703

697704
Ok(())
698705
}
699706

700707
/// Initiate an asynchronous read with idle line detection enabled
701708
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
702-
self.inner_read(buffer, true).await
709+
self.inner_read(buffer, true, false).await
710+
}
711+
712+
/// Initiate an asynchronous read, waiting for a break character (frame error) before starting the read
713+
/// Returns Err(Framing) if a second break occurs before buffer.len() characters have been received.
714+
pub async fn read_from_break(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
715+
self.inner_read(buffer, false, true).await
703716
}
704717

705718
async fn inner_read_run(
706719
&mut self,
707720
buffer: &mut [u8],
708721
enable_idle_line_detection: bool,
722+
wait_for_break: bool,
709723
) -> Result<ReadCompletionEvent, Error> {
710724
let r = self.info.regs;
711725

@@ -767,8 +781,8 @@ impl<'d> UartRx<'d, Async> {
767781
r.cr3().modify(|w| {
768782
// enable Error Interrupt: (Frame error, Noise error, Overrun error)
769783
w.set_eie(true);
770-
// enable DMA Rx Request
771-
w.set_dmar(true);
784+
// enable DMA Rx Request unless waiting for break first
785+
if !wait_for_break { w.set_dmar(true); }
772786
});
773787

774788
compiler_fence(Ordering::SeqCst);
@@ -779,7 +793,7 @@ impl<'d> UartRx<'d, Async> {
779793

780794
let cr3 = r.cr3().read();
781795

782-
if !cr3.dmar() {
796+
if !wait_for_break && !cr3.dmar() {
783797
// something went wrong
784798
// because the only way to get this flag cleared is to have an interrupt
785799

@@ -841,7 +855,7 @@ impl<'d> UartRx<'d, Async> {
841855

842856
compiler_fence(Ordering::SeqCst);
843857

844-
let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
858+
let has_errors = sr.pe() || sr.ne() || sr.fe() || (sr.ore() && !wait_for_break);
845859

846860
if has_errors {
847861
// all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler
@@ -889,7 +903,7 @@ impl<'d> UartRx<'d, Async> {
889903
r
890904
}
891905

892-
async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> {
906+
async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool, wait_for_break: bool) -> Result<usize, Error> {
893907
if buffer.is_empty() {
894908
return Ok(0);
895909
} else if buffer.len() > 0xFFFF {
@@ -899,7 +913,7 @@ impl<'d> UartRx<'d, Async> {
899913
let buffer_len = buffer.len();
900914

901915
// wait for DMA to complete or IDLE line detection if requested
902-
let res = self.inner_read_run(buffer, enable_idle_line_detection).await;
916+
let res = self.inner_read_run(buffer, enable_idle_line_detection, wait_for_break).await;
903917

904918
match res {
905919
Ok(ReadCompletionEvent::DmaCompleted) => Ok(buffer_len),

0 commit comments

Comments
 (0)