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:
parent
23c16903db
commit
6b08c70273
1 changed files with 54 additions and 21 deletions
|
@ -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::*;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue