Fix interrupt handling so it is similar to before the rework, and fix examples

This commit is contained in:
Mathias 2023-03-31 15:50:37 +02:00
parent cfbe93c280
commit 472dc6b7d1
3 changed files with 62 additions and 122 deletions

View File

@ -43,9 +43,9 @@ pub struct BufferedUartRx<'d, T: BasicInstance> {
impl<'d, T: BasicInstance> BufferedUart<'d, T> { impl<'d, T: BasicInstance> BufferedUart<'d, T> {
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8],
config: Config, config: Config,
@ -53,14 +53,14 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
T::enable(); T::enable();
T::reset(); T::reset();
Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
} }
pub fn new_with_rtscts( pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd, rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd, cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8],
@ -81,15 +81,15 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
}); });
} }
Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
} }
#[cfg(not(usart_v1))] #[cfg(not(usart_v1))]
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd, de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8],
@ -107,14 +107,14 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
}); });
} }
Self::new_inner(peri, rx, tx, irq, tx_buffer, rx_buffer, config) Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
} }
fn new_inner( fn new_inner(
_peri: impl Peripheral<P = T> + 'd, _peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8],
config: Config, config: Config,
@ -155,8 +155,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
} }
} }
pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
(self.rx, self.tx) (self.tx, self.rx)
} }
} }
@ -165,85 +165,46 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
poll_fn(move |cx| { poll_fn(move |cx| {
let state = T::buffered_state(); let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() }; let mut rx_reader = unsafe { state.rx_buf.reader() };
let n = rx_reader.pop(|data| { let data = rx_reader.pop_slice();
let n = data.len().min(buf.len());
buf[..n].copy_from_slice(&data[..n]); if !data.is_empty() {
n let len = data.len().min(buf.len());
}); buf[..len].copy_from_slice(&data[..len]);
if n == 0 {
state.rx_waker.register(cx.waker()); let do_pend = state.rx_buf.is_full();
return Poll::Pending; rx_reader.pop_done(len);
if do_pend {
unsafe { T::Interrupt::steal().pend() };
}
return Poll::Ready(Ok(len));
} }
// FIXME: state.rx_waker.register(cx.waker());
// (Re-)Enable the interrupt to receive more data in case it was Poll::Pending
// disabled because the buffer was full.
// let regs = T::regs();
// unsafe {
// regs.uartimsc().write_set(|w| {
// w.set_rxim(true);
// w.set_rtim(true);
// });
// }
Poll::Ready(Ok(n))
}) })
.await .await
// poll_fn(move |cx| {
// let state = T::buffered_state();
// let mut do_pend = false;
// compiler_fence(Ordering::SeqCst);
// // We have data ready in buffer? Return it.
// let data = state.rx_buf.pop_buf();
// if !data.is_empty() {
// let len = data.len().min(buf.len());
// buf[..len].copy_from_slice(&data[..len]);
// if state.rx_buf.is_full() {
// do_pend = true;
// }
// state.rx_buf.pop(len);
// return Poll::Ready(Ok(len));
// }
// state.rx_waker.register(cx.waker());
// if do_pend {
// inner.pend();
// }
// Poll::Pending
// })
// .await
} }
fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
loop { loop {
let state = T::buffered_state(); let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() }; let mut rx_reader = unsafe { state.rx_buf.reader() };
let n = rx_reader.pop(|data| { let data = rx_reader.pop_slice();
let n = data.len().min(buf.len());
buf[..n].copy_from_slice(&data[..n]);
n
});
if n > 0 { if !data.is_empty() {
// FIXME: let len = data.len().min(buf.len());
// (Re-)Enable the interrupt to receive more data in case it was buf[..len].copy_from_slice(&data[..len]);
// disabled because the buffer was full.
// let regs = T::regs();
// unsafe {
// regs.uartimsc().write_set(|w| {
// w.set_rxim(true);
// w.set_rtim(true);
// });
// }
return Ok(n); let do_pend = state.rx_buf.is_full();
rx_reader.pop_done(len);
if do_pend {
unsafe { T::Interrupt::steal().pend() };
}
return Ok(len);
} }
} }
} }
@ -279,22 +240,23 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
async fn write(&self, buf: &[u8]) -> Result<usize, Error> { async fn write(&self, buf: &[u8]) -> Result<usize, Error> {
poll_fn(move |cx| { poll_fn(move |cx| {
let state = T::buffered_state(); let state = T::buffered_state();
let empty = state.tx_buf.is_empty();
let mut tx_writer = unsafe { state.tx_buf.writer() }; let mut tx_writer = unsafe { state.tx_buf.writer() };
let n = tx_writer.push(|data| { let data = tx_writer.push_slice();
let n = data.len().min(buf.len()); if data.is_empty() {
data[..n].copy_from_slice(&buf[..n]);
n
});
if n == 0 {
state.tx_waker.register(cx.waker()); state.tx_waker.register(cx.waker());
return Poll::Pending; return Poll::Pending;
} }
// The TX interrupt only triggers when the there was data in the let n = data.len().min(buf.len());
// FIFO and the number of bytes drops below a threshold. When the data[..n].copy_from_slice(&buf[..n]);
// FIFO was empty we have to manually pend the interrupt to shovel tx_writer.push_done(n);
// TX data from the buffer into the FIFO.
unsafe { T::Interrupt::steal() }.pend(); if empty {
unsafe { T::Interrupt::steal() }.pend();
}
Poll::Ready(Ok(n)) Poll::Ready(Ok(n))
}) })
.await .await
@ -316,19 +278,19 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> { fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
loop { loop {
let state = T::buffered_state(); let state = T::buffered_state();
let empty = state.tx_buf.is_empty();
let mut tx_writer = unsafe { state.tx_buf.writer() }; let mut tx_writer = unsafe { state.tx_buf.writer() };
let n = tx_writer.push(|data| { let data = tx_writer.push_slice();
if !data.is_empty() {
let n = data.len().min(buf.len()); let n = data.len().min(buf.len());
data[..n].copy_from_slice(&buf[..n]); data[..n].copy_from_slice(&buf[..n]);
n tx_writer.push_done(n);
});
if empty {
unsafe { T::Interrupt::steal() }.pend();
}
if n != 0 {
// The TX interrupt only triggers when the there was data in the
// FIFO and the number of bytes drops below a threshold. When the
// FIFO was empty we have to manually pend the interrupt to shovel
// TX data from the buffer into the FIFO.
unsafe { T::Interrupt::steal() }.pend();
return Ok(n); return Ok(n);
} }
} }

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::usart::{BufferedUart, Config, State}; use embassy_stm32::usart::{BufferedUart, Config};
use embedded_io::asynch::BufRead; use embedded_io::asynch::BufRead;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -16,20 +16,10 @@ async fn main(_spawner: Spawner) {
let config = Config::default(); let config = Config::default();
let mut state = State::new();
let irq = interrupt::take!(USART3); let irq = interrupt::take!(USART3);
let mut tx_buf = [0u8; 32]; let mut tx_buf = [0u8; 32];
let mut rx_buf = [0u8; 32]; let mut rx_buf = [0u8; 32];
let mut buf_usart = BufferedUart::new( let mut buf_usart = BufferedUart::new(p.USART3, irq, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config);
&mut state,
p.USART3,
p.PD9,
p.PD8,
irq,
&mut tx_buf,
&mut rx_buf,
config,
);
loop { loop {
let buf = buf_usart.fill_buf().await.unwrap(); let buf = buf_usart.fill_buf().await.unwrap();

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::usart::{BufferedUart, Config, State}; use embassy_stm32::usart::{BufferedUart, Config};
use embedded_io::asynch::{Read, Write}; use embedded_io::asynch::{Read, Write};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -20,20 +20,8 @@ async fn main(_spawner: Spawner) {
let mut config = Config::default(); let mut config = Config::default();
config.baudrate = 9600; config.baudrate = 9600;
let mut state = State::new();
let irq = interrupt::take!(USART2); let irq = interrupt::take!(USART2);
let mut usart = unsafe { let mut usart = unsafe { BufferedUart::new(p.USART2, irq, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) };
BufferedUart::new(
&mut state,
p.USART2,
p.PA3,
p.PA2,
irq,
&mut TX_BUFFER,
&mut RX_BUFFER,
config,
)
};
usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
info!("wrote Hello, starting echo"); info!("wrote Hello, starting echo");