mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 16:23:10 +00:00
stm32/usart: remove instance generic params
This commit is contained in:
parent
ded1f9d335
commit
183f2f6913
@ -387,7 +387,6 @@ fn main() {
|
|||||||
struct ClockGen<'a> {
|
struct ClockGen<'a> {
|
||||||
rcc_registers: &'a PeripheralRegisters,
|
rcc_registers: &'a PeripheralRegisters,
|
||||||
chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
|
chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
|
||||||
force_refcount: HashSet<&'a str>,
|
|
||||||
|
|
||||||
refcount_statics: BTreeSet<Ident>,
|
refcount_statics: BTreeSet<Ident>,
|
||||||
clock_names: BTreeSet<String>,
|
clock_names: BTreeSet<String>,
|
||||||
@ -397,7 +396,6 @@ fn main() {
|
|||||||
let mut clock_gen = ClockGen {
|
let mut clock_gen = ClockGen {
|
||||||
rcc_registers,
|
rcc_registers,
|
||||||
chained_muxes: HashMap::new(),
|
chained_muxes: HashMap::new(),
|
||||||
force_refcount: HashSet::from(["usart"]),
|
|
||||||
|
|
||||||
refcount_statics: BTreeSet::new(),
|
refcount_statics: BTreeSet::new(),
|
||||||
clock_names: BTreeSet::new(),
|
clock_names: BTreeSet::new(),
|
||||||
@ -542,7 +540,6 @@ fn main() {
|
|||||||
None => (TokenStream::new(), TokenStream::new()),
|
None => (TokenStream::new(), TokenStream::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
|
|
||||||
let pname = format_ident!("{}", p.name);
|
let pname = format_ident!("{}", p.name);
|
||||||
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||||
let set_en_field = format_ident!("set_{}", en.field.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 en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
|
||||||
|
|
||||||
let refcount =
|
let refcount = *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
|
||||||
clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
|
|
||||||
let (before_enable, before_disable) = if refcount {
|
let (before_enable, before_disable) = if refcount {
|
||||||
let refcount_static =
|
let refcount_static =
|
||||||
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
@ -12,154 +12,163 @@ use embassy_sync::waitqueue::AtomicWaker;
|
|||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
use super::DePin;
|
use super::DePin;
|
||||||
use super::{
|
use super::{
|
||||||
clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, BasicInstance, Config, ConfigError, CtsPin, Error,
|
clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance,
|
||||||
RtsPin, RxPin, TxPin,
|
Regs, RtsPin, RxPin, TxPin,
|
||||||
};
|
};
|
||||||
use crate::gpio::AFType;
|
use crate::gpio::AFType;
|
||||||
use crate::interrupt;
|
use crate::interrupt::typelevel::Interrupt as _;
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::{self, InterruptExt};
|
||||||
|
use crate::time::Hertz;
|
||||||
|
|
||||||
/// Interrupt handler.
|
/// Interrupt handler.
|
||||||
pub struct InterruptHandler<T: BasicInstance> {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
_phantom: PhantomData<T>,
|
_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() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
on_interrupt(T::info().regs, T::buffered_state())
|
||||||
let state = T::buffered_state();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// RX
|
unsafe fn on_interrupt(r: Regs, state: &'static State) {
|
||||||
let sr_val = sr(r).read();
|
// RX
|
||||||
// On v1 & v2, reading DR clears the rxne, error and idle interrupt
|
let sr_val = sr(r).read();
|
||||||
// flags. Keep this close to the SR read to reduce the chance of a
|
// On v1 & v2, reading DR clears the rxne, error and idle interrupt
|
||||||
// flag being set in-between.
|
// flags. Keep this close to the SR read to reduce the chance of a
|
||||||
let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
|
// flag being set in-between.
|
||||||
Some(rdr(r).read_volatile())
|
let dr = if sr_val.rxne() || cfg!(any(usart_v1, usart_v2)) && (sr_val.ore() || sr_val.idle()) {
|
||||||
|
Some(rdr(r).read_volatile())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
clear_interrupt_flags(r, sr_val);
|
||||||
|
|
||||||
|
if sr_val.pe() {
|
||||||
|
warn!("Parity error");
|
||||||
|
}
|
||||||
|
if sr_val.fe() {
|
||||||
|
warn!("Framing error");
|
||||||
|
}
|
||||||
|
if sr_val.ne() {
|
||||||
|
warn!("Noise error");
|
||||||
|
}
|
||||||
|
if sr_val.ore() {
|
||||||
|
warn!("Overrun error");
|
||||||
|
}
|
||||||
|
if sr_val.rxne() {
|
||||||
|
let mut rx_writer = state.rx_buf.writer();
|
||||||
|
let buf = rx_writer.push_slice();
|
||||||
|
if !buf.is_empty() {
|
||||||
|
if let Some(byte) = dr {
|
||||||
|
buf[0] = byte;
|
||||||
|
rx_writer.push_done(1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
||||||
};
|
|
||||||
clear_interrupt_flags(r, sr_val);
|
|
||||||
|
|
||||||
if sr_val.pe() {
|
|
||||||
warn!("Parity error");
|
|
||||||
}
|
|
||||||
if sr_val.fe() {
|
|
||||||
warn!("Framing error");
|
|
||||||
}
|
|
||||||
if sr_val.ne() {
|
|
||||||
warn!("Noise error");
|
|
||||||
}
|
|
||||||
if sr_val.ore() {
|
|
||||||
warn!("Overrun error");
|
|
||||||
}
|
|
||||||
if sr_val.rxne() {
|
|
||||||
let mut rx_writer = state.rx_buf.writer();
|
|
||||||
let buf = rx_writer.push_slice();
|
|
||||||
if !buf.is_empty() {
|
|
||||||
if let Some(byte) = dr {
|
|
||||||
buf[0] = byte;
|
|
||||||
rx_writer.push_done(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
|
|
||||||
}
|
|
||||||
|
|
||||||
if !state.rx_buf.is_empty() {
|
|
||||||
state.rx_waker.wake();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sr_val.idle() {
|
if !state.rx_buf.is_empty() {
|
||||||
state.rx_waker.wake();
|
state.rx_waker.wake();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
|
if sr_val.idle() {
|
||||||
// indicates that all bytes are pushed out from the FIFO.
|
state.rx_waker.wake();
|
||||||
// For other usart variants it shows that last byte from the buffer was just sent.
|
}
|
||||||
if sr_val.tc() {
|
|
||||||
// For others it is cleared above with `clear_interrupt_flags`.
|
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
|
||||||
sr(r).modify(|w| w.set_tc(false));
|
|
||||||
|
|
||||||
|
// With `usart_v4` hardware FIFO is enabled and Transmission complete (TC)
|
||||||
|
// indicates that all bytes are pushed out from the FIFO.
|
||||||
|
// For other usart variants it shows that last byte from the buffer was just sent.
|
||||||
|
if sr_val.tc() {
|
||||||
|
// For others it is cleared above with `clear_interrupt_flags`.
|
||||||
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
|
sr(r).modify(|w| w.set_tc(false));
|
||||||
|
|
||||||
|
r.cr1().modify(|w| {
|
||||||
|
w.set_tcie(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
state.tx_done.store(true, Ordering::Release);
|
||||||
|
state.tx_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TX
|
||||||
|
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| {
|
r.cr1().modify(|w| {
|
||||||
w.set_tcie(false);
|
w.set_txeie(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
state.tx_done.store(true, Ordering::Release);
|
// Enable transmission complete interrupt when last byte is going to be sent out.
|
||||||
state.tx_waker.wake();
|
if buf.len() == 1 {
|
||||||
}
|
|
||||||
|
|
||||||
// TX
|
|
||||||
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| {
|
r.cr1().modify(|w| {
|
||||||
w.set_txeie(true);
|
w.set_tcie(true);
|
||||||
});
|
|
||||||
|
|
||||||
// Enable transmission complete interrupt when last byte is going to be sent out.
|
|
||||||
if buf.len() == 1 {
|
|
||||||
r.cr1().modify(|w| {
|
|
||||||
w.set_tcie(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tdr(r).write_volatile(buf[0].into());
|
|
||||||
tx_reader.pop_done(1);
|
|
||||||
} else {
|
|
||||||
// Disable interrupt until we have something to transmit again.
|
|
||||||
r.cr1().modify(|w| {
|
|
||||||
w.set_txeie(false);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tdr(r).write_volatile(buf[0].into());
|
||||||
|
tx_reader.pop_done(1);
|
||||||
|
} else {
|
||||||
|
// Disable interrupt until we have something to transmit again.
|
||||||
|
r.cr1().modify(|w| {
|
||||||
|
w.set_txeie(false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct State {
|
pub(super) struct State {
|
||||||
pub(crate) rx_waker: AtomicWaker,
|
rx_waker: AtomicWaker,
|
||||||
pub(crate) rx_buf: RingBuffer,
|
rx_buf: RingBuffer,
|
||||||
pub(crate) tx_waker: AtomicWaker,
|
tx_waker: AtomicWaker,
|
||||||
pub(crate) tx_buf: RingBuffer,
|
tx_buf: RingBuffer,
|
||||||
pub(crate) tx_done: AtomicBool,
|
tx_done: AtomicBool,
|
||||||
|
tx_rx_refcount: AtomicU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Create new state
|
pub(super) const fn new() -> Self {
|
||||||
pub(crate) const fn new() -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
rx_buf: RingBuffer::new(),
|
rx_buf: RingBuffer::new(),
|
||||||
tx_buf: RingBuffer::new(),
|
tx_buf: RingBuffer::new(),
|
||||||
rx_waker: AtomicWaker::new(),
|
rx_waker: AtomicWaker::new(),
|
||||||
tx_waker: AtomicWaker::new(),
|
tx_waker: AtomicWaker::new(),
|
||||||
tx_done: AtomicBool::new(true),
|
tx_done: AtomicBool::new(true),
|
||||||
|
tx_rx_refcount: AtomicU8::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bidirectional buffered UART
|
/// Bidirectional buffered UART
|
||||||
pub struct BufferedUart<'d, T: BasicInstance> {
|
pub struct BufferedUart<'d> {
|
||||||
rx: BufferedUartRx<'d, T>,
|
rx: BufferedUartRx<'d>,
|
||||||
tx: BufferedUartTx<'d, T>,
|
tx: BufferedUartTx<'d>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tx-only buffered UART
|
/// Tx-only buffered UART
|
||||||
///
|
///
|
||||||
/// Created with [BufferedUart::split]
|
/// Created with [BufferedUart::split]
|
||||||
pub struct BufferedUartTx<'d, T: BasicInstance> {
|
pub struct BufferedUartTx<'d> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
kernel_clock: Hertz,
|
||||||
|
_phantom: PhantomData<&'d mut ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rx-only buffered UART
|
/// Rx-only buffered UART
|
||||||
///
|
///
|
||||||
/// Created with [BufferedUart::split]
|
/// Created with [BufferedUart::split]
|
||||||
pub struct BufferedUartRx<'d, T: BasicInstance> {
|
pub struct BufferedUartRx<'d> {
|
||||||
phantom: PhantomData<&'d mut T>,
|
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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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
|
/// Create a new bidirectional buffered UART driver
|
||||||
pub fn new(
|
pub fn new<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<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],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Result<Self, ConfigError> {
|
) -> Result<Self, ConfigError> {
|
||||||
// UartRx and UartTx have one refcount ea.
|
|
||||||
T::enable_and_reset();
|
|
||||||
T::enable_and_reset();
|
T::enable_and_reset();
|
||||||
|
|
||||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
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
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
@ -218,13 +225,11 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
) -> Result<Self, ConfigError> {
|
) -> Result<Self, ConfigError> {
|
||||||
into_ref!(cts, rts);
|
into_ref!(cts, rts);
|
||||||
|
|
||||||
// UartRx and UartTx have one refcount ea.
|
|
||||||
T::enable_and_reset();
|
|
||||||
T::enable_and_reset();
|
T::enable_and_reset();
|
||||||
|
|
||||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
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_rtse(true);
|
||||||
w.set_ctse(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
|
/// Create a new bidirectional buffered UART driver with a driver-enable pin
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
@ -246,19 +251,17 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
) -> Result<Self, ConfigError> {
|
) -> Result<Self, ConfigError> {
|
||||||
into_ref!(de);
|
into_ref!(de);
|
||||||
|
|
||||||
// UartRx and UartTx have one refcount ea.
|
|
||||||
T::enable_and_reset();
|
|
||||||
T::enable_and_reset();
|
T::enable_and_reset();
|
||||||
|
|
||||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||||
T::regs().cr3().write(|w| {
|
T::info().regs.cr3().write(|w| {
|
||||||
w.set_dem(true);
|
w.set_dem(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
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,
|
_peri: impl Peripheral<P = T> + '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,
|
||||||
@ -268,17 +271,19 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
) -> Result<Self, ConfigError> {
|
) -> Result<Self, ConfigError> {
|
||||||
into_ref!(_peri, rx, tx);
|
into_ref!(_peri, rx, tx);
|
||||||
|
|
||||||
|
let info = T::info();
|
||||||
let state = T::buffered_state();
|
let state = T::buffered_state();
|
||||||
|
let kernel_clock = T::frequency();
|
||||||
let len = tx_buffer.len();
|
let len = tx_buffer.len();
|
||||||
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||||
let len = rx_buffer.len();
|
let len = rx_buffer.len();
|
||||||
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), 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);
|
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
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| {
|
r.cr1().modify(|w| {
|
||||||
w.set_rxneie(true);
|
w.set_rxneie(true);
|
||||||
@ -288,22 +293,34 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
|
|||||||
T::Interrupt::unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
|
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
rx: BufferedUartRx { phantom: PhantomData },
|
rx: BufferedUartRx {
|
||||||
tx: BufferedUartTx { phantom: PhantomData },
|
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)
|
/// 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)
|
(self.tx, self.rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconfigure the driver
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
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_rxneie(true);
|
||||||
w.set_idleie(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> {
|
async fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let data = rx_reader.pop_slice();
|
let data = rx_reader.pop_slice();
|
||||||
|
|
||||||
@ -327,7 +344,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
|
|||||||
rx_reader.pop_done(len);
|
rx_reader.pop_done(len);
|
||||||
|
|
||||||
if do_pend {
|
if do_pend {
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Poll::Ready(Ok(len));
|
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> {
|
fn blocking_read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let data = rx_reader.pop_slice();
|
let data = rx_reader.pop_slice();
|
||||||
|
|
||||||
@ -353,7 +370,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
|
|||||||
rx_reader.pop_done(len);
|
rx_reader.pop_done(len);
|
||||||
|
|
||||||
if do_pend {
|
if do_pend {
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(len);
|
return Ok(len);
|
||||||
@ -363,7 +380,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
|
|||||||
|
|
||||||
async fn fill_buf(&self) -> Result<&[u8], Error> {
|
async fn fill_buf(&self) -> Result<&[u8], Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let (p, n) = rx_reader.pop_buf();
|
let (p, n) = rx_reader.pop_buf();
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
@ -378,20 +395,20 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn consume(&self, amt: usize) {
|
fn consume(&self, amt: usize) {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let full = state.rx_buf.is_full();
|
let full = state.rx_buf.is_full();
|
||||||
rx_reader.pop_done(amt);
|
rx_reader.pop_done(amt);
|
||||||
if full {
|
if full {
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconfigure the driver
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
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_rxneie(true);
|
||||||
w.set_idleie(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> {
|
async fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
state.tx_done.store(false, Ordering::Release);
|
state.tx_done.store(false, Ordering::Release);
|
||||||
|
|
||||||
let empty = state.tx_buf.is_empty();
|
let empty = state.tx_buf.is_empty();
|
||||||
@ -420,7 +437,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
|||||||
tx_writer.push_done(n);
|
tx_writer.push_done(n);
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(Ok(n))
|
Poll::Ready(Ok(n))
|
||||||
@ -430,7 +447,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
|||||||
|
|
||||||
async fn flush(&self) -> Result<(), Error> {
|
async fn flush(&self) -> Result<(), Error> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
|
|
||||||
if !state.tx_done.load(Ordering::Acquire) {
|
if !state.tx_done.load(Ordering::Acquire) {
|
||||||
state.tx_waker.register(cx.waker());
|
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> {
|
fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
let empty = state.tx_buf.is_empty();
|
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() };
|
||||||
@ -455,7 +472,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
|||||||
tx_writer.push_done(n);
|
tx_writer.push_done(n);
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
T::Interrupt::pend();
|
self.info.interrupt.pend();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(n);
|
return Ok(n);
|
||||||
@ -465,7 +482,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
|||||||
|
|
||||||
fn blocking_flush(&self) -> Result<(), Error> {
|
fn blocking_flush(&self) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
if state.tx_buf.is_empty() {
|
if state.tx_buf.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -474,9 +491,9 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
|
|||||||
|
|
||||||
/// Reconfigure the driver
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
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_rxneie(true);
|
||||||
w.set_idleie(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) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
unsafe {
|
unsafe {
|
||||||
state.rx_buf.deinit();
|
state.rx_buf.deinit();
|
||||||
|
|
||||||
// TX is inactive if the the buffer is not available.
|
// TX is inactive if the the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if state.tx_buf.len() == 0 {
|
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) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
let state = self.state;
|
||||||
unsafe {
|
unsafe {
|
||||||
state.tx_buf.deinit();
|
state.tx_buf.deinit();
|
||||||
|
|
||||||
// RX is inactive if the the buffer is not available.
|
// RX is inactive if the the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if state.rx_buf.len() == 0 {
|
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;
|
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;
|
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;
|
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> {
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.rx.read(buf).await
|
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> {
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
Self::read(self, buf).await
|
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> {
|
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||||
self.rx.fill_buf().await
|
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> {
|
async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
|
||||||
Self::fill_buf(self).await
|
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> {
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.tx.write(buf).await
|
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> {
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
Self::write(self, buf).await
|
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> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.rx.blocking_read(buf)
|
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> {
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_read(buf)
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.tx.blocking_write(buf)
|
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> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
Self::blocking_write(self, buf)
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
unsafe {
|
unsafe {
|
||||||
let sr = sr(r).read();
|
let sr = sr(r).read();
|
||||||
if sr.pe() {
|
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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::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;
|
type Error = Error;
|
||||||
|
|
||||||
fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::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;
|
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;
|
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;
|
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> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
embedded_hal_02::serial::Read::read(self)
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
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>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
embedded_hal_02::serial::Read::read(&mut self.rx)
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicU8, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
@ -15,7 +15,8 @@ use futures_util::future::{select, Either};
|
|||||||
|
|
||||||
use crate::dma::ChannelAndRequest;
|
use crate::dma::ChannelAndRequest;
|
||||||
use crate::gpio::{AFType, AnyPin, SealedPin};
|
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};
|
use crate::mode::{Async, Blocking, Mode};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
@ -27,57 +28,59 @@ use crate::pac::usart::Lpuart as Regs;
|
|||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
use crate::pac::usart::Usart as Regs;
|
use crate::pac::usart::Usart as Regs;
|
||||||
use crate::pac::usart::{regs, vals};
|
use crate::pac::usart::{regs, vals};
|
||||||
|
use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::{interrupt, peripherals, Peripheral};
|
use crate::Peripheral;
|
||||||
|
|
||||||
/// Interrupt handler.
|
/// Interrupt handler.
|
||||||
pub struct InterruptHandler<T: BasicInstance> {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
_phantom: PhantomData<T>,
|
_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() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
on_interrupt(T::info().regs, T::state())
|
||||||
let s = T::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());
|
|
||||||
if has_errors {
|
|
||||||
// clear all interrupts and DMA Rx Request
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
} else if cr1.idleie() && sr.idle() {
|
|
||||||
// IDLE detected: no more data will come
|
|
||||||
r.cr1().modify(|w| {
|
|
||||||
// disable idle line detection
|
|
||||||
w.set_idleie(false);
|
|
||||||
});
|
|
||||||
} else 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
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
s.rx_waker.wake();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
if has_errors {
|
||||||
|
// clear all interrupts and DMA Rx Request
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
} else if cr1.idleie() && sr.idle() {
|
||||||
|
// IDLE detected: no more data will come
|
||||||
|
r.cr1().modify(|w| {
|
||||||
|
// disable idle line detection
|
||||||
|
w.set_idleie(false);
|
||||||
|
});
|
||||||
|
} else 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
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
s.rx_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
/// Number of data bits
|
/// Number of data bits
|
||||||
@ -239,12 +242,12 @@ enum ReadCompletionEvent {
|
|||||||
///
|
///
|
||||||
/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
|
/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`]
|
||||||
/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
|
/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`.
|
||||||
pub struct Uart<'d, T: BasicInstance, M: Mode> {
|
pub struct Uart<'d, M: Mode> {
|
||||||
tx: UartTx<'d, T, M>,
|
tx: UartTx<'d, M>,
|
||||||
rx: UartRx<'d, T, 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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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,
|
/// Can be obtained from [`Uart::split`], or can be constructed independently,
|
||||||
/// if you do not need the receiving half of the driver.
|
/// if you do not need the receiving half of the driver.
|
||||||
pub struct UartTx<'d, T: BasicInstance, M: Mode> {
|
pub struct UartTx<'d, M: Mode> {
|
||||||
_phantom: PhantomData<(T, M)>,
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
kernel_clock: Hertz,
|
||||||
tx: Option<PeripheralRef<'d, AnyPin>>,
|
tx: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
de: Option<PeripheralRef<'d, AnyPin>>,
|
de: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
type ConfigError = ConfigError;
|
||||||
|
|
||||||
@ -304,17 +310,20 @@ impl<'d, T: BasicInstance, M: Mode> SetConfig for UartTx<'d, T, M> {
|
|||||||
/// store data received between calls.
|
/// store data received between calls.
|
||||||
///
|
///
|
||||||
/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043).
|
/// Also see [this github comment](https://github.com/embassy-rs/embassy/pull/2185#issuecomment-1810047043).
|
||||||
pub struct UartRx<'d, T: BasicInstance, M: Mode> {
|
pub struct UartRx<'d, M: Mode> {
|
||||||
_phantom: PhantomData<(T, M)>,
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
kernel_clock: Hertz,
|
||||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||||
detect_previous_overrun: bool,
|
detect_previous_overrun: bool,
|
||||||
#[cfg(any(usart_v1, usart_v2))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
buffered_sr: stm32_metapac::usart::regs::Sr,
|
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 Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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.
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
tx_dma: impl Peripheral<P = impl TxDma<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
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
cts: impl Peripheral<P = impl CtsPin<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
|
/// Initiate an asynchronous UART write
|
||||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
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
|
// Disable Receiver for Half-Duplex mode
|
||||||
if r.cr3().read().hdsel() {
|
if r.cr3().read().hdsel() {
|
||||||
@ -377,21 +386,17 @@ impl<'d, T: BasicInstance> UartTx<'d, T, Async> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn flush_inner() -> Result<(), Error> {
|
|
||||||
Self::blocking_flush_inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wait until transmission complete
|
/// Wait until transmission complete
|
||||||
pub async fn flush(&mut self) -> Result<(), Error> {
|
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.
|
/// 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.
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
config: Config,
|
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
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
cts: impl Peripheral<P = impl CtsPin<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> {
|
impl<'d, M: Mode> UartTx<'d, M> {
|
||||||
fn new_inner(
|
fn new_inner<T: Instance>(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: Option<PeripheralRef<'d, AnyPin>>,
|
tx: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
cts: 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> {
|
) -> Result<Self, ConfigError> {
|
||||||
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().modify(|w| {
|
r.cr3().modify(|w| {
|
||||||
w.set_ctse(cts.is_some());
|
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!
|
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||||
let _s = T::state();
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
info,
|
||||||
|
state,
|
||||||
|
kernel_clock,
|
||||||
tx,
|
tx,
|
||||||
cts,
|
cts,
|
||||||
de: None,
|
de: None,
|
||||||
@ -446,12 +456,12 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
|
|||||||
|
|
||||||
/// Reconfigure the driver
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
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
|
/// Perform a blocking UART write
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
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
|
// Disable Receiver for Half-Duplex mode
|
||||||
if r.cr3().read().hdsel() {
|
if r.cr3().read().hdsel() {
|
||||||
@ -465,28 +475,29 @@ impl<'d, T: BasicInstance, M: Mode> UartTx<'d, T, M> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blocking_flush_inner() -> Result<(), Error> {
|
|
||||||
let r = T::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
|
/// Block until transmission complete
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
Self::blocking_flush_inner()
|
blocking_flush(self.info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
|
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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> UartRx<'d, Async> {
|
||||||
/// Create a new rx-only UART with no hardware flow control.
|
/// 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.
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<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
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<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],
|
buffer: &mut [u8],
|
||||||
enable_idle_line_detection: bool,
|
enable_idle_line_detection: bool,
|
||||||
) -> Result<ReadCompletionEvent, Error> {
|
) -> 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.
|
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
|
||||||
if r.cr3().read().hdsel() {
|
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
|
// 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
|
// Start USART DMA
|
||||||
// will not do anything yet because DMAR is not yet set
|
// will not do anything yet because DMAR is not yet set
|
||||||
// future which will complete when DMA Read request completes
|
// 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
|
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
|
||||||
if !self.detect_previous_overrun {
|
if !self.detect_previous_overrun {
|
||||||
@ -640,9 +651,8 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
// future which completes when idle line or error is detected
|
// future which completes when idle line or error is detected
|
||||||
|
let s = self.state;
|
||||||
let abort = poll_fn(move |cx| {
|
let abort = poll_fn(move |cx| {
|
||||||
let s = T::state();
|
|
||||||
|
|
||||||
s.rx_waker.register(cx.waker());
|
s.rx_waker.register(cx.waker());
|
||||||
|
|
||||||
let sr = sr(r).read();
|
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.
|
/// 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.
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
config: Config,
|
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
|
/// 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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
rts: impl Peripheral<P = impl RtsPin<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> {
|
impl<'d, M: Mode> UartRx<'d, M> {
|
||||||
fn new_inner(
|
fn new_inner<T: Instance>(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
rts: 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> {
|
) -> Result<Self, ConfigError> {
|
||||||
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| {
|
r.cr3().write(|w| {
|
||||||
w.set_rtse(rts.is_some());
|
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();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
// create state once!
|
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||||
let _s = T::state();
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
|
info,
|
||||||
|
state,
|
||||||
|
kernel_clock,
|
||||||
rx,
|
rx,
|
||||||
rts,
|
rts,
|
||||||
rx_dma,
|
rx_dma,
|
||||||
@ -792,12 +807,12 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
|
|||||||
|
|
||||||
/// Reconfigure the driver
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
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))]
|
#[cfg(any(usart_v1, usart_v2))]
|
||||||
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
loop {
|
loop {
|
||||||
// Handle all buffered error flags.
|
// Handle all buffered error flags.
|
||||||
if self.buffered_sr.pe() {
|
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))]
|
#[cfg(any(usart_v3, usart_v4))]
|
||||||
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
fn check_rx_flags(&mut self) -> Result<bool, Error> {
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
let sr = r.isr().read();
|
let sr = r.isr().read();
|
||||||
if sr.pe() {
|
if sr.pe() {
|
||||||
r.icr().write(|w| w.set_pe(true));
|
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
|
/// Read a single u8 if there is one available, otherwise return WouldBlock
|
||||||
pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
|
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()? {
|
if self.check_rx_flags()? {
|
||||||
Ok(unsafe { rdr(r).read_volatile() })
|
Ok(unsafe { rdr(r).read_volatile() })
|
||||||
} else {
|
} else {
|
||||||
@ -860,11 +875,11 @@ impl<'d, T: BasicInstance, M: Mode> UartRx<'d, T, M> {
|
|||||||
|
|
||||||
/// Perform a blocking read into `buffer`
|
/// Perform a blocking read into `buffer`
|
||||||
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
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.
|
// Call flush for Half-Duplex mode. It prevents reading of bytes which have just been written.
|
||||||
if r.cr3().read().hdsel() {
|
if r.cr3().read().hdsel() {
|
||||||
UartTx::<'d, T, M>::blocking_flush_inner()?;
|
blocking_flush(self.info)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
for b in buffer {
|
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) {
|
fn drop(&mut self) {
|
||||||
self.tx.as_ref().map(|x| x.set_as_disconnected());
|
self.tx.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.cts.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());
|
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) {
|
fn drop(&mut self) {
|
||||||
self.rx.as_ref().map(|x| x.set_as_disconnected());
|
self.rx.as_ref().map(|x| x.set_as_disconnected());
|
||||||
self.rts.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
|
/// Create a new bidirectional UART
|
||||||
pub fn new(
|
pub fn new<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -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
|
/// 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,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -943,7 +971,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Async> {
|
|||||||
|
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
/// Create a new bidirectional UART with a driver-enable pin
|
/// 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,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -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
|
/// 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).
|
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||||
#[doc(alias("HDSEL"))]
|
#[doc(alias("HDSEL"))]
|
||||||
pub fn new_half_duplex(
|
pub fn new_half_duplex<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<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).
|
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
#[doc(alias("HDSEL"))]
|
#[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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<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.
|
/// Create a new blocking bidirectional UART.
|
||||||
pub fn new_blocking(
|
pub fn new_blocking<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -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
|
/// 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,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -1100,7 +1128,7 @@ impl<'d, T: BasicInstance> Uart<'d, T, Blocking> {
|
|||||||
|
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
/// Create a new bidirectional UART with a driver-enable pin
|
/// 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,
|
peri: impl Peripheral<P = T> + '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,
|
||||||
@ -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
|
/// 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).
|
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||||
#[doc(alias("HDSEL"))]
|
#[doc(alias("HDSEL"))]
|
||||||
pub fn new_blocking_half_duplex(
|
pub fn new_blocking_half_duplex<T: Instance>(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||||
mut config: Config,
|
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).
|
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
#[doc(alias("HDSEL"))]
|
#[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,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||||
mut config: Config,
|
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> {
|
impl<'d, M: Mode> Uart<'d, M> {
|
||||||
fn new_inner(
|
fn new_inner<T: Instance>(
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
tx: 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>>,
|
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Result<Self, ConfigError> {
|
) -> Result<Self, ConfigError> {
|
||||||
// UartRx and UartTx have one refcount each.
|
|
||||||
T::enable_and_reset();
|
|
||||||
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| {
|
r.cr3().write(|w| {
|
||||||
w.set_rtse(rts.is_some());
|
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)))]
|
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||||
w.set_dem(de.is_some());
|
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();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
// create state once!
|
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||||
let _s = T::state();
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tx: UartTx {
|
tx: UartTx {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
|
info,
|
||||||
|
state,
|
||||||
|
kernel_clock,
|
||||||
tx,
|
tx,
|
||||||
cts,
|
cts,
|
||||||
de,
|
de,
|
||||||
@ -1230,6 +1261,9 @@ impl<'d, T: BasicInstance, M: Mode> Uart<'d, T, M> {
|
|||||||
},
|
},
|
||||||
rx: UartRx {
|
rx: UartRx {
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
|
info,
|
||||||
|
state,
|
||||||
|
kernel_clock,
|
||||||
rx,
|
rx,
|
||||||
rts,
|
rts,
|
||||||
rx_dma,
|
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
|
/// Split the Uart into a transmitter and receiver, which is
|
||||||
/// particularly useful when having two tasks correlating to
|
/// particularly useful when having two tasks correlating to
|
||||||
/// transmitting and receiving.
|
/// 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)
|
(self.tx, self.rx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> {
|
fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
|
||||||
T::Interrupt::disable();
|
info.interrupt.disable();
|
||||||
let r = T::regs();
|
let r = info.regs;
|
||||||
|
|
||||||
let cr = r.cr1().read();
|
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();
|
info.interrupt.unpend();
|
||||||
unsafe { T::Interrupt::enable() };
|
unsafe { info.interrupt.enable() };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure(
|
fn configure(
|
||||||
r: Regs,
|
info: &Info,
|
||||||
|
kernel_clock: Hertz,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
pclk_freq: Hertz,
|
|
||||||
kind: Kind,
|
|
||||||
enable_rx: bool,
|
enable_rx: bool,
|
||||||
enable_tx: bool,
|
enable_tx: bool,
|
||||||
) -> Result<(), ConfigError> {
|
) -> Result<(), ConfigError> {
|
||||||
|
let r = info.regs;
|
||||||
|
let kind = info.kind;
|
||||||
|
|
||||||
if !enable_rx && !enable_tx {
|
if !enable_rx && !enable_tx {
|
||||||
return Err(ConfigError::RxOrTxNotEnabled);
|
return Err(ConfigError::RxOrTxNotEnabled);
|
||||||
}
|
}
|
||||||
@ -1348,7 +1384,7 @@ fn configure(
|
|||||||
let mut over8 = false;
|
let mut over8 = false;
|
||||||
let mut found_brr = None;
|
let mut found_brr = None;
|
||||||
for &(presc, _presc_val) in &DIVS {
|
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!(
|
trace!(
|
||||||
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
|
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
|
||||||
presc,
|
presc,
|
||||||
@ -1389,7 +1425,7 @@ fn configure(
|
|||||||
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
|
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
|
||||||
oversampling,
|
oversampling,
|
||||||
config.baudrate,
|
config.baudrate,
|
||||||
pclk_freq.0 / brr * mul
|
kernel_clock.0 / brr * mul
|
||||||
);
|
);
|
||||||
|
|
||||||
r.cr2().write(|w| {
|
r.cr2().write(|w| {
|
||||||
@ -1458,14 +1494,14 @@ fn configure(
|
|||||||
Ok(())
|
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;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
self.nb_read()
|
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;
|
type Error = Error;
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_write(buffer)
|
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;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
self.nb_read()
|
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;
|
type Error = Error;
|
||||||
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.blocking_write(buffer)
|
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;
|
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;
|
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;
|
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> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
self.nb_read()
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
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>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
self.nb_read()
|
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> {
|
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
|
||||||
self.blocking_write(&[char]).map_err(nb::Error::Other)
|
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>
|
impl<M: Mode> embedded_io::ErrorType for Uart<'_, M> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M>
|
impl<M: Mode> embedded_io::ErrorType for UartTx<'_, M> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, M: Mode> embedded_io::Write for Uart<'_, T, M>
|
impl<M: Mode> embedded_io::Write for Uart<'_, M> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_write(buf)?;
|
self.blocking_write(buf)?;
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
@ -1582,10 +1609,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, M: Mode> embedded_io::Write for UartTx<'_, T, M>
|
impl<M: Mode> embedded_io::Write for UartTx<'_, M> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.blocking_write(buf)?;
|
self.blocking_write(buf)?;
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
@ -1596,10 +1620,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_io_async::Write for Uart<'_, T, Async>
|
impl embedded_io_async::Write for Uart<'_, Async> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.write(buf).await?;
|
self.write(buf).await?;
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
@ -1610,10 +1631,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_io_async::Write for UartTx<'_, T, Async>
|
impl embedded_io_async::Write for UartTx<'_, Async> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
self.write(buf).await?;
|
self.write(buf).await?;
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
@ -1686,72 +1704,75 @@ enum Kind {
|
|||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
rx_waker: AtomicWaker,
|
rx_waker: AtomicWaker,
|
||||||
|
tx_rx_refcount: AtomicU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
const fn new() -> Self {
|
const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
rx_waker: AtomicWaker::new(),
|
rx_waker: AtomicWaker::new(),
|
||||||
|
tx_rx_refcount: AtomicU8::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SealedBasicInstance: crate::rcc::RccPeripheral {
|
struct Info {
|
||||||
const KIND: Kind;
|
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 state() -> &'static State;
|
||||||
|
|
||||||
fn buffered_state() -> &'static buffered::State;
|
fn buffered_state() -> &'static buffered::State;
|
||||||
}
|
}
|
||||||
|
|
||||||
trait SealedFullInstance: SealedBasicInstance {
|
/// USART peripheral instance trait.
|
||||||
#[allow(unused)]
|
|
||||||
fn regs_uart() -> crate::pac::usart::Usart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Basic UART driver instance
|
|
||||||
#[allow(private_bounds)]
|
#[allow(private_bounds)]
|
||||||
pub trait BasicInstance: Peripheral<P = Self> + SealedBasicInstance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
|
||||||
/// Interrupt for this instance.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: interrupt::typelevel::Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Full UART driver instance
|
pin_trait!(RxPin, Instance);
|
||||||
#[allow(private_bounds)]
|
pin_trait!(TxPin, Instance);
|
||||||
pub trait FullInstance: SealedFullInstance {}
|
pin_trait!(CtsPin, Instance);
|
||||||
|
pin_trait!(RtsPin, Instance);
|
||||||
|
pin_trait!(CkPin, Instance);
|
||||||
|
pin_trait!(DePin, Instance);
|
||||||
|
|
||||||
pin_trait!(RxPin, BasicInstance);
|
dma_trait!(TxDma, Instance);
|
||||||
pin_trait!(TxPin, BasicInstance);
|
dma_trait!(RxDma, Instance);
|
||||||
pin_trait!(CtsPin, BasicInstance);
|
|
||||||
pin_trait!(RtsPin, BasicInstance);
|
|
||||||
pin_trait!(CkPin, BasicInstance);
|
|
||||||
pin_trait!(DePin, BasicInstance);
|
|
||||||
|
|
||||||
dma_trait!(TxDma, BasicInstance);
|
|
||||||
dma_trait!(RxDma, BasicInstance);
|
|
||||||
|
|
||||||
macro_rules! impl_usart {
|
macro_rules! impl_usart {
|
||||||
($inst:ident, $irq:ident, $kind:expr) => {
|
($inst:ident, $irq:ident, $kind:expr) => {
|
||||||
impl SealedBasicInstance for crate::peripherals::$inst {
|
#[allow(private_interfaces)]
|
||||||
const KIND: Kind = $kind;
|
impl SealedInstance for crate::peripherals::$inst {
|
||||||
|
fn info() -> &'static Info {
|
||||||
fn regs() -> Regs {
|
static INFO: Info = Info {
|
||||||
unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
|
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 {
|
fn state() -> &'static State {
|
||||||
static STATE: crate::usart::State = crate::usart::State::new();
|
static STATE: State = State::new();
|
||||||
&STATE
|
&STATE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffered_state() -> &'static buffered::State {
|
fn buffered_state() -> &'static buffered::State {
|
||||||
static STATE: buffered::State = buffered::State::new();
|
static BUFFERED_STATE: buffered::State = buffered::State::new();
|
||||||
&STATE
|
&BUFFERED_STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicInstance for peripherals::$inst {
|
impl Instance for crate::peripherals::$inst {
|
||||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1761,16 +1782,7 @@ foreach_interrupt!(
|
|||||||
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
|
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
|
||||||
impl_usart!($inst, $irq, Kind::Lpuart);
|
impl_usart!($inst, $irq, Kind::Lpuart);
|
||||||
};
|
};
|
||||||
|
|
||||||
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
|
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||||
impl_usart!($inst, $irq, Kind::Uart);
|
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 {}
|
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
@ -7,20 +6,23 @@ use core::task::Poll;
|
|||||||
use embassy_embedded_hal::SetConfig;
|
use embassy_embedded_hal::SetConfig;
|
||||||
use futures_util::future::{select, Either};
|
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::dma::ReadableRingBuffer;
|
||||||
use crate::mode::Async;
|
use crate::mode::Async;
|
||||||
|
use crate::time::Hertz;
|
||||||
use crate::usart::{Regs, Sr};
|
use crate::usart::{Regs, Sr};
|
||||||
|
|
||||||
/// Rx-only Ring-buffered UART Driver
|
/// Rx-only Ring-buffered UART Driver
|
||||||
///
|
///
|
||||||
/// Created with [UartRx::into_ring_buffered]
|
/// Created with [UartRx::into_ring_buffered]
|
||||||
pub struct RingBufferedUartRx<'d, T: BasicInstance> {
|
pub struct RingBufferedUartRx<'d> {
|
||||||
_phantom: PhantomData<T>,
|
info: &'static Info,
|
||||||
|
state: &'static State,
|
||||||
|
kernel_clock: Hertz,
|
||||||
ring_buf: ReadableRingBuffer<'d, u8>,
|
ring_buf: ReadableRingBuffer<'d, u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: BasicInstance> SetConfig for RingBufferedUartRx<'d, T> {
|
impl<'d> SetConfig for RingBufferedUartRx<'d> {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
type ConfigError = ConfigError;
|
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
|
/// 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
|
/// 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.
|
/// 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);
|
assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
|
||||||
|
|
||||||
let opts = Default::default();
|
let opts = Default::default();
|
||||||
@ -43,19 +45,24 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
|
|||||||
let request = rx_dma.request;
|
let request = rx_dma.request;
|
||||||
let rx_dma = unsafe { rx_dma.channel.clone_unchecked() };
|
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
|
// Don't disable the clock
|
||||||
mem::forget(self);
|
mem::forget(self);
|
||||||
|
|
||||||
RingBufferedUartRx {
|
RingBufferedUartRx {
|
||||||
_phantom: PhantomData,
|
info,
|
||||||
|
state,
|
||||||
|
kernel_clock,
|
||||||
ring_buf,
|
ring_buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
|
impl<'d> RingBufferedUartRx<'d> {
|
||||||
/// Clear the ring buffer and start receiving in the background
|
/// Clear the ring buffer and start receiving in the background
|
||||||
pub fn start(&mut self) -> Result<(), Error> {
|
pub fn start(&mut self) -> Result<(), Error> {
|
||||||
// Clear the ring buffer so that it is ready to receive data
|
// 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
|
/// Reconfigure the driver
|
||||||
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||||
reconfigure::<T>(config)
|
reconfigure(self.info, self.kernel_clock, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start uart background receive
|
/// Start uart background receive
|
||||||
@ -85,7 +92,7 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
|
|||||||
// start the dma controller
|
// start the dma controller
|
||||||
self.ring_buf.start();
|
self.ring_buf.start();
|
||||||
|
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// disable RXNE interrupt
|
||||||
@ -107,7 +114,7 @@ impl<'d, T: BasicInstance> RingBufferedUartRx<'d, T> {
|
|||||||
fn teardown_uart(&mut self) {
|
fn teardown_uart(&mut self) {
|
||||||
self.ring_buf.request_stop();
|
self.ring_buf.request_stop();
|
||||||
|
|
||||||
let r = T::regs();
|
let r = self.info.regs;
|
||||||
// clear all interrupts and DMA Rx Request
|
// clear all interrupts and DMA Rx Request
|
||||||
r.cr1().modify(|w| {
|
r.cr1().modify(|w| {
|
||||||
// disable RXNE interrupt
|
// 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.
|
/// 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()`.
|
/// 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> {
|
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
|
// Start background receive if it was not already started
|
||||||
if !r.cr3().read().dmar() {
|
if !r.cr3().read().dmar() {
|
||||||
self.start()?;
|
self.start()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_for_errors(clear_idle_flag(T::regs()))?;
|
check_for_errors(clear_idle_flag(r))?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.ring_buf.read(buf) {
|
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
|
// Future which completes when idle line is detected
|
||||||
|
let s = self.state;
|
||||||
let uart = poll_fn(|cx| {
|
let uart = poll_fn(|cx| {
|
||||||
let s = T::state();
|
|
||||||
s.rx_waker.register(cx.waker());
|
s.rx_waker.register(cx.waker());
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
// Critical section is needed so that IDLE isn't set after
|
// Critical section is needed so that IDLE isn't set after
|
||||||
// our read but before we clear it.
|
// 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)?;
|
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) {
|
fn drop(&mut self) {
|
||||||
self.teardown_uart();
|
self.teardown_uart();
|
||||||
|
super::drop_tx_rx(self.info, self.state);
|
||||||
T::disable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an error result if the Sr register has errors
|
/// Return an error result if the Sr register has errors
|
||||||
fn check_for_errors(s: Sr) -> Result<(), Error> {
|
fn check_for_errors(s: Sr) -> Result<(), Error> {
|
||||||
if s.pe() {
|
if s.pe() {
|
||||||
@ -248,17 +255,11 @@ fn clear_idle_flag(r: Regs) -> Sr {
|
|||||||
sr
|
sr
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_io_async::ErrorType for RingBufferedUartRx<'_, T>
|
impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_io_async::Read for RingBufferedUartRx<'_, T>
|
impl embedded_io_async::Read for RingBufferedUartRx<'_> {
|
||||||
where
|
|
||||||
T: BasicInstance,
|
|
||||||
{
|
|
||||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
self.read(buf).await
|
self.read(buf).await
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::mode::Async;
|
use embassy_stm32::mode::Async;
|
||||||
use embassy_stm32::peripherals::UART7;
|
|
||||||
use embassy_stm32::usart::{Config, Uart, UartRx};
|
use embassy_stm32::usart::{Config, Uart, UartRx};
|
||||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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];
|
let mut buf = [0; 8];
|
||||||
loop {
|
loop {
|
||||||
info!("reading...");
|
info!("reading...");
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::mode::Async;
|
use embassy_stm32::mode::Async;
|
||||||
use embassy_stm32::peripherals::UART7;
|
|
||||||
use embassy_stm32::usart::{Config, Uart, UartRx};
|
use embassy_stm32::usart::{Config, Uart, UartRx};
|
||||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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];
|
let mut buf = [0; 8];
|
||||||
loop {
|
loop {
|
||||||
info!("reading...");
|
info!("reading...");
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::mode::Async;
|
use embassy_stm32::mode::Async;
|
||||||
use embassy_stm32::peripherals::UART7;
|
|
||||||
use embassy_stm32::usart::{Config, Uart, UartRx};
|
use embassy_stm32::usart::{Config, Uart, UartRx};
|
||||||
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
use embassy_stm32::{bind_interrupts, peripherals, usart};
|
||||||
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
|
||||||
@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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];
|
let mut buf = [0; 8];
|
||||||
loop {
|
loop {
|
||||||
info!("reading...");
|
info!("reading...");
|
||||||
|
@ -52,7 +52,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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
|
// workaround https://github.com/embassy-rs/embassy/issues/1426
|
||||||
Timer::after_millis(100).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ async fn transmit_task(mut tx: UartTx<'static, peris::UART, Async>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[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...");
|
info!("Ready to receive...");
|
||||||
|
|
||||||
let mut rng = ChaCha8Rng::seed_from_u64(1337);
|
let mut rng = ChaCha8Rng::seed_from_u64(1337);
|
||||||
|
Loading…
Reference in New Issue
Block a user