aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-01-01 10:51:14 +0000
committerGitHub <[email protected]>2022-01-01 10:51:14 +0000
commitc20ef419a67746688d6ba85a73016856cee76885 (patch)
treed997b4de3285590d9ee8cabcdfc98cb75eccb1b2
parent2f637b7be2d7dec8a5edb47921b018a41c942cc9 (diff)
parenta94932be0281926211bdb7a4de1f71a8e34cd745 (diff)
Merge #558
558: Port buffered uart to v1 stm32 hardware r=Dirbaio a=DCNick3 #526 seems to suggest that it will be rewritten for DMA support, but I am not sure how to implement it and the port was quite straightforward, so here it is. It might be immediately useful before DMA version will be implemented Note that I have not tested this on v2 hardware Co-authored-by: Nikita Strygin <[email protected]>
-rw-r--r--embassy-stm32/src/usart/mod.rs73
1 files changed, 52 insertions, 21 deletions
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index b51a728c0..3567746cf 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -245,9 +245,7 @@ where
245 } 245 }
246} 246}
247 247
248#[cfg(usart_v2)]
249pub use buffered::*; 248pub use buffered::*;
250#[cfg(usart_v2)]
251mod buffered { 249mod buffered {
252 use atomic_polyfill::{compiler_fence, Ordering}; 250 use atomic_polyfill::{compiler_fence, Ordering};
253 use core::pin::Pin; 251 use core::pin::Pin;
@@ -323,39 +321,30 @@ mod buffered {
323 fn on_rx(&mut self) { 321 fn on_rx(&mut self) {
324 let r = self.uart.inner.regs(); 322 let r = self.uart.inner.regs();
325 unsafe { 323 unsafe {
326 let sr = r.isr().read(); 324 let sr = sr(r).read();
325 // TODO: do we want to handle interrupts the same way on v1 hardware?
327 if sr.pe() { 326 if sr.pe() {
328 r.icr().write(|w| { 327 clear_interrupt_flag(r, InterruptFlag::PE);
329 w.set_pe(true);
330 });
331 trace!("Parity error"); 328 trace!("Parity error");
332 } else if sr.fe() { 329 } else if sr.fe() {
333 r.icr().write(|w| { 330 clear_interrupt_flag(r, InterruptFlag::FE);
334 w.set_fe(true);
335 });
336 trace!("Framing error"); 331 trace!("Framing error");
337 } else if sr.ne() { 332 } else if sr.ne() {
338 r.icr().write(|w| { 333 clear_interrupt_flag(r, InterruptFlag::NE);
339 w.set_ne(true);
340 });
341 trace!("Noise error"); 334 trace!("Noise error");
342 } else if sr.ore() { 335 } else if sr.ore() {
343 r.icr().write(|w| { 336 clear_interrupt_flag(r, InterruptFlag::ORE);
344 w.set_ore(true);
345 });
346 trace!("Overrun error"); 337 trace!("Overrun error");
347 } else if sr.rxne() { 338 } else if sr.rxne() {
348 let buf = self.rx.push_buf(); 339 let buf = self.rx.push_buf();
349 if buf.is_empty() { 340 if buf.is_empty() {
350 self.rx_waker.wake(); 341 self.rx_waker.wake();
351 } else { 342 } else {
352 buf[0] = r.rdr().read().0 as u8; 343 buf[0] = rdr(r).read_volatile();
353 self.rx.push(1); 344 self.rx.push(1);
354 } 345 }
355 } else if sr.idle() { 346 } else if sr.idle() {
356 r.icr().write(|w| { 347 clear_interrupt_flag(r, InterruptFlag::IDLE);
357 w.set_idle(true);
358 });
359 self.rx_waker.wake(); 348 self.rx_waker.wake();
360 }; 349 };
361 } 350 }
@@ -364,13 +353,13 @@ mod buffered {
364 fn on_tx(&mut self) { 353 fn on_tx(&mut self) {
365 let r = self.uart.inner.regs(); 354 let r = self.uart.inner.regs();
366 unsafe { 355 unsafe {
367 if r.isr().read().txe() { 356 if sr(r).read().txe() {
368 let buf = self.tx.pop_buf(); 357 let buf = self.tx.pop_buf();
369 if !buf.is_empty() { 358 if !buf.is_empty() {
370 r.cr1().modify(|w| { 359 r.cr1().modify(|w| {
371 w.set_txeie(true); 360 w.set_txeie(true);
372 }); 361 });
373 r.tdr().write_value(regs::Dr(buf[0].into())); 362 tdr(r).write_volatile(buf[0].into());
374 self.tx.pop(1); 363 self.tx.pop(1);
375 self.tx_waker.wake(); 364 self.tx_waker.wake();
376 } else { 365 } else {
@@ -480,11 +469,30 @@ fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
480 r.dr().ptr() as _ 469 r.dr().ptr() as _
481} 470}
482 471
472enum InterruptFlag {
473 PE,
474 FE,
475 NE,
476 ORE,
477 IDLE,
478}
479
483#[cfg(usart_v1)] 480#[cfg(usart_v1)]
484fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { 481fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
485 r.sr() 482 r.sr()
486} 483}
487 484
485#[cfg(usart_v1)]
486unsafe fn clear_interrupt_flag(r: crate::pac::usart::Usart, _flag: InterruptFlag) {
487 // This bit is set by hardware when noise is detected on a received frame. It is cleared by a
488 // software sequence (an read to the USART_SR register followed by a read to the
489 // USART_DR register).
490
491 // this is the same as what st's HAL does on v1 hardware
492 r.sr().read();
493 r.dr().read();
494}
495
488#[cfg(usart_v2)] 496#[cfg(usart_v2)]
489fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { 497fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
490 r.tdr().ptr() as _ 498 r.tdr().ptr() as _
@@ -500,6 +508,29 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Ixr, crate::
500 r.isr() 508 r.isr()
501} 509}
502 510
511#[cfg(usart_v2)]
512#[inline]
513unsafe fn clear_interrupt_flag(r: crate::pac::usart::Usart, flag: InterruptFlag) {
514 // v2 has a separate register for clearing flags (nice)
515 match flag {
516 InterruptFlag::PE => r.icr().write(|w| {
517 w.set_pe(true);
518 }),
519 InterruptFlag::FE => r.icr().write(|w| {
520 w.set_fe(true);
521 }),
522 InterruptFlag::NE => r.icr().write(|w| {
523 w.set_ne(true);
524 }),
525 InterruptFlag::ORE => r.icr().write(|w| {
526 w.set_ore(true);
527 }),
528 InterruptFlag::IDLE => r.icr().write(|w| {
529 w.set_idle(true);
530 }),
531 }
532}
533
503pub(crate) mod sealed { 534pub(crate) mod sealed {
504 use super::*; 535 use super::*;
505 536