aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-02-25 14:28:44 +0000
committerGitHub <[email protected]>2022-02-25 14:28:44 +0000
commitd381b8e2b613dac5a8b6c80033e81fabc4a8632d (patch)
tree8dca0824c0c25e19fd48d3c15466b207da588ea3
parent6da4b6636435b350b21f0b30e7175a2a6899acdc (diff)
parent48f700b35c5371f1df374a615a5d68adff02597a (diff)
Merge #645
645: stm32 usart: Fix RX interrupt flag handling r=lulf a=timokroeger * On v1 interrupts cannot be cleared individually. Instead they are cleared implicitly by reading or writing DR (which we do now). * Multiple error flags can be set at the same time: Handle them all in one go intstead of re-entering the ISR for each one so that we do not lose any error flags on v1 hardware. * Wake when the RX buffer becomes full: This allows fast running chips to pull data from the buffer before receiving the next byte. Tested on v1 hardware, lets see if v2 still succeeds on CI. Co-authored-by: Timo Kröger <[email protected]>
-rw-r--r--embassy-stm32/src/usart/mod.rs90
1 files changed, 34 insertions, 56 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index c757769da..12e5d503d 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -395,29 +395,39 @@ mod buffered {
395 let r = self.uart.inner.regs(); 395 let r = self.uart.inner.regs();
396 unsafe { 396 unsafe {
397 let sr = sr(r).read(); 397 let sr = sr(r).read();
398 // TODO: do we want to handle interrupts the same way on v1 hardware? 398 clear_interrupt_flags(r, sr);
399 if sr.pe() { 399
400 clear_interrupt_flag(r, InterruptFlag::PE); 400 // This read also clears the error and idle interrupt flags on v1.
401 trace!("Parity error"); 401 let b = rdr(r).read_volatile();
402 } else if sr.fe() { 402
403 clear_interrupt_flag(r, InterruptFlag::FE); 403 if sr.rxne() {
404 trace!("Framing error"); 404 if sr.pe() {
405 } else if sr.ne() { 405 warn!("Parity error");
406 clear_interrupt_flag(r, InterruptFlag::NE); 406 }
407 trace!("Noise error"); 407 if sr.fe() {
408 } else if sr.ore() { 408 warn!("Framing error");
409 clear_interrupt_flag(r, InterruptFlag::ORE); 409 }
410 trace!("Overrun error"); 410 if sr.ne() {
411 } else if sr.rxne() { 411 warn!("Noise error");
412 }
413 if sr.ore() {
414 warn!("Overrun error");
415 }
416
412 let buf = self.rx.push_buf(); 417 let buf = self.rx.push_buf();
413 if buf.is_empty() { 418 if !buf.is_empty() {
414 self.rx_waker.wake(); 419 buf[0] = b;
415 } else {
416 buf[0] = rdr(r).read_volatile();
417 self.rx.push(1); 420 self.rx.push(1);
421 } else {
422 warn!("RX buffer full, discard received byte");
423 }
424
425 if self.rx.is_full() {
426 self.rx_waker.wake();
418 } 427 }
419 } else if sr.idle() { 428 }
420 clear_interrupt_flag(r, InterruptFlag::IDLE); 429
430 if sr.idle() {
421 self.rx_waker.wake(); 431 self.rx_waker.wake();
422 }; 432 };
423 } 433 }
@@ -542,28 +552,14 @@ fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
542 r.dr().ptr() as _ 552 r.dr().ptr() as _
543} 553}
544 554
545enum InterruptFlag {
546 PE,
547 FE,
548 NE,
549 ORE,
550 IDLE,
551}
552
553#[cfg(usart_v1)] 555#[cfg(usart_v1)]
554fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { 556fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
555 r.sr() 557 r.sr()
556} 558}
557 559
558#[cfg(usart_v1)] 560#[cfg(usart_v1)]
559unsafe fn clear_interrupt_flag(r: crate::pac::usart::Usart, _flag: InterruptFlag) { 561unsafe fn clear_interrupt_flags(_r: crate::pac::usart::Usart, _sr: regs::Sr) {
560 // This bit is set by hardware when noise is detected on a received frame. It is cleared by a 562 // On v1 the flags are cleared implicitly by reads and writes to DR.
561 // software sequence (an read to the USART_SR register followed by a read to the
562 // USART_DR register).
563
564 // this is the same as what st's HAL does on v1 hardware
565 r.sr().read();
566 r.dr().read();
567} 563}
568 564
569#[cfg(usart_v2)] 565#[cfg(usart_v2)]
@@ -582,26 +578,8 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Ixr, crate::
582} 578}
583 579
584#[cfg(usart_v2)] 580#[cfg(usart_v2)]
585#[inline] 581unsafe fn clear_interrupt_flags(r: crate::pac::usart::Usart, sr: regs::Ixr) {
586unsafe fn clear_interrupt_flag(r: crate::pac::usart::Usart, flag: InterruptFlag) { 582 r.icr().write(|w| *w = sr);
587 // v2 has a separate register for clearing flags (nice)
588 match flag {
589 InterruptFlag::PE => r.icr().write(|w| {
590 w.set_pe(true);
591 }),
592 InterruptFlag::FE => r.icr().write(|w| {
593 w.set_fe(true);
594 }),
595 InterruptFlag::NE => r.icr().write(|w| {
596 w.set_ne(true);
597 }),
598 InterruptFlag::ORE => r.icr().write(|w| {
599 w.set_ore(true);
600 }),
601 InterruptFlag::IDLE => r.icr().write(|w| {
602 w.set_idle(true);
603 }),
604 }
605} 583}
606 584
607pub(crate) mod sealed { 585pub(crate) mod sealed {