Port buffered uart to v1 stm32 hardware

- No DMA
- Create clear_interrupt_flag function to
    handle differences between v1 and v2 hardware
This commit is contained in:
Nikita Strygin 2021-12-26 18:04:07 +03:00
parent 23c16903db
commit 6b08c70273

View file

@ -245,9 +245,7 @@ where
} }
} }
#[cfg(usart_v2)]
pub use buffered::*; pub use buffered::*;
#[cfg(usart_v2)]
mod buffered { mod buffered {
use atomic_polyfill::{compiler_fence, Ordering}; use atomic_polyfill::{compiler_fence, Ordering};
use core::pin::Pin; use core::pin::Pin;
@ -323,39 +321,30 @@ mod buffered {
fn on_rx(&mut self) { fn on_rx(&mut self) {
let r = self.uart.inner.regs(); let r = self.uart.inner.regs();
unsafe { unsafe {
let sr = r.isr().read(); let sr = sr(r).read();
// TODO: do we want to handle interrupts the same way on v1 hardware?
if sr.pe() { if sr.pe() {
r.icr().write(|w| { clear_interrupt_flag(r, InterruptFlag::PE);
w.set_pe(true);
});
trace!("Parity error"); trace!("Parity error");
} else if sr.fe() { } else if sr.fe() {
r.icr().write(|w| { clear_interrupt_flag(r, InterruptFlag::FE);
w.set_fe(true);
});
trace!("Framing error"); trace!("Framing error");
} else if sr.ne() { } else if sr.ne() {
r.icr().write(|w| { clear_interrupt_flag(r, InterruptFlag::NE);
w.set_ne(true);
});
trace!("Noise error"); trace!("Noise error");
} else if sr.ore() { } else if sr.ore() {
r.icr().write(|w| { clear_interrupt_flag(r, InterruptFlag::ORE);
w.set_ore(true);
});
trace!("Overrun error"); trace!("Overrun error");
} else if sr.rxne() { } else if sr.rxne() {
let buf = self.rx.push_buf(); let buf = self.rx.push_buf();
if buf.is_empty() { if buf.is_empty() {
self.rx_waker.wake(); self.rx_waker.wake();
} else { } else {
buf[0] = r.rdr().read().0 as u8; buf[0] = rdr(r).read_volatile();
self.rx.push(1); self.rx.push(1);
} }
} else if sr.idle() { } else if sr.idle() {
r.icr().write(|w| { clear_interrupt_flag(r, InterruptFlag::IDLE);
w.set_idle(true);
});
self.rx_waker.wake(); self.rx_waker.wake();
}; };
} }
@ -364,13 +353,13 @@ mod buffered {
fn on_tx(&mut self) { fn on_tx(&mut self) {
let r = self.uart.inner.regs(); let r = self.uart.inner.regs();
unsafe { unsafe {
if r.isr().read().txe() { if sr(r).read().txe() {
let buf = self.tx.pop_buf(); let buf = self.tx.pop_buf();
if !buf.is_empty() { if !buf.is_empty() {
r.cr1().modify(|w| { r.cr1().modify(|w| {
w.set_txeie(true); w.set_txeie(true);
}); });
r.tdr().write_value(regs::Dr(buf[0].into())); tdr(r).write_volatile(buf[0].into());
self.tx.pop(1); self.tx.pop(1);
self.tx_waker.wake(); self.tx_waker.wake();
} else { } else {
@ -480,11 +469,32 @@ fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().ptr() as _ r.dr().ptr() as _
} }
enum InterruptFlag {
PE,
FE,
NE,
ORE,
IDLE,
}
#[cfg(usart_v1)] #[cfg(usart_v1)]
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
r.sr() r.sr()
} }
#[cfg(usart_v1)]
fn clear_interrupt_flag(r: crate::pac::usart::Usart, _flag: InterruptFlag) {
// This bit is set by hardware when noise is detected on a received frame. It is cleared by a
// software sequence (an read to the USART_SR register followed by a read to the
// USART_DR register).
// this is the same as what st's HAL does on v1 hardware
unsafe {
r.sr().read();
r.dr().read();
}
}
#[cfg(usart_v2)] #[cfg(usart_v2)]
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.tdr().ptr() as _ r.tdr().ptr() as _
@ -500,6 +510,29 @@ fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Ixr, crate::
r.isr() r.isr()
} }
#[cfg(usart_v2)]
#[inline]
fn clear_interrupt_flag(r: crate::pac::usart::Usart, flag: InterruptFlag) {
// v2 has a separate register for clearing flags (nice)
match flag {
InterruptFlag::PE => r.icr().write(|w| {
w.set_pe(true);
}),
InterruptFlag::FE => r.icr().write(|w| {
w.set_fe(true);
}),
InterruptFlag::NE => r.icr().write(|w| {
w.set_ne(true);
}),
InterruptFlag::ORE => r.icr().write(|w| {
w.set_ore(true);
}),
InterruptFlag::IDLE => r.icr().write(|w| {
w.set_idle(true);
}),
}
}
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;