#![macro_use]
#![warn(missing_docs)]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, AtomicU8, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::PeripheralRef;
use embassy_sync::waitqueue::AtomicWaker;
use futures_util::future::{select, Either};
use crate::dma::ChannelAndRequest;
use crate::gpio::{AfType, AnyPin, Pull, SealedPin};
use crate::interrupt::{self, Interrupt, typelevel::Interrupt as _};
use crate::mode::{Async, Blocking, Mode};
use crate::time::Hertz;
use crate::{rcc, Peripheral};
use crate::pac::usart::Usart as Regs;
use crate::pac::usart::{regs, vals};
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
on_interrupt(T::regs(), T::state())
}
}
unsafe fn on_interrupt(r: Regs, s: &'static State) {
let (sr, cr1, cr3) = (r.isr().read(), r.cr1().read(), r.cr3().read());
let has_errors = (sr.pe() && cr1.peie()) || ((sr.fe() || sr.ore()) && cr3.eie());
if has_errors {
r.cr1().modify(|w| {
w.set_rxneie(false);
w.set_peie(false);
w.set_idleie(false);
});
r.cr3().modify(|w| {
w.set_eie(false);
w.set_dmar(false);
});
} else if cr1.idleie() && sr.idle() {
r.cr1().modify(|w| {
w.set_idleie(false);
});
} else if cr1.tcie() && sr.tc() {
r.cr1().modify(|w| {
w.set_tcie(false);
});
} else if cr1.rxneie() {
} else {
return;
}
compiler_fence(Ordering::SeqCst);
s.rx_waker.wake();
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DataBits {
DataBits6,
DataBits7,
DataBits8,
DataBits9,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
#[doc = "2 stop bits"]
STOP2,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum HalfDuplexReadback {
NoReadback,
Readback,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Duplex {
Full,
Half(HalfDuplexReadback),
}
impl Duplex {
fn is_half(&self) -> bool {
matches!(self, Duplex::Half(_))
}
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ConfigError {
BaudrateTooLow,
BaudrateTooHigh,
RxOrTxNotEnabled,
DataParityNotSupported,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
pub baudrate: u32,
pub data_bits: DataBits,
pub stop_bits: StopBits,
pub parity: Parity,
pub _detect_previous_overrun: bool,
pub assume_noise_free: bool,
pub rx_pull: Pull,
duplex: Duplex,
}
impl Config {
fn tx_af(&self) -> AfType {
AfType::new(Pull::Up)
}
fn rx_af(&self) -> AfType {
AfType::new(self.rx_pull)
}
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 115200,
data_bits: DataBits::DataBits8,
stop_bits: StopBits::STOP1,
parity: Parity::ParityNone,
_detect_previous_overrun: false,
assume_noise_free: false,
rx_pull: Pull::None,
duplex: Duplex::Full,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct HalfDuplexConfig {
pull: Pull,
}
impl HalfDuplexConfig {
fn af_type(self) -> AfType {
AfType::new(self.pull)
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
BufferTooLong,
}
enum ReadCompletionEvent {
DmaCompleted,
Idle(usize),
}
pub struct Uart<'d, T: Instance, M: Mode> {
tx: UartTx<'d, T, M>,
rx: UartRx<'d, T, M>,
}
impl<'d, T: Instance, M: Mode> SetConfig for Uart<'d, T, M> {
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.tx.set_config(config)?;
self.rx.set_config(config)
}
}
pub struct UartTx<'d, T: Instance, M: Mode> {
state: &'static State,
kernel_clock: Hertz,
tx: Option<PeripheralRef<'d, AnyPin>>,
cts: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>,
duplex: Duplex,
_phantom: PhantomData<(T, M)>,
}
impl<'d, T: Instance, M: Mode> SetConfig for UartTx<'d, T, M> {
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.set_config(config)
}
}
pub struct UartRx<'d, T: Instance, M: Mode> {
state: &'static State,
kernel_clock: Hertz,
rx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
rx_dma: Option<ChannelAndRequest<'d>>,
_detect_previous_overrun: bool,
_phantom: PhantomData<(T, M)>,
}
impl<'d, T: Instance, M: Mode> SetConfig for UartRx<'d, T, M> {
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.set_config(config)
}
}
impl<'d, T: Instance> UartTx<'d, T, Async> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(tx, AfType::new(Pull::Up)),
None,
new_dma!(tx_dma),
config,
)
}
pub fn new_with_cts(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(tx, AfType::new(Pull::Up)),
new_pin!(cts, AfType::new(Pull::None)),
new_dma!(tx_dma),
config,
)
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback));
let ch = self.tx_dma.as_mut().unwrap();
r.cr3().modify(|reg| {
reg.set_dmat(true);
});
let transfer = unsafe { ch.write(buffer, r.tdr().as_ptr() as _, Default::default()) };
transfer.await;
Ok(())
}
pub async fn flush(&mut self) -> Result<(), Error> {
flush::<T>(&self.state).await
}
}
impl<'d, T: Instance> UartTx<'d, T, Blocking> {
pub fn new_blocking(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(tx, AfType::new(Pull::Up)),
None,
None,
config,
)
}
pub fn new_blocking_with_cts(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(tx, AfType::new(Pull::Up)),
new_pin!(cts, AfType::new(config.rx_pull)),
None,
config,
)
}
}
impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,
tx: Option<PeripheralRef<'d, AnyPin>>,
cts: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>,
config: Config,
) -> Result<Self, ConfigError> {
let mut this = Self {
state: T::state(),
kernel_clock: T::frequency().unwrap(),
tx,
cts,
tx_dma,
duplex: config.duplex,
_phantom: PhantomData,
};
this.enable_and_configure(&config)?;
Ok(this)
}
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
let state = self.state;
state.tx_rx_refcount.store(1, Ordering::Relaxed);
rcc::enable_and_reset::<T>();
T::regs().cr3().modify(|w| {
w.set_ctse(self.cts.is_some());
});
configure::<T>(self.kernel_clock, config, false, true)?;
Ok(())
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(self.kernel_clock, config)
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback));
for &b in buffer {
while !r.isr().read().txe() {}
r.tdr().write_value(regs::Tdr(b as _));
}
Ok(())
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
blocking_flush::<T>()
}
pub fn send_break(&self) {
send_break(&T::regs());
}
pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
set_baudrate::<T>(self.kernel_clock, baudrate)
}
}
async fn flush<T: Instance>(state: &State) -> Result<(), Error> {
let r = T::regs();
if r.cr1().read().te() && !r.isr().read().tc() {
r.cr1().modify(|w| {
w.set_tcie(true);
});
compiler_fence(Ordering::SeqCst);
let abort = poll_fn(move |cx| {
state.rx_waker.register(cx.waker());
let sr = r.isr().read();
if sr.tc() {
return Poll::Ready(());
}
Poll::Pending
});
abort.await;
}
Ok(())
}
fn blocking_flush<T: Instance>() -> Result<(), Error> {
let r = T::regs();
if r.cr1().read().te() {
while !r.isr().read().tc() {}
}
Ok(())
}
pub fn send_break(regs: &Regs) {
while regs.isr().read().sbkf() {}
regs.rqr().write(|w| w.set_sbkrq(true));
}
fn half_duplex_set_rx_tx_before_write(r: &Regs, enable_readback: bool) {
let mut cr1 = r.cr1().read();
if r.cr3().read().hdsel() && !cr1.te() {
cr1.set_te(true);
cr1.set_re(enable_readback);
r.cr1().write_value(cr1);
}
}
impl<'d, T: Instance> UartRx<'d, T, Async> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, AfType::new(config.rx_pull)),
None,
new_dma!(rx_dma),
config,
)
}
pub fn new_with_rts(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, AfType::new(config.rx_pull)),
new_pin!(rts, AfType::new(Pull::Up)),
new_dma!(rx_dma),
config,
)
}
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.inner_read(buffer, false).await?;
Ok(())
}
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
self.inner_read(buffer, true).await
}
async fn inner_read_run(
&mut self,
buffer: &mut [u8],
enable_idle_line_detection: bool,
) -> Result<ReadCompletionEvent, Error> {
let r = T::regs();
if r.cr3().read().hdsel() && r.cr1().read().te() {
flush::<T>(&self.state).await?;
r.cr1().modify(|reg| {
reg.set_re(true);
reg.set_te(false);
});
}
let on_drop = OnDrop::new(move || {
r.cr1().modify(|w| {
w.set_rxneie(false);
w.set_peie(false);
w.set_idleie(false);
});
r.cr3().modify(|w| {
w.set_eie(false);
w.set_dmar(false);
});
});
let ch = self.rx_dma.as_mut().unwrap();
let buffer_len = buffer.len();
let transfer = unsafe { ch.read(r.rdr().as_ptr() as _, buffer, Default::default()) };
if !self._detect_previous_overrun {
let sr = r.isr().read();
unsafe { r.rdr().as_ptr().read_volatile() };
clear_interrupt_flags(r, sr);
}
r.cr1().modify(|w| {
w.set_rxneie(false);
w.set_peie(w.pce());
});
r.cr3().modify(|w| {
w.set_eie(true);
w.set_dmar(true);
});
compiler_fence(Ordering::SeqCst);
let cr3 = r.cr3().read();
if !cr3.dmar() {
let sr = r.isr().read();
unsafe { r.rdr().as_ptr().read_volatile() };
clear_interrupt_flags(r, sr);
if sr.pe() {
return Err(Error::Parity);
}
if sr.fe() {
return Err(Error::Framing);
}
if sr.nf() {
return Err(Error::Noise);
}
if sr.ore() {
return Err(Error::Overrun);
}
unreachable!();
}
if enable_idle_line_detection {
let sr = r.isr().read();
unsafe { r.rdr().as_ptr().read_volatile() };
clear_interrupt_flags(r, sr);
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
let s = self.state;
let abort = poll_fn(move |cx| {
s.rx_waker.register(cx.waker());
let sr = r.isr().read();
unsafe { r.rdr().as_ptr().read_volatile() };
clear_interrupt_flags(r, sr);
if enable_idle_line_detection {
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
let has_errors = sr.pe() || sr.fe() || sr.nf() || sr.ore();
if has_errors {
if sr.pe() {
return Poll::Ready(Err(Error::Parity));
}
if sr.fe() {
return Poll::Ready(Err(Error::Framing));
}
if sr.nf() {
return Poll::Ready(Err(Error::Noise));
}
if sr.ore() {
return Poll::Ready(Err(Error::Overrun));
}
}
if enable_idle_line_detection && sr.idle() {
return Poll::Ready(Ok(()));
}
Poll::Pending
});
let r = match select(transfer, abort).await {
Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted),
Either::Right((Ok(()), transfer)) => Ok(ReadCompletionEvent::Idle(
buffer_len - transfer.get_remaining_transfers() as usize,
)),
Either::Right((Err(e), _)) => Err(e),
};
drop(on_drop);
r
}
async fn inner_read(&mut self, buffer: &mut [u8], enable_idle_line_detection: bool) -> Result<usize, Error> {
if buffer.is_empty() {
return Ok(0);
} else if buffer.len() > 0xFFFF {
return Err(Error::BufferTooLong);
}
let buffer_len = buffer.len();
let res = self.inner_read_run(buffer, enable_idle_line_detection).await;
match res {
Ok(ReadCompletionEvent::DmaCompleted) => Ok(buffer_len),
Ok(ReadCompletionEvent::Idle(n)) => Ok(n),
Err(e) => Err(e),
}
}
}
impl<'d, T: Instance> UartRx<'d, T, Blocking> {
pub fn new_blocking(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(peri,
new_pin!(rx, AfType::new(config.rx_pull)),
None,
None,
config
)
}
pub fn new_blocking_with_rts(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, AfType::new(config.rx_pull)),
new_pin!(rts, AfType::new(Pull::Up)),
None,
config,
)
}
}
impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,
rx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
rx_dma: Option<ChannelAndRequest<'d>>,
config: Config,
) -> Result<Self, ConfigError> {
let mut this = Self {
_phantom: PhantomData,
state: T::state(),
kernel_clock: T::frequency().unwrap(),
rx,
rts,
rx_dma,
_detect_previous_overrun: config._detect_previous_overrun,
};
this.enable_and_configure(&config)?;
Ok(this)
}
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
let state = self.state;
state.tx_rx_refcount.store(1, Ordering::Relaxed);
rcc::enable_and_reset::<T>();
T::regs().cr3().write(|w| {
w.set_rtse(self.rts.is_some());
});
configure::<T>(self.kernel_clock, &config, true, false)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(self.kernel_clock, config)
}
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
let sr = r.isr().read();
if sr.pe() {
r.icr().write(|w| w.set_pecf(true));
return Err(Error::Parity);
} else if sr.fe() {
r.icr().write(|w| w.set_fecf(true));
return Err(Error::Framing);
} else if sr.ore() {
r.icr().write(|w| w.set_orecf(true));
return Err(Error::Overrun);
}
Ok(sr.rxne())
}
pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs();
if self.check_rx_flags()? {
Ok(unsafe { r.rdr().as_ptr().read_volatile().0 as u8 })
} else {
Err(nb::Error::WouldBlock)
}
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs();
if r.cr3().read().hdsel() && r.cr1().read().te() {
blocking_flush::<T>()?;
r.cr1().modify(|reg| {
reg.set_re(true);
reg.set_te(false);
});
}
for b in buffer {
while !self.check_rx_flags()? {}
unsafe { *b = r.rdr().as_ptr().read_volatile().0 as u8 }
}
Ok(())
}
pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
set_baudrate::<T>(self.kernel_clock, baudrate)
}
}
impl<'d, T: Instance, M: Mode> Drop for UartTx<'d, T, M> {
fn drop(&mut self) {
self.tx.as_ref().map(|x| x.set_as_disconnected());
self.cts.as_ref().map(|x| x.set_as_disconnected());
drop_tx_rx::<T>(self.state);
}
}
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
fn drop(&mut self) {
self.rx.as_ref().map(|x| x.set_as_disconnected());
self.rts.as_ref().map(|x| x.set_as_disconnected());
drop_tx_rx::<T>(self.state);
}
}
fn drop_tx_rx<T: Instance>(state: &State) {
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 {
rcc::disable::<T>();
}
}
impl<'d, T: Instance> Uart<'d, T, Async> {
pub fn new(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, config.rx_af()),
new_pin!(tx, config.tx_af()),
None,
None,
new_dma!(tx_dma),
new_dma!(rx_dma),
config,
)
}
pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, config.rx_af()),
new_pin!(tx, config.tx_af()),
new_pin!(rts, AfType::new(Pull::Up)),
new_pin!(cts, AfType::new(Pull::None)),
new_dma!(tx_dma),
new_dma!(rx_dma),
config,
)
}
#[doc(alias("HDSEL"))]
pub fn new_half_duplex(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
mut config: Config,
readback: HalfDuplexReadback,
half_duplex: HalfDuplexConfig,
) -> Result<Self, ConfigError> {
config.duplex = Duplex::Half(readback);
Self::new_inner(
peri,
None,
new_pin!(tx, half_duplex.af_type()),
None,
None,
new_dma!(tx_dma),
new_dma!(rx_dma),
config,
)
}
#[doc(alias("HDSEL"))]
pub fn new_half_duplex_on_rx(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
mut config: Config,
readback: HalfDuplexReadback,
half_duplex: HalfDuplexConfig,
) -> Result<Self, ConfigError> {
config.duplex = Duplex::Half(readback);
Self::new_inner(
peri,
None,
None,
new_pin!(rx, half_duplex.af_type()),
None,
new_dma!(tx_dma),
new_dma!(rx_dma),
config,
)
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.write(buffer).await
}
pub async fn flush(&mut self) -> Result<(), Error> {
self.tx.flush().await
}
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.read(buffer).await
}
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
self.rx.read_until_idle(buffer).await
}
}
impl<'d, T: Instance> Uart<'d, T, Blocking> {
pub fn new_blocking(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, config.rx_af()),
new_pin!(tx, config.tx_af()),
None,
None,
None,
None,
config,
)
}
pub fn new_blocking_with_rtscts(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
Self::new_inner(
peri,
new_pin!(rx, config.rx_af()),
new_pin!(tx, config.tx_af()),
new_pin!(rts, AfType::new(Pull::Up)),
new_pin!(cts, AfType::new(Pull::None)),
None,
None,
config,
)
}
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxdPin<T>> + 'd,
mut config: Config,
readback: HalfDuplexReadback,
half_duplex: HalfDuplexConfig,
) -> Result<Self, ConfigError> {
config.duplex = Duplex::Half(readback);
Self::new_inner(
peri,
None,
new_pin!(tx, half_duplex.af_type()),
None,
None,
None,
None,
config,
)
}
#[doc(alias("HDSEL"))]
pub fn new_blocking_half_duplex_on_rx(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxdPin<T>> + 'd,
mut config: Config,
readback: HalfDuplexReadback,
half_duplex: HalfDuplexConfig,
) -> Result<Self, ConfigError> {
config.duplex = Duplex::Half(readback);
Self::new_inner(
peri,
None,
None,
new_pin!(rx, half_duplex.af_type()),
None,
None,
None,
config,
)
}
}
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,
rx: Option<PeripheralRef<'d, AnyPin>>,
tx: Option<PeripheralRef<'d, AnyPin>>,
rts: Option<PeripheralRef<'d, AnyPin>>,
cts: Option<PeripheralRef<'d, AnyPin>>,
tx_dma: Option<ChannelAndRequest<'d>>,
rx_dma: Option<ChannelAndRequest<'d>>,
config: Config,
) -> Result<Self, ConfigError> {
let state = T::state();
let kernel_clock = T::frequency().unwrap();
let mut this = Self {
tx: UartTx {
_phantom: PhantomData,
state,
kernel_clock,
tx,
cts,
tx_dma,
duplex: config.duplex,
},
rx: UartRx {
_phantom: PhantomData,
state,
kernel_clock,
rx,
rts,
rx_dma,
_detect_previous_overrun: config._detect_previous_overrun,
},
};
this.enable_and_configure(&config)?;
Ok(this)
}
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
let state = self.rx.state;
state.tx_rx_refcount.store(2, Ordering::Relaxed);
rcc::enable_and_reset::<T>();
T::regs().cr3().write(|w| {
w.set_rtse(self.rx.rts.is_some());
w.set_ctse(self.tx.cts.is_some());
});
configure::<T>(self.rx.kernel_clock, config, true, true)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush()
}
pub(crate) fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
self.rx.nb_read()
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer)
}
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
(self.tx, self.rx)
}
pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
(&mut self.tx, &mut self.rx)
}
pub fn send_break(&self) {
self.tx.send_break();
}
pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> {
self.tx.set_baudrate(baudrate)?;
self.rx.set_baudrate(baudrate)?;
Ok(())
}
}
fn reconfigure<T: Instance>(kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
T::Interrupt::disable();
let r = T::regs();
let cr = r.cr1().read();
configure::<T>(kernel_clock, config, cr.re(), cr.te())?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
let clock = pclk / presc;
let brr = clock / baud * mul;
let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
brr + rounding
}
fn set_baudrate<T: Instance>(kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
T::Interrupt::disable();
set_usart_baudrate::<T>(kernel_clock, baudrate)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
fn find_and_set_brr(r: Regs, kind: Kind, kernel_clock: Hertz, baudrate: u32) -> Result<bool, ConfigError> {
static DIVS: [(u16, ()); 1] = [(1, ())];
let (mul, brr_min, brr_max) = match kind {
Kind::Uart => {
trace!("USART: Kind::Uart");
(1, 0x10, 0x1_0000)
}
};
let mut found_brr = None;
let mut over8 = false;
for &(presc, _presc_val) in &DIVS {
let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul);
trace!(
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
presc,
brr,
brr >> 4,
brr & 0x0F
);
if brr < brr_min {
if brr * 2 >= brr_min && kind == Kind::Uart {
over8 = true;
r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07)));
found_brr = Some(brr);
break;
}
return Err(ConfigError::BaudrateTooHigh);
}
if brr < brr_max {
r.brr().write_value(regs::Brr(brr));
found_brr = Some(brr);
break;
}
}
match found_brr {
Some(brr) => {
let oversampling = if over8 { "8 bit" } else { "16 bit" };
trace!(
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
oversampling,
baudrate,
kernel_clock.0 / brr * mul
);
Ok(over8)
}
None => Err(ConfigError::BaudrateTooLow),
}
}
fn set_usart_baudrate<T: Instance>(kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> {
let r = T::regs();
r.cr1().modify(|w| {
w.set_ue(false);
});
let over8 = find_and_set_brr(r, T::kind(), kernel_clock, baudrate)?;
r.cr1().modify(|w| {
w.set_ue(true);
w.set_over8(vals::OVER8::from_bits(over8 as _));
});
Ok(())
}
fn configure<T: Instance>(
kernel_clock: Hertz,
config: &Config,
enable_rx: bool,
enable_tx: bool,
) -> Result<(), ConfigError> {
let r = T::regs();
let kind = T::kind();
if !enable_rx && !enable_tx {
return Err(ConfigError::RxOrTxNotEnabled);
}
r.cr1().modify(|w| {
w.set_ue(false);
});
let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?;
r.cr2().write(|w| {
w.set_stop(match config.stop_bits {
StopBits::STOP1 => vals::STOP::Stop1,
StopBits::STOP2 => vals::STOP::Stop2,
});
});
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
w.set_hdsel(config.duplex.is_half());
});
r.cr1().write(|w| {
w.set_ue(true);
if config.duplex.is_half() {
w.set_te(false);
w.set_re(true);
} else {
w.set_te(enable_tx);
w.set_re(enable_rx);
}
match (config.parity, config.data_bits) {
(Parity::ParityNone, DataBits::DataBits8) => {
trace!("USART: m: 8 data bits, no parity");
w.set_m(vals::M::Bit8);
w.set_pce(false);
}
(Parity::ParityNone, DataBits::DataBits9) => {
trace!("USART: m: 9 data bits, no parity");
w.set_m(vals::M::Bit9);
w.set_pce(false);
}
(Parity::ParityNone, DataBits::DataBits7) => {
trace!("USART: m: 7 data bits, no parity");
w.set_m(vals::M::Bit8);
w.set_pce(false);
}
(Parity::ParityEven, DataBits::DataBits8) => {
trace!("USART: m: 8 data bits, even parity");
w.set_m(vals::M::Bit9);
w.set_pce(true);
w.set_ps(vals::PS::Even);
}
(Parity::ParityEven, DataBits::DataBits7) => {
trace!("USART: m: 7 data bits, even parity");
w.set_m(vals::M::Bit8);
w.set_pce(true);
w.set_ps(vals::PS::Even);
}
(Parity::ParityOdd, DataBits::DataBits8) => {
trace!("USART: m: 8 data bits, odd parity");
w.set_m(vals::M::Bit9);
w.set_pce(true);
w.set_ps(vals::PS::Odd);
}
(Parity::ParityOdd, DataBits::DataBits7) => {
trace!("USART: m 7 data bits, odd parity");
w.set_m(vals::M::Bit8);
w.set_pce(true);
w.set_ps(vals::PS::Odd);
}
(_, DataBits::DataBits6) => {
todo!()
}
_ => {
return Err(ConfigError::DataParityNotSupported);
}
}
w.set_over8(vals::OVER8::from_bits(over8 as _));
Ok(())
})?;
Ok(())
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl embedded_hal_nb::serial::Error for Error {
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
match *self {
Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise,
Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
Self::BufferTooLong => embedded_hal_nb::serial::ErrorKind::Other,
}
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> {
type Error = Error;
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.nb_read()
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.blocking_flush().map_err(nb::Error::Other)
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> {
fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
self.blocking_write(&[char]).map_err(nb::Error::Other)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.blocking_flush().map_err(nb::Error::Other)
}
}
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}
impl<T:Instance, M: Mode> embedded_io::ErrorType for Uart<'_, T, M> {
type Error = Error;
}
impl<T:Instance, M: Mode> embedded_io::ErrorType for UartTx<'_, T, M> {
type Error = Error;
}
impl<T:Instance, M: Mode> embedded_io::Write for Uart<'_, T, M> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<T:Instance, M: Mode> embedded_io::Write for UartTx<'_, T, M> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.blocking_write(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<T:Instance> embedded_io_async::Write for Uart<'_, T, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush().await
}
}
impl<T:Instance> embedded_io_async::Write for UartTx<'_, T, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush().await
}
}
pub use buffered::*;
pub use crate::usart::buffered::InterruptHandler as BufferedInterruptHandler;
mod buffered;
mod ringbuffered;
pub use ringbuffered::RingBufferedUartRx;
fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
r.icr().write(|w| *w = regs::Icr(sr.0));
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Kind {
Uart,
}
struct State {
rx_waker: AtomicWaker,
tx_rx_refcount: AtomicU8,
}
impl State {
const fn new() -> Self {
Self {
rx_waker: AtomicWaker::new(),
tx_rx_refcount: AtomicU8::new(0),
}
}
}
#[allow(private_interfaces)]
pub(crate) trait SealedInstance: crate::rcc::RccEnableReset + crate::rcc::RccGetFreq {
fn regs() -> Regs;
fn interrupt() -> Interrupt;
fn kind() -> Kind;
fn state() -> &'static State;
fn buffered_state() -> &'static buffered::State;
}
#[allow(private_bounds)]
pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
type Interrupt: interrupt::typelevel::Interrupt;
}
pin_trait!(RxdPin, Instance);
pin_trait!(TxdPin, Instance);
pin_trait!(CtsPin, Instance);
pin_trait!(RtsPin, Instance);
pin_trait!(CkPin, Instance);
dma_trait!(TxDma, Instance);
dma_trait!(RxDma, Instance);
macro_rules! impl_usart {
($inst:ident, $irq:ident, $kind:expr) => {
#[allow(private_interfaces)]
impl SealedInstance for crate::peripherals::$inst {
fn regs() -> Regs {
crate::pac::$inst
}
fn interrupt() -> Interrupt {
crate::interrupt::$irq
}
fn kind() -> Kind {
$kind
}
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
}
fn buffered_state() -> &'static buffered::State {
static BUFFERED_STATE: buffered::State = buffered::State::new();
&BUFFERED_STATE
}
}
impl Instance for crate::peripherals::$inst {
type Interrupt = crate::interrupt::typelevel::$irq;
}
};
}
impl_usart!(USART1, USART1, Kind::Uart);
impl_usart!(USART2, USART2, Kind::Uart);
impl_usart!(USART3, USART3, Kind::Uart);