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> {
pub fn new(
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,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
@ -53,14 +53,14 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
T::enable();
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(
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,
irq: impl Peripheral<P = T::Interrupt> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
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))]
pub fn new_with_de(
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,
irq: impl Peripheral<P = T::Interrupt> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_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(
_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,
irq: impl Peripheral<P = T::Interrupt> + 'd,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
config: Config,
@ -155,8 +155,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
}
}
pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) {
(self.rx, self.tx)
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
(self.tx, self.rx)
}
}
@ -165,85 +165,46 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
poll_fn(move |cx| {
let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() };
let n = rx_reader.pop(|data| {
let n = data.len().min(buf.len());
buf[..n].copy_from_slice(&data[..n]);
n
});
if n == 0 {
state.rx_waker.register(cx.waker());
return Poll::Pending;
let data = rx_reader.pop_slice();
if !data.is_empty() {
let len = data.len().min(buf.len());
buf[..len].copy_from_slice(&data[..len]);
let do_pend = state.rx_buf.is_full();
rx_reader.pop_done(len);
if do_pend {
unsafe { T::Interrupt::steal().pend() };
}
// FIXME:
// (Re-)Enable the interrupt to receive more data in case it was
// 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 Poll::Ready(Ok(len));
}
Poll::Ready(Ok(n))
state.rx_waker.register(cx.waker());
Poll::Pending
})
.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> {
loop {
let state = T::buffered_state();
let mut rx_reader = unsafe { state.rx_buf.reader() };
let n = rx_reader.pop(|data| {
let n = data.len().min(buf.len());
buf[..n].copy_from_slice(&data[..n]);
n
});
let data = rx_reader.pop_slice();
if n > 0 {
// FIXME:
// (Re-)Enable the interrupt to receive more data in case it was
// disabled because the buffer was full.
// let regs = T::regs();
// unsafe {
// regs.uartimsc().write_set(|w| {
// w.set_rxim(true);
// w.set_rtim(true);
// });
// }
if !data.is_empty() {
let len = data.len().min(buf.len());
buf[..len].copy_from_slice(&data[..len]);
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> {
poll_fn(move |cx| {
let state = T::buffered_state();
let empty = state.tx_buf.is_empty();
let mut tx_writer = unsafe { state.tx_buf.writer() };
let n = tx_writer.push(|data| {
let n = data.len().min(buf.len());
data[..n].copy_from_slice(&buf[..n]);
n
});
if n == 0 {
let data = tx_writer.push_slice();
if data.is_empty() {
state.tx_waker.register(cx.waker());
return Poll::Pending;
}
// 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.
let n = data.len().min(buf.len());
data[..n].copy_from_slice(&buf[..n]);
tx_writer.push_done(n);
if empty {
unsafe { T::Interrupt::steal() }.pend();
}
Poll::Ready(Ok(n))
})
.await
@ -316,19 +278,19 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
loop {
let state = T::buffered_state();
let empty = state.tx_buf.is_empty();
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());
data[..n].copy_from_slice(&buf[..n]);
n
});
tx_writer.push_done(n);
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.
if empty {
unsafe { T::Interrupt::steal() }.pend();
}
return Ok(n);
}
}

View File

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

View File

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