stm32/usart: remove instance generic params

This commit is contained in:
Jan Špaček 2024-04-18 18:50:30 +02:00
parent ded1f9d335
commit 183f2f6913
8 changed files with 470 additions and 434 deletions

View File

@ -387,7 +387,6 @@ fn main() {
struct ClockGen<'a> {
rcc_registers: &'a PeripheralRegisters,
chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
force_refcount: HashSet<&'a str>,
refcount_statics: BTreeSet<Ident>,
clock_names: BTreeSet<String>,
@ -397,7 +396,6 @@ fn main() {
let mut clock_gen = ClockGen {
rcc_registers,
chained_muxes: HashMap::new(),
force_refcount: HashSet::from(["usart"]),
refcount_statics: BTreeSet::new(),
clock_names: BTreeSet::new(),
@ -542,7 +540,6 @@ fn main() {
None => (TokenStream::new(), TokenStream::new()),
};
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
let pname = format_ident!("{}", p.name);
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
@ -570,8 +567,7 @@ fn main() {
};
let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
let refcount =
clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
let refcount = *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
let (before_enable, before_disable) = if refcount {
let refcount_static =
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());

View File

@ -1,7 +1,7 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::slice;
use core::sync::atomic::{AtomicBool, Ordering};
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
@ -12,23 +12,26 @@ use embassy_sync::waitqueue::AtomicWaker;
#[cfg(not(any(usart_v1, usart_v2)))]
use super::DePin;
use super::{
clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, BasicInstance, Config, ConfigError, CtsPin, Error,
RtsPin, RxPin, TxPin,
clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance,
Regs, RtsPin, RxPin, TxPin,
};
use crate::gpio::AFType;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::typelevel::Interrupt as _;
use crate::interrupt::{self, InterruptExt};
use crate::time::Hertz;
/// Interrupt handler.
pub struct InterruptHandler<T: BasicInstance> {
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
let state = T::buffered_state();
on_interrupt(T::info().regs, T::buffered_state())
}
}
unsafe fn on_interrupt(r: Regs, state: &'static State) {
// RX
let sr_val = sr(r).read();
// On v1 & v2, reading DR clears the rxne, error and idle interrupt
@ -115,51 +118,57 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
});
}
}
}
}
pub(crate) struct State {
pub(crate) rx_waker: AtomicWaker,
pub(crate) rx_buf: RingBuffer,
pub(crate) tx_waker: AtomicWaker,
pub(crate) tx_buf: RingBuffer,
pub(crate) tx_done: AtomicBool,
pub(super) struct State {
rx_waker: AtomicWaker,
rx_buf: RingBuffer,
tx_waker: AtomicWaker,
tx_buf: RingBuffer,
tx_done: AtomicBool,
tx_rx_refcount: AtomicU8,
}
impl State {
/// Create new state
pub(crate) const fn new() -> Self {
pub(super) const fn new() -> Self {
Self {
rx_buf: RingBuffer::new(),
tx_buf: RingBuffer::new(),
rx_waker: AtomicWaker::new(),
tx_waker: AtomicWaker::new(),
tx_done: AtomicBool::new(true),
tx_rx_refcount: AtomicU8::new(0),
}
}
}
/// Bidirectional buffered UART
pub struct BufferedUart<'d, T: BasicInstance> {
rx: BufferedUartRx<'d, T>,
tx: BufferedUartTx<'d, T>,
pub struct BufferedUart<'d> {
rx: BufferedUartRx<'d>,
tx: BufferedUartTx<'d>,
}
/// Tx-only buffered UART
///
/// Created with [BufferedUart::split]
pub struct BufferedUartTx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
pub struct BufferedUartTx<'d> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
_phantom: PhantomData<&'d mut ()>,
}
/// Rx-only buffered UART
///
/// Created with [BufferedUart::split]
pub struct BufferedUartRx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
pub struct BufferedUartRx<'d> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
_phantom: PhantomData<&'d mut ()>,
}
impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> {
impl<'d> SetConfig for BufferedUart<'d> {
type Config = Config;
type ConfigError = ConfigError;
@ -168,7 +177,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUart<'d, T> {
}
}
impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> {
impl<'d> SetConfig for BufferedUartRx<'d> {
type Config = Config;
type ConfigError = ConfigError;
@ -177,7 +186,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartRx<'d, T> {
}
}
impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
impl<'d> SetConfig for BufferedUartTx<'d> {
type Config = Config;
type ConfigError = ConfigError;
@ -186,9 +195,9 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
}
}
impl<'d, T: BasicInstance> BufferedUart<'d, T> {
impl<'d> BufferedUart<'d> {
/// Create a new bidirectional buffered UART driver
pub fn new(
pub fn new<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -197,15 +206,13 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
rx_buffer: &'d mut [u8],
config: Config,
) -> Result<Self, ConfigError> {
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
}
/// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
pub fn new_with_rtscts(
pub fn new_with_rtscts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -218,13 +225,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(cts, rts);
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
T::info().regs.cr3().write(|w| {
w.set_rtse(true);
w.set_ctse(true);
});
@ -234,7 +239,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
/// Create a new bidirectional buffered UART driver with a driver-enable pin
#[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de(
pub fn new_with_de<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -246,19 +251,17 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(de);
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
T::info().regs.cr3().write(|w| {
w.set_dem(true);
});
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
}
fn new_inner(
fn new_inner<T: Instance>(
_peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -268,17 +271,19 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
) -> Result<Self, ConfigError> {
into_ref!(_peri, rx, tx);
let info = T::info();
let state = T::buffered_state();
let kernel_clock = T::frequency();
let len = tx_buffer.len();
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
let len = rx_buffer.len();
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
let r = T::regs();
let r = info.regs;
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, true, true)?;
configure(info, kernel_clock, &config, true, true)?;
r.cr1().modify(|w| {
w.set_rxneie(true);
@ -288,22 +293,34 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
state.tx_rx_refcount.store(2, Ordering::Relaxed);
Ok(Self {
rx: BufferedUartRx { phantom: PhantomData },
tx: BufferedUartTx { phantom: PhantomData },
rx: BufferedUartRx {
info,
state,
kernel_clock,
_phantom: PhantomData,
},
tx: BufferedUartTx {
info,
state,
kernel_clock,
_phantom: PhantomData,
},
})
}
/// Split the driver into a Tx and Rx part (useful for sending to separate tasks)
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
pub fn split(self) -> (BufferedUartTx<'d>, BufferedUartRx<'d>) {
(self.tx, self.rx)
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?;
reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
T::regs().cr1().modify(|w| {
self.rx.info.regs.cr1().modify(|w| {
w.set_rxneie(true);
w.set_idleie(true);
});
@ -312,10 +329,10 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
}
}
impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
impl<'d> BufferedUartRx<'d> {
async fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
poll_fn(move |cx| {
let state = T::buffered_state();
let state = self.state;
let mut rx_reader = unsafe { state.rx_buf.reader() };
let data = rx_reader.pop_slice();
@ -327,7 +344,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
rx_reader.pop_done(len);
if do_pend {
T::Interrupt::pend();
self.info.interrupt.pend();
}
return Poll::Ready(Ok(len));
@ -341,7 +358,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
loop {
let state = T::buffered_state();
let state = self.state;
let mut rx_reader = unsafe { state.rx_buf.reader() };
let data = rx_reader.pop_slice();
@ -353,7 +370,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
rx_reader.pop_done(len);
if do_pend {
T::Interrupt::pend();
self.info.interrupt.pend();
}
return Ok(len);
@ -363,7 +380,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
async fn fill_buf(&self) -> Result<&[u8], Error> {
poll_fn(move |cx| {
let state = T::buffered_state();
let state = self.state;
let mut rx_reader = unsafe { state.rx_buf.reader() };
let (p, n) = rx_reader.pop_buf();
if n == 0 {
@ -378,20 +395,20 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
}
fn consume(&self, amt: usize) {
let state = T::buffered_state();
let state = self.state;
let mut rx_reader = unsafe { state.rx_buf.reader() };
let full = state.rx_buf.is_full();
rx_reader.pop_done(amt);
if full {
T::Interrupt::pend();
self.info.interrupt.pend();
}
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?;
reconfigure(self.info, self.kernel_clock, config)?;
T::regs().cr1().modify(|w| {
self.info.regs.cr1().modify(|w| {
w.set_rxneie(true);
w.set_idleie(true);
});
@ -400,10 +417,10 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
}
}
impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
impl<'d> BufferedUartTx<'d> {
async fn write(&self, buf: &[u8]) -> Result<usize, Error> {
poll_fn(move |cx| {
let state = T::buffered_state();
let state = self.state;
state.tx_done.store(false, Ordering::Release);
let empty = state.tx_buf.is_empty();
@ -420,7 +437,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
tx_writer.push_done(n);
if empty {
T::Interrupt::pend();
self.info.interrupt.pend();
}
Poll::Ready(Ok(n))
@ -430,7 +447,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
async fn flush(&self) -> Result<(), Error> {
poll_fn(move |cx| {
let state = T::buffered_state();
let state = self.state;
if !state.tx_done.load(Ordering::Acquire) {
state.tx_waker.register(cx.waker());
@ -444,7 +461,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
loop {
let state = T::buffered_state();
let state = self.state;
let empty = state.tx_buf.is_empty();
let mut tx_writer = unsafe { state.tx_buf.writer() };
@ -455,7 +472,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
tx_writer.push_done(n);
if empty {
T::Interrupt::pend();
self.info.interrupt.pend();
}
return Ok(n);
@ -465,7 +482,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
fn blocking_flush(&self) -> Result<(), Error> {
loop {
let state = T::buffered_state();
let state = self.state;
if state.tx_buf.is_empty() {
return Ok(());
}
@ -474,9 +491,9 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?;
reconfigure(self.info, self.kernel_clock, config)?;
T::regs().cr1().modify(|w| {
self.info.regs.cr1().modify(|w| {
w.set_rxneie(true);
w.set_idleie(true);
});
@ -485,65 +502,78 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
}
}
impl<'d, T: BasicInstance> Drop for BufferedUartRx<'d, T> {
impl<'d> Drop for BufferedUartRx<'d> {
fn drop(&mut self) {
let state = T::buffered_state();
let state = self.state;
unsafe {
state.rx_buf.deinit();
// TX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler
if state.tx_buf.len() == 0 {
T::Interrupt::disable();
self.info.interrupt.disable();
}
}
T::disable();
drop_tx_rx(self.info, state);
}
}
impl<'d, T: BasicInstance> Drop for BufferedUartTx<'d, T> {
impl<'d> Drop for BufferedUartTx<'d> {
fn drop(&mut self) {
let state = T::buffered_state();
let state = self.state;
unsafe {
state.tx_buf.deinit();
// RX is inactive if the the buffer is not available.
// We can now unregister the interrupt handler
if state.rx_buf.len() == 0 {
T::Interrupt::disable();
self.info.interrupt.disable();
}
}
T::disable();
drop_tx_rx(self.info, state);
}
}
impl<'d, T: BasicInstance> embedded_io_async::ErrorType for BufferedUart<'d, T> {
fn drop_tx_rx(info: &Info, state: &State) {
// We cannot use atomic subtraction here, because it's not supported for all targets
let is_last_drop = critical_section::with(|_| {
let refcount = state.tx_rx_refcount.load(Ordering::Relaxed);
assert!(refcount >= 1);
state.tx_rx_refcount.store(refcount - 1, Ordering::Relaxed);
refcount == 1
});
if is_last_drop {
info.enable_bit.disable();
}
}
impl<'d> embedded_io_async::ErrorType for BufferedUart<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> {
impl<'d> embedded_io_async::ErrorType for BufferedUartRx<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> {
impl<'d> embedded_io_async::ErrorType for BufferedUartTx<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_io_async::Read for BufferedUart<'d, T> {
impl<'d> embedded_io_async::Read for BufferedUart<'d> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.read(buf).await
}
}
impl<'d, T: BasicInstance> embedded_io_async::Read for BufferedUartRx<'d, T> {
impl<'d> embedded_io_async::Read for BufferedUartRx<'d> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
Self::read(self, buf).await
}
}
impl<'d, T: BasicInstance> embedded_io_async::BufRead for BufferedUart<'d, T> {
impl<'d> embedded_io_async::BufRead for BufferedUart<'d> {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
self.rx.fill_buf().await
}
@ -553,7 +583,7 @@ impl<'d, T: BasicInstance> embedded_io_async::BufRead for BufferedUart<'d, T> {
}
}
impl<'d, T: BasicInstance> embedded_io_async::BufRead for BufferedUartRx<'d, T> {
impl<'d> embedded_io_async::BufRead for BufferedUartRx<'d> {
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
Self::fill_buf(self).await
}
@ -563,7 +593,7 @@ impl<'d, T: BasicInstance> embedded_io_async::BufRead for BufferedUartRx<'d, T>
}
}
impl<'d, T: BasicInstance> embedded_io_async::Write for BufferedUart<'d, T> {
impl<'d> embedded_io_async::Write for BufferedUart<'d> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.write(buf).await
}
@ -573,7 +603,7 @@ impl<'d, T: BasicInstance> embedded_io_async::Write for BufferedUart<'d, T> {
}
}
impl<'d, T: BasicInstance> embedded_io_async::Write for BufferedUartTx<'d, T> {
impl<'d> embedded_io_async::Write for BufferedUartTx<'d> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
Self::write(self, buf).await
}
@ -583,19 +613,19 @@ impl<'d, T: BasicInstance> embedded_io_async::Write for BufferedUartTx<'d, T> {
}
}
impl<'d, T: BasicInstance> embedded_io::Read for BufferedUart<'d, T> {
impl<'d> embedded_io::Read for BufferedUart<'d> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.blocking_read(buf)
}
}
impl<'d, T: BasicInstance> embedded_io::Read for BufferedUartRx<'d, T> {
impl<'d> embedded_io::Read for BufferedUartRx<'d> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.blocking_read(buf)
}
}
impl<'d, T: BasicInstance> embedded_io::Write for BufferedUart<'d, T> {
impl<'d> embedded_io::Write for BufferedUart<'d> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.blocking_write(buf)
}
@ -605,7 +635,7 @@ impl<'d, T: BasicInstance> embedded_io::Write for BufferedUart<'d, T> {
}
}
impl<'d, T: BasicInstance> embedded_io::Write for BufferedUartTx<'d, T> {
impl<'d> embedded_io::Write for BufferedUartTx<'d> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
Self::blocking_write(self, buf)
}
@ -615,11 +645,11 @@ impl<'d, T: BasicInstance> embedded_io::Write for BufferedUartTx<'d, T> {
}
}
impl<'d, T: BasicInstance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> {
impl<'d> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
let r = T::regs();
let r = self.info.regs;
unsafe {
let sr = sr(r).read();
if sr.pe() {
@ -643,7 +673,7 @@ impl<'d, T: BasicInstance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<
}
}
impl<'d, T: BasicInstance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
impl<'d> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d> {
type Error = Error;
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@ -662,7 +692,7 @@ impl<'d, T: BasicInstance> embedded_hal_02::blocking::serial::Write<u8> for Buff
}
}
impl<'d, T: BasicInstance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> {
impl<'d> embedded_hal_02::serial::Read<u8> for BufferedUart<'d> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@ -670,7 +700,7 @@ impl<'d, T: BasicInstance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d
}
}
impl<'d, T: BasicInstance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> {
impl<'d> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d> {
type Error = Error;
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@ -689,25 +719,25 @@ impl<'d, T: BasicInstance> embedded_hal_02::blocking::serial::Write<u8> for Buff
}
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> {
impl<'d> embedded_hal_nb::serial::ErrorType for BufferedUart<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> {
impl<'d> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> {
impl<'d> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d> {
type Error = Error;
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> {
impl<'d> embedded_hal_nb::serial::Read for BufferedUartRx<'d> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
embedded_hal_02::serial::Read::read(self)
}
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
impl<'d> embedded_hal_nb::serial::Write for BufferedUartTx<'d> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
}
@ -717,13 +747,13 @@ impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d,
}
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> {
impl<'d> embedded_hal_nb::serial::Read for BufferedUart<'d> {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> {
impl<'d> embedded_hal_nb::serial::Write for BufferedUart<'d> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
}

View File

@ -4,7 +4,7 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::sync::atomic::{compiler_fence, AtomicU8, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
@ -15,7 +15,8 @@ use futures_util::future::{select, Either};
use crate::dma::ChannelAndRequest;
use crate::gpio::{AFType, AnyPin, SealedPin};
use crate::interrupt::typelevel::Interrupt;
use crate::interrupt::typelevel::Interrupt as _;
use crate::interrupt::{self, Interrupt, InterruptExt};
use crate::mode::{Async, Blocking, Mode};
#[allow(unused_imports)]
#[cfg(not(any(usart_v1, usart_v2)))]
@ -27,19 +28,22 @@ use crate::pac::usart::Lpuart as Regs;
#[cfg(any(usart_v1, usart_v2))]
use crate::pac::usart::Usart as Regs;
use crate::pac::usart::{regs, vals};
use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
use crate::time::Hertz;
use crate::{interrupt, peripherals, Peripheral};
use crate::Peripheral;
/// Interrupt handler.
pub struct InterruptHandler<T: BasicInstance> {
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
let s = T::state();
on_interrupt(T::info().regs, T::state())
}
}
unsafe fn on_interrupt(r: Regs, s: &'static State) {
let (sr, cr1, cr3) = (sr(r).read(), r.cr1().read(), r.cr3().read());
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ne() || sr.ore()) && cr3.eie());
@ -75,7 +79,6 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
compiler_fence(Ordering::SeqCst);
s.rx_waker.wake();
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@ -239,12 +242,12 @@ enum ReadCompletionEvent {
///
/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
pub struct Uart<'d, T: BasicInstance, M: Mode> {
tx: UartTx<'d, T, M>,
rx: UartRx<'d, T, M>,
pub struct Uart<'d, M: Mode> {
tx: UartTx<'d, M>,
rx: UartRx<'d, M>,
}
impl<'d, T: BasicInstance, M: Mode> SetConfig for Uart<'d, T, M> {
impl<'d, M: Mode> SetConfig for Uart<'d, M> {
type Config = Config;
type ConfigError = ConfigError;
@ -258,15 +261,18 @@ impl<'d, T: BasicInstance, M: Mode> SetConfig for Uart<'d, T, M> {
///
/// Can be obtained from [`Uart::split`], or can be constructed independently,
/// if you do not need the receiving half of the driver.
pub struct UartTx<'d, T: BasicInstance, M: Mode> {
_phantom: PhantomData<(T, M)>,
pub struct UartTx<'d, M: Mode> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
tx: Option<PeripheralRef<'d, AnyPin>>,
cts: Option<PeripheralRef<'d, AnyPin>>,
de: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>,
_phantom: PhantomData<M>,
}
impl<'d, T: BasicInstance, M: Mode> SetConfig for UartTx<'d, T, M> {
impl<'d, M: Mode> SetConfig for UartTx<'d, M> {
type Config = Config;
type ConfigError = ConfigError;
@ -304,17 +310,20 @@ impl<'d, T: BasicInstance, M: Mode> SetConfig for UartTx<'d, T, M> {
/// store data received between calls.
///
/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043).
pub struct UartRx<'d, T: BasicInstance, M: Mode> {
_phantom: PhantomData<(T, M)>,
pub struct UartRx<'d, M: Mode> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
rx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
rx_dma: Option<ChannelAndRequest<'d>>,
detect_previous_overrun: bool,
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr,
_phantom: PhantomData<M>,
}
impl<'d, T: BasicInstance, M: Mode> SetConfig for UartRx<'d, T, M> {
impl<'d, M: Mode> SetConfig for UartRx<'d, M> {
type Config = Config;
type ConfigError = ConfigError;
@ -323,9 +332,9 @@ impl<'d, T: BasicInstance, M: Mode> SetConfig for UartRx<'d, T, M> {
}
}
impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
impl<'d> UartTx<'d, Async> {
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new(
pub fn new<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
@ -341,7 +350,7 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
}
/// Create a new tx-only UART with a clear-to-send pin
pub fn new_with_cts(
pub fn new_with_cts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
@ -359,7 +368,7 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
/// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
let r = self.info.regs;
// Disable Receiver for Half-Duplex mode
if r.cr3().read().hdsel() {
@ -377,21 +386,17 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
Ok(())
}
async fn flush_inner() -> Result<(), Error> {
Self::blocking_flush_inner()
}
/// Wait until transmission complete
pub async fn flush(&mut self) -> Result<(), Error> {
Self::flush_inner().await
self.blocking_flush()
}
}
impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
impl<'d> UartTx<'d, Blocking> {
/// Create a new blocking tx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new_blocking(
pub fn new_blocking<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
config: Config,
@ -400,7 +405,7 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
}
/// Create a new blocking tx-only UART with a clear-to-send pin
pub fn new_blocking_with_cts(
pub fn new_blocking_with_cts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
@ -416,8 +421,8 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Blocking> {
}
}
impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
fn new_inner(
impl<'d, M: Mode> UartTx<'d, M> {
fn new_inner<T: Instance>(
_peri: impl Peripheral<P = T> + 'd,
tx: Option<PeripheralRef<'d, AnyPin>>,
cts: Option<PeripheralRef<'d, AnyPin>>,
@ -426,16 +431,21 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
) -> Result<Self, ConfigError> {
T::enable_and_reset();
let r = T::regs();
let info = T::info();
let state = T::state();
let kernel_clock = T::frequency();
let r = info.regs;
r.cr3().modify(|w| {
w.set_ctse(cts.is_some());
});
configure(r, &config, T::frequency(), T::KIND, false, true)?;
configure(info, kernel_clock, &config, false, true)?;
// create state once!
let _s = T::state();
state.tx_rx_refcount.store(1, Ordering::Relaxed);
Ok(Self {
info,
state,
kernel_clock,
tx,
cts,
de: None,
@ -446,12 +456,12 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
reconfigure(self.info, self.kernel_clock, config)
}
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
let r = self.info.regs;
// Disable Receiver for Half-Duplex mode
if r.cr3().read().hdsel() {
@ -465,28 +475,29 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
Ok(())
}
fn blocking_flush_inner() -> Result<(), Error> {
let r = T::regs();
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
blocking_flush(self.info)
}
}
fn blocking_flush(info: &Info) -> Result<(), Error> {
let r = info.regs;
while !sr(r).read().tc() {}
// Enable Receiver after transmission complete for Half-Duplex mode
if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(true));
}
Ok(())
}
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
Self::blocking_flush_inner()
}
Ok(())
}
impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
impl<'d> UartRx<'d, Async> {
/// Create a new rx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
pub fn new(
pub fn new<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -497,7 +508,7 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
}
/// Create a new rx-only UART with a request-to-send pin
pub fn new_with_rts(
pub fn new_with_rts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -531,11 +542,11 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
buffer: &mut [u8],
enable_idle_line_detection: bool,
) -> Result<ReadCompletionEvent, Error> {
let r = T::regs();
let r = self.info.regs;
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() {
UartTx::<'d, T, Async>::flush_inner().await?;
blocking_flush(self.info)?;
}
// make sure USART state is restored to neutral state when this future is dropped
@ -565,7 +576,7 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
// Start USART DMA
// will not do anything yet because DMAR is not yet set
// future which will complete when DMA Read request completes
let transfer = unsafe { ch.read(rdr(T::regs()), buffer, Default::default()) };
let transfer = unsafe { ch.read(rdr(r), buffer, Default::default()) };
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
if !self.detect_previous_overrun {
@ -640,9 +651,8 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
compiler_fence(Ordering::SeqCst);
// future which completes when idle line or error is detected
let s = self.state;
let abort = poll_fn(move |cx| {
let s = T::state();
s.rx_waker.register(cx.waker());
let sr = sr(r).read();
@ -728,11 +738,11 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
}
}
impl<'d, T: BasicInstance> UartRx<'d, T, Blocking> {
impl<'d> UartRx<'d, Blocking> {
/// Create a new rx-only UART with no hardware flow control.
///
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
pub fn new_blocking(
pub fn new_blocking<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
config: Config,
@ -741,7 +751,7 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Blocking> {
}
/// Create a new rx-only UART with a request-to-send pin
pub fn new_blocking_with_rts(
pub fn new_blocking_with_rts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
@ -757,8 +767,8 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Blocking> {
}
}
impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
fn new_inner(
impl<'d, M: Mode> UartRx<'d, M> {
fn new_inner<T: Instance>(
_peri: impl Peripheral<P = T> + 'd,
rx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
@ -767,20 +777,25 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
) -> Result<Self, ConfigError> {
T::enable_and_reset();
let r = T::regs();
let info = T::info();
let state = T::state();
let kernel_clock = T::frequency();
let r = info.regs;
r.cr3().write(|w| {
w.set_rtse(rts.is_some());
});
configure(r, &config, T::frequency(), T::KIND, true, false)?;
configure(info, kernel_clock, &config, true, false)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
state.tx_rx_refcount.store(1, Ordering::Relaxed);
Ok(Self {
_phantom: PhantomData,
info,
state,
kernel_clock,
rx,
rts,
rx_dma,
@ -792,12 +807,12 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
reconfigure(self.info, self.kernel_clock, config)
}
#[cfg(any(usart_v1, usart_v2))]
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
let r = self.info.regs;
loop {
// Handle all buffered error flags.
if self.buffered_sr.pe() {
@ -830,7 +845,7 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
#[cfg(any(usart_v3, usart_v4))]
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
let r = self.info.regs;
let sr = r.isr().read();
if sr.pe() {
r.icr().write(|w| w.set_pe(true));
@ -850,7 +865,7 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
/// Read a single u8 if there is one available, otherwise return WouldBlock
pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs();
let r = self.info.regs;
if self.check_rx_flags()? {
Ok(unsafe { rdr(r).read_volatile() })
} else {
@ -860,11 +875,11 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs();
let r = self.info.regs;
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
if r.cr3().read().hdsel() {
UartTx::<'d, T, M>::blocking_flush_inner()?;
blocking_flush(self.info)?;
}
for b in buffer {
@ -875,26 +890,39 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
}
}
impl<'d, T: BasicInstance, M: Mode> Drop for UartTx<'d, T, M> {
impl<'d, M: Mode> Drop for UartTx<'d, M> {
fn drop(&mut self) {
self.tx.as_ref().map(|x| x.set_as_disconnected());
self.cts.as_ref().map(|x| x.set_as_disconnected());
self.de.as_ref().map(|x| x.set_as_disconnected());
T::disable();
drop_tx_rx(self.info, self.state);
}
}
impl<'d, T: BasicInstance, M: Mode> Drop for UartRx<'d, T, M> {
impl<'d, M: Mode> Drop for UartRx<'d, M> {
fn drop(&mut self) {
self.rx.as_ref().map(|x| x.set_as_disconnected());
self.rts.as_ref().map(|x| x.set_as_disconnected());
T::disable();
drop_tx_rx(self.info, self.state);
}
}
impl<'d, T: BasicInstance> Uart<'d, T, Async> {
fn drop_tx_rx(info: &Info, state: &State) {
// We cannot use atomic subtraction here, because it's not supported for all targets
let is_last_drop = critical_section::with(|_| {
let refcount = state.tx_rx_refcount.load(Ordering::Relaxed);
assert!(refcount >= 1);
state.tx_rx_refcount.store(refcount - 1, Ordering::Relaxed);
refcount == 1
});
if is_last_drop {
info.enable_bit.disable();
}
}
impl<'d> Uart<'d, Async> {
/// Create a new bidirectional UART
pub fn new(
pub fn new<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -917,7 +945,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
}
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_with_rtscts(
pub fn new_with_rtscts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -943,7 +971,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de(
pub fn new_with_de<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -977,7 +1005,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[doc(alias("HDSEL"))]
pub fn new_half_duplex(
pub fn new_half_duplex<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -1015,7 +1043,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[cfg(not(any(usart_v1, usart_v2)))]
#[doc(alias("HDSEL"))]
pub fn new_half_duplex_on_rx(
pub fn new_half_duplex_on_rx<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -1055,9 +1083,9 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
}
}
impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
impl<'d> Uart<'d, Blocking> {
/// Create a new blocking bidirectional UART.
pub fn new_blocking(
pub fn new_blocking<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -1077,7 +1105,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
}
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_blocking_with_rtscts(
pub fn new_blocking_with_rtscts<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -1100,7 +1128,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_blocking_with_de(
pub fn new_blocking_with_de<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -1131,7 +1159,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex(
pub fn new_blocking_half_duplex<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
mut config: Config,
@ -1166,7 +1194,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
/// on the line must be managed by software (for instance by using a centralized arbiter).
#[cfg(not(any(usart_v1, usart_v2)))]
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex_on_rx(
pub fn new_blocking_half_duplex_on_rx<T: Instance>(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
mut config: Config,
@ -1188,8 +1216,8 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
}
}
impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
fn new_inner(
impl<'d, M: Mode> Uart<'d, M> {
fn new_inner<T: Instance>(
_peri: impl Peripheral<P = T> + 'd,
rx: Option<PeripheralRef<'d, AnyPin>>,
tx: Option<PeripheralRef<'d, AnyPin>>,
@ -1200,11 +1228,12 @@ impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
rx_dma: Option<ChannelAndRequest<'d>>,
config: Config,
) -> Result<Self, ConfigError> {
// UartRx and UartTx have one refcount each.
T::enable_and_reset();
T::enable_and_reset();
let r = T::regs();
let info = T::info();
let state = T::state();
let kernel_clock = T::frequency();
let r = info.regs;
r.cr3().write(|w| {
w.set_rtse(rts.is_some());
@ -1212,17 +1241,19 @@ impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
#[cfg(not(any(usart_v1, usart_v2)))]
w.set_dem(de.is_some());
});
configure(r, &config, T::frequency(), T::KIND, true, true)?;
configure(info, kernel_clock, &config, true, true)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
state.tx_rx_refcount.store(2, Ordering::Relaxed);
Ok(Self {
tx: UartTx {
_phantom: PhantomData,
info,
state,
kernel_clock,
tx,
cts,
de,
@ -1230,6 +1261,9 @@ impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
},
rx: UartRx {
_phantom: PhantomData,
info,
state,
kernel_clock,
rx,
rts,
rx_dma,
@ -1263,32 +1297,34 @@ impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
/// Split the Uart into a transmitter and receiver, which is
/// particularly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
(self.tx, self.rx)
}
}
fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> {
T::Interrupt::disable();
let r = T::regs();
fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
info.interrupt.disable();
let r = info.regs;
let cr = r.cr1().read();
configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?;
configure(info, kernel_clock, config, cr.re(), cr.te())?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
info.interrupt.unpend();
unsafe { info.interrupt.enable() };
Ok(())
}
fn configure(
r: Regs,
info: &Info,
kernel_clock: Hertz,
config: &Config,
pclk_freq: Hertz,
kind: Kind,
enable_rx: bool,
enable_tx: bool,
) -> Result<(), ConfigError> {
let r = info.regs;
let kind = info.kind;
if !enable_rx && !enable_tx {
return Err(ConfigError::RxOrTxNotEnabled);
}
@ -1348,7 +1384,7 @@ fn configure(
let mut over8 = false;
let mut found_brr = None;
for &(presc, _presc_val) in &DIVS {
let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul);
let brr = calculate_brr(config.baudrate, kernel_clock.0, presc as u32, mul);
trace!(
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
presc,
@ -1389,7 +1425,7 @@ fn configure(
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
oversampling,
config.baudrate,
pclk_freq.0 / brr * mul
kernel_clock.0 / brr * mul
);
r.cr2().write(|w| {
@ -1458,14 +1494,14 @@ fn configure(
Ok(())
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
@ -1475,14 +1511,14 @@ impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8>
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
@ -1504,25 +1540,25 @@ impl embedded_hal_nb::serial::Error for Error {
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> {
type Error = Error;
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> {
type Error = Error;
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> {
type Error = Error;
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
@ -1532,13 +1568,13 @@ impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
@ -1554,24 +1590,15 @@ impl embedded_io::Error for Error {
}
}
impl<T, M: Mode> embedded_io::ErrorType for Uart<'_, T, M>
where
T: BasicInstance,
{
impl<M: Mode> embedded_io::ErrorType for Uart<'_, M> {
type Error = Error;
}
impl<T, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M>
where
T: BasicInstance,
{
impl<M: Mode> embedded_io::ErrorType for UartTx<'_, M> {
type Error = Error;
}
impl<T, M: Mode> embedded_io::Write for Uart<'_, T, M>
where
T: BasicInstance,
{
impl<M: Mode> embedded_io::Write for Uart<'_, M> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
@ -1582,10 +1609,7 @@ where
}
}
impl<T, M: Mode> embedded_io::Write for UartTx<'_, T, M>
where
T: BasicInstance,
{
impl<M: Mode> embedded_io::Write for UartTx<'_, M> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
@ -1596,10 +1620,7 @@ where
}
}
impl<T> embedded_io_async::Write for Uart<'_, T, Async>
where
T: BasicInstance,
{
impl embedded_io_async::Write for Uart<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
@ -1610,10 +1631,7 @@ where
}
}
impl<T> embedded_io_async::Write for UartTx<'_, T, Async>
where
T: BasicInstance,
{
impl embedded_io_async::Write for UartTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
@ -1686,72 +1704,75 @@ enum Kind {
struct State {
rx_waker: AtomicWaker,
tx_rx_refcount: AtomicU8,
}
impl State {
const fn new() -> Self {
Self {
rx_waker: AtomicWaker::new(),
tx_rx_refcount: AtomicU8::new(0),
}
}
}
trait SealedBasicInstance: crate::rcc::RccPeripheral {
const KIND: Kind;
struct Info {
regs: Regs,
enable_bit: ClockEnableBit,
interrupt: Interrupt,
kind: Kind,
}
fn regs() -> Regs;
#[allow(private_interfaces)]
pub(crate) trait SealedInstance: crate::rcc::RccPeripheral {
fn info() -> &'static Info;
fn state() -> &'static State;
fn buffered_state() -> &'static buffered::State;
}
trait SealedFullInstance: SealedBasicInstance {
#[allow(unused)]
fn regs_uart() -> crate::pac::usart::Usart;
}
/// Basic UART driver instance
/// USART peripheral instance trait.
#[allow(private_bounds)]
pub trait BasicInstance: Peripheral<P = Self> + SealedBasicInstance + 'static + Send {
/// Interrupt for this instance.
pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
/// Interrupt for this peripheral.
type Interrupt: interrupt::typelevel::Interrupt;
}
/// Full UART driver instance
#[allow(private_bounds)]
pub trait FullInstance: SealedFullInstance {}
pin_trait!(RxPin, Instance);
pin_trait!(TxPin, Instance);
pin_trait!(CtsPin, Instance);
pin_trait!(RtsPin, Instance);
pin_trait!(CkPin, Instance);
pin_trait!(DePin, Instance);
pin_trait!(RxPin, BasicInstance);
pin_trait!(TxPin, BasicInstance);
pin_trait!(CtsPin, BasicInstance);
pin_trait!(RtsPin, BasicInstance);
pin_trait!(CkPin, BasicInstance);
pin_trait!(DePin, BasicInstance);
dma_trait!(TxDma, BasicInstance);
dma_trait!(RxDma, BasicInstance);
dma_trait!(TxDma, Instance);
dma_trait!(RxDma, Instance);
macro_rules! impl_usart {
($inst:ident, $irq:ident, $kind:expr) => {
impl SealedBasicInstance for crate::peripherals::$inst {
const KIND: Kind = $kind;
fn regs() -> Regs {
unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
#[allow(private_interfaces)]
impl SealedInstance for crate::peripherals::$inst {
fn info() -> &'static Info {
static INFO: Info = Info {
regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
enable_bit: crate::peripherals::$inst::ENABLE_BIT,
interrupt: crate::interrupt::typelevel::$irq::IRQ,
kind: $kind,
};
&INFO
}
fn state() -> &'static crate::usart::State {
static STATE: crate::usart::State = crate::usart::State::new();
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
}
fn buffered_state() -> &'static buffered::State {
static STATE: buffered::State = buffered::State::new();
&STATE
static BUFFERED_STATE: buffered::State = buffered::State::new();
&BUFFERED_STATE
}
}
impl BasicInstance for peripherals::$inst {
impl Instance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
@ -1761,16 +1782,7 @@ foreach_interrupt!(
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
impl_usart!($inst, $irq, Kind::Lpuart);
};
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
impl_usart!($inst, $irq, Kind::Uart);
impl SealedFullInstance for peripherals::$inst {
fn regs_uart() -> crate::pac::usart::Usart {
crate::pac::$inst
}
}
impl FullInstance for peripherals::$inst {}
};
);

View File

@ -1,5 +1,4 @@
use core::future::poll_fn;
use core::marker::PhantomData;
use core::mem;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
@ -7,20 +6,23 @@ use core::task::Poll;
use embassy_embedded_hal::SetConfig;
use futures_util::future::{select, Either};
use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, ConfigError, Error, UartRx};
use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx};
use crate::dma::ReadableRingBuffer;
use crate::mode::Async;
use crate::time::Hertz;
use crate::usart::{Regs, Sr};
/// Rx-only Ring-buffered UART Driver
///
/// Created with [UartRx::into_ring_buffered]
pub struct RingBufferedUartRx<'d, T: BasicInstance> {
_phantom: PhantomData<T>,
pub struct RingBufferedUartRx<'d> {
info: &'static Info,
state: &'static State,
kernel_clock: Hertz,
ring_buf: ReadableRingBuffer<'d, u8>,
}
impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
impl<'d> SetConfig for RingBufferedUartRx<'d> {
type Config = Config;
type ConfigError = ConfigError;
@ -29,11 +31,11 @@ impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
}
}
impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
impl<'d> UartRx<'d, Async> {
/// Turn the `UartRx` into a buffered uart which can continously receive in the background
/// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
/// DMA controller, and must be large enough to prevent overflows.
pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T> {
pub fn into_ring_buffered(mut self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d> {
assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
let opts = Default::default();
@ -43,19 +45,24 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
let request = rx_dma.request;
let rx_dma = unsafe { rx_dma.channel.clone_unchecked() };
let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(T::regs()), dma_buf, opts) };
let info = self.info;
let state = self.state;
let kernel_clock = self.kernel_clock;
let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) };
// Don't disable the clock
mem::forget(self);
RingBufferedUartRx {
_phantom: PhantomData,
info,
state,
kernel_clock,
ring_buf,
}
}
}
impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
impl<'d> RingBufferedUartRx<'d> {
/// Clear the ring buffer and start receiving in the background
pub fn start(&mut self) -> Result<(), Error> {
// Clear the ring buffer so that it is ready to receive data
@ -74,7 +81,7 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
reconfigure(self.info, self.kernel_clock, config)
}
/// Start uart background receive
@ -85,7 +92,7 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
// start the dma controller
self.ring_buf.start();
let r = T::regs();
let r = self.info.regs;
// clear all interrupts and DMA Rx Request
r.cr1().modify(|w| {
// disable RXNE interrupt
@ -107,7 +114,7 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
fn teardown_uart(&mut self) {
self.ring_buf.request_stop();
let r = T::regs();
let r = self.info.regs;
// clear all interrupts and DMA Rx Request
r.cr1().modify(|w| {
// disable RXNE interrupt
@ -136,14 +143,14 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
/// Receive in the background is terminated if an error is returned.
/// It must then manually be started again by calling `start()` or by re-calling `read()`.
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let r = T::regs();
let r = self.info.regs;
// Start background receive if it was not already started
if !r.cr3().read().dmar() {
self.start()?;
}
check_for_errors(clear_idle_flag(T::regs()))?;
check_for_errors(clear_idle_flag(r))?;
loop {
match self.ring_buf.read(buf) {
@ -184,15 +191,15 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
});
// Future which completes when idle line is detected
let s = self.state;
let uart = poll_fn(|cx| {
let s = T::state();
s.rx_waker.register(cx.waker());
compiler_fence(Ordering::SeqCst);
// Critical section is needed so that IDLE isn't set after
// our read but before we clear it.
let sr = critical_section::with(|_| clear_idle_flag(T::regs()));
let sr = critical_section::with(|_| clear_idle_flag(self.info.regs));
check_for_errors(sr)?;
@ -211,13 +218,13 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
}
}
impl<T: BasicInstance> Drop for RingBufferedUartRx<'_, T> {
impl Drop for RingBufferedUartRx<'_> {
fn drop(&mut self) {
self.teardown_uart();
T::disable();
super::drop_tx_rx(self.info, self.state);
}
}
/// Return an error result if the Sr register has errors
fn check_for_errors(s: Sr) -> Result<(), Error> {
if s.pe() {
@ -248,17 +255,11 @@ fn clear_idle_flag(r: Regs) -> Sr {
sr
}
impl<T> embedded_io_async::ErrorType for RingBufferedUartRx<'_, T>
where
T: BasicInstance,
{
impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> {
type Error = Error;
}
impl<T> embedded_io_async::Read for RingBufferedUartRx<'_, T>
where
T: BasicInstance,
{
impl embedded_io_async::Read for RingBufferedUartRx<'_> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read(buf).await
}

View File

@ -4,7 +4,6 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::mode::Async;
use embassy_stm32::peripherals::UART7;
use embassy_stm32::usart::{Config, Uart, UartRx};
use embassy_stm32::{bind_interrupts, peripherals, usart};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
}
#[embassy_executor::task]
async fn reader(mut rx: UartRx<'static, UART7, Async>) {
async fn reader(mut rx: UartRx<'static, Async>) {
let mut buf = [0; 8];
loop {
info!("reading...");

View File

@ -4,7 +4,6 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::mode::Async;
use embassy_stm32::peripherals::UART7;
use embassy_stm32::usart::{Config, Uart, UartRx};
use embassy_stm32::{bind_interrupts, peripherals, usart};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
}
#[embassy_executor::task]
async fn reader(mut rx: UartRx<'static, UART7, Async>) {
async fn reader(mut rx: UartRx<'static, Async>) {
let mut buf = [0; 8];
loop {
info!("reading...");

View File

@ -4,7 +4,6 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::mode::Async;
use embassy_stm32::peripherals::UART7;
use embassy_stm32::usart::{Config, Uart, UartRx};
use embassy_stm32::{bind_interrupts, peripherals, usart};
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
}
#[embassy_executor::task]
async fn reader(mut rx: UartRx<'static, UART7, Async>) {
async fn reader(mut rx: UartRx<'static, Async>) {
let mut buf = [0; 8];
loop {
info!("reading...");

View File

@ -52,7 +52,7 @@ async fn main(spawner: Spawner) {
}
#[embassy_executor::task]
async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
async fn transmit_task(mut tx: UartTx<'static, Async>) {
// workaround https://github.com/embassy-rs/embassy/issues/1426
Timer::after_millis(100).await;
@ -75,7 +75,7 @@ async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
}
#[embassy_executor::task]
async fn receive_task(mut rx: RingBufferedUartRx<'static, peris::UART>) {
async fn receive_task(mut rx: RingBufferedUartRx<'static>) {
info!("Ready to receive...");
let mut rng = ChaCha8Rng::seed_from_u64(1337);