stm32: move to bind_interrupts
disable lora functionality for now
This commit is contained in:
@@ -8,6 +8,78 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: BasicInstance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let state = T::buffered_state();
|
||||
|
||||
// RX
|
||||
unsafe {
|
||||
let sr = sr(r).read();
|
||||
clear_interrupt_flags(r, sr);
|
||||
|
||||
if sr.rxne() {
|
||||
if sr.pe() {
|
||||
warn!("Parity error");
|
||||
}
|
||||
if sr.fe() {
|
||||
warn!("Framing error");
|
||||
}
|
||||
if sr.ne() {
|
||||
warn!("Noise error");
|
||||
}
|
||||
if sr.ore() {
|
||||
warn!("Overrun error");
|
||||
}
|
||||
|
||||
let mut rx_writer = state.rx_buf.writer();
|
||||
let buf = rx_writer.push_slice();
|
||||
if !buf.is_empty() {
|
||||
// This read also clears the error and idle interrupt flags on v1.
|
||||
buf[0] = rdr(r).read_volatile();
|
||||
rx_writer.push_done(1);
|
||||
} else {
|
||||
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
||||
}
|
||||
|
||||
if state.rx_buf.is_full() {
|
||||
state.rx_waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
if sr.idle() {
|
||||
state.rx_waker.wake();
|
||||
};
|
||||
}
|
||||
|
||||
// TX
|
||||
unsafe {
|
||||
if sr(r).read().txe() {
|
||||
let mut tx_reader = state.tx_buf.reader();
|
||||
let buf = tx_reader.pop_slice();
|
||||
if !buf.is_empty() {
|
||||
r.cr1().modify(|w| {
|
||||
w.set_txeie(true);
|
||||
});
|
||||
tdr(r).write_volatile(buf[0].into());
|
||||
tx_reader.pop_done(1);
|
||||
state.tx_waker.wake();
|
||||
} else {
|
||||
// Disable interrupt until we have something to transmit again
|
||||
r.cr1().modify(|w| {
|
||||
w.set_txeie(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
rx_waker: AtomicWaker,
|
||||
rx_buf: RingBuffer,
|
||||
@@ -43,7 +115,7 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
|
||||
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
@@ -53,12 +125,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
pub fn new_with_rtscts(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
@@ -81,13 +153,13 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
});
|
||||
}
|
||||
|
||||
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
pub fn new_with_de(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
de: impl Peripheral<P = impl DePin<T>> + 'd,
|
||||
@@ -107,19 +179,18 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
});
|
||||
}
|
||||
|
||||
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> BufferedUart<'d, T> {
|
||||
into_ref!(_peri, rx, tx, irq);
|
||||
into_ref!(_peri, rx, tx);
|
||||
|
||||
let state = T::buffered_state();
|
||||
let len = tx_buffer.len();
|
||||
@@ -145,9 +216,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
||||
});
|
||||
}
|
||||
|
||||
irq.set_handler(on_interrupt::<T>);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
Self {
|
||||
rx: BufferedUartRx { phantom: PhantomData },
|
||||
@@ -336,71 +406,6 @@ impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn on_interrupt<T: BasicInstance>(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let state = T::buffered_state();
|
||||
|
||||
// RX
|
||||
unsafe {
|
||||
let sr = sr(r).read();
|
||||
clear_interrupt_flags(r, sr);
|
||||
|
||||
if sr.rxne() {
|
||||
if sr.pe() {
|
||||
warn!("Parity error");
|
||||
}
|
||||
if sr.fe() {
|
||||
warn!("Framing error");
|
||||
}
|
||||
if sr.ne() {
|
||||
warn!("Noise error");
|
||||
}
|
||||
if sr.ore() {
|
||||
warn!("Overrun error");
|
||||
}
|
||||
|
||||
let mut rx_writer = state.rx_buf.writer();
|
||||
let buf = rx_writer.push_slice();
|
||||
if !buf.is_empty() {
|
||||
// This read also clears the error and idle interrupt flags on v1.
|
||||
buf[0] = rdr(r).read_volatile();
|
||||
rx_writer.push_done(1);
|
||||
} else {
|
||||
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
||||
}
|
||||
|
||||
if state.rx_buf.is_full() {
|
||||
state.rx_waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
if sr.idle() {
|
||||
state.rx_waker.wake();
|
||||
};
|
||||
}
|
||||
|
||||
// TX
|
||||
unsafe {
|
||||
if sr(r).read().txe() {
|
||||
let mut tx_reader = state.tx_buf.reader();
|
||||
let buf = tx_reader.pop_slice();
|
||||
if !buf.is_empty() {
|
||||
r.cr1().modify(|w| {
|
||||
w.set_txeie(true);
|
||||
});
|
||||
tdr(r).write_volatile(buf[0].into());
|
||||
tx_reader.pop_done(1);
|
||||
state.tx_waker.wake();
|
||||
} else {
|
||||
// Disable interrupt until we have something to transmit again
|
||||
r.cr1().modify(|w| {
|
||||
w.set_txeie(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_io::Error for Error {
|
||||
fn kind(&self) -> embedded_io::ErrorKind {
|
||||
embedded_io::ErrorKind::Other
|
||||
|
@@ -5,7 +5,7 @@ use core::marker::PhantomData;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_cortex_m::interrupt::InterruptExt;
|
||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
||||
use embassy_hal_common::drop::OnDrop;
|
||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||
use futures::future::{select, Either};
|
||||
@@ -18,7 +18,71 @@ use crate::pac::usart::Lpuart as Regs;
|
||||
use crate::pac::usart::Usart as Regs;
|
||||
use crate::pac::usart::{regs, vals};
|
||||
use crate::time::Hertz;
|
||||
use crate::{peripherals, Peripheral};
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: BasicInstance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: BasicInstance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
|
||||
|
||||
let mut wake = false;
|
||||
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
|
||||
if has_errors {
|
||||
// clear all interrupts and DMA Rx Request
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
// disable RXNE interrupt
|
||||
w.set_rxneie(false);
|
||||
// disable parity interrupt
|
||||
w.set_peie(false);
|
||||
// disable idle line interrupt
|
||||
w.set_idleie(false);
|
||||
});
|
||||
r.cr3().modify(|w| {
|
||||
// disable Error Interrupt: (Frame error, Noise error, Overrun error)
|
||||
w.set_eie(false);
|
||||
// disable DMA Rx Request
|
||||
w.set_dmar(false);
|
||||
});
|
||||
}
|
||||
|
||||
wake = true;
|
||||
} else {
|
||||
if cr1.idleie() && sr.idle() {
|
||||
// IDLE detected: no more data will come
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
// disable idle line detection
|
||||
w.set_idleie(false);
|
||||
});
|
||||
}
|
||||
|
||||
wake = true;
|
||||
}
|
||||
|
||||
if cr1.rxneie() {
|
||||
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
|
||||
|
||||
// It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection
|
||||
|
||||
wake = true;
|
||||
}
|
||||
}
|
||||
|
||||
if wake {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
s.rx_waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum DataBits {
|
||||
@@ -215,7 +279,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
@@ -223,12 +287,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(peri, irq, rx, rx_dma, config)
|
||||
Self::new_inner(peri, rx, rx_dma, config)
|
||||
}
|
||||
|
||||
pub fn new_with_rts(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
@@ -246,17 +310,16 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
});
|
||||
}
|
||||
|
||||
Self::new_inner(peri, irq, rx, rx_dma, config)
|
||||
Self::new_inner(peri, rx, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, irq, rx, rx_dma);
|
||||
into_ref!(peri, rx, rx_dma);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@@ -266,9 +329,8 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
|
||||
configure(r, &config, T::frequency(), T::KIND, true, false);
|
||||
|
||||
irq.set_handler(Self::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// create state once!
|
||||
let _s = T::state();
|
||||
@@ -282,63 +344,6 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_interrupt(_: *mut ()) {
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
let (sr, cr1, cr3) = unsafe { (sr(r).read(), r.cr1().read(), r.cr3().read()) };
|
||||
|
||||
let mut wake = false;
|
||||
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
|
||||
if has_errors {
|
||||
// clear all interrupts and DMA Rx Request
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
// disable RXNE interrupt
|
||||
w.set_rxneie(false);
|
||||
// disable parity interrupt
|
||||
w.set_peie(false);
|
||||
// disable idle line interrupt
|
||||
w.set_idleie(false);
|
||||
});
|
||||
r.cr3().modify(|w| {
|
||||
// disable Error Interrupt: (Frame error, Noise error, Overrun error)
|
||||
w.set_eie(false);
|
||||
// disable DMA Rx Request
|
||||
w.set_dmar(false);
|
||||
});
|
||||
}
|
||||
|
||||
wake = true;
|
||||
} else {
|
||||
if cr1.idleie() && sr.idle() {
|
||||
// IDLE detected: no more data will come
|
||||
unsafe {
|
||||
r.cr1().modify(|w| {
|
||||
// disable idle line detection
|
||||
w.set_idleie(false);
|
||||
});
|
||||
}
|
||||
|
||||
wake = true;
|
||||
}
|
||||
|
||||
if cr1.rxneie() {
|
||||
// We cannot check the RXNE flag as it is auto-cleared by the DMA controller
|
||||
|
||||
// It is up to the listener to determine if this in fact was a RX event and disable the RXNE detection
|
||||
|
||||
wake = true;
|
||||
}
|
||||
}
|
||||
|
||||
if wake {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
s.rx_waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
unsafe fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
||||
let r = T::regs();
|
||||
@@ -643,7 +648,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
@@ -651,14 +656,14 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
T::enable();
|
||||
T::reset();
|
||||
|
||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
pub fn new_with_rtscts(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
|
||||
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
@@ -678,7 +683,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
w.set_ctse(true);
|
||||
});
|
||||
}
|
||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
@@ -686,7 +691,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
de: impl Peripheral<P = impl DePin<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
@@ -703,19 +708,18 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
w.set_dem(true);
|
||||
});
|
||||
}
|
||||
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
irq: impl Peripheral<P = T::Interrupt> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(peri, rx, tx, irq, tx_dma, rx_dma);
|
||||
into_ref!(peri, rx, tx, tx_dma, rx_dma);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
@@ -726,9 +730,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
||||
|
||||
configure(r, &config, T::frequency(), T::KIND, true, true);
|
||||
|
||||
irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
|
||||
irq.unpend();
|
||||
irq.enable();
|
||||
unsafe { T::Interrupt::steal() }.unpend();
|
||||
unsafe { T::Interrupt::steal() }.enable();
|
||||
|
||||
// create state once!
|
||||
let _s = T::state();
|
||||
@@ -1068,6 +1071,9 @@ mod eio {
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use buffered::*;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use crate::usart::buffered::InterruptHandler as BufferedInterruptHandler;
|
||||
#[cfg(feature = "nightly")]
|
||||
mod buffered;
|
||||
|
||||
|
Reference in New Issue
Block a user