2023-12-19 16:41:00 +01:00

1397 lines
41 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
#![macro_use]
#![warn(missing_docs)]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll;
use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
use futures::future::{select, Either};
use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType;
use crate::interrupt::typelevel::Interrupt;
#[allow(unused_imports)]
#[cfg(not(any(usart_v1, usart_v2)))]
use crate::pac::usart::regs::Isr as Sr;
#[cfg(any(usart_v1, usart_v2))]
use crate::pac::usart::regs::Sr;
#[cfg(not(any(usart_v1, usart_v2)))]
use crate::pac::usart::Lpuart as Regs;
#[cfg(any(usart_v1, usart_v2))]
use crate::pac::usart::Usart as Regs;
use crate::pac::usart::{regs, vals};
use crate::time::Hertz;
use crate::{interrupt, peripherals, Peripheral};
/// Interrupt handler.
pub struct InterruptHandler<T: BasicInstance> {
_phantom: PhantomData<T>,
}
impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
let r = T::regs();
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();
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of data bits
pub enum DataBits {
/// 8 Data Bits
DataBits8,
/// 9 Data Bits
DataBits9,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Parity
pub enum Parity {
/// No parity
ParityNone,
/// Even Parity
ParityEven,
/// Odd Parity
ParityOdd,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of stop bits
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
#[doc = "0.5 stop bits"]
STOP0P5,
#[doc = "2 stop bits"]
STOP2,
#[doc = "1.5 stop bits"]
STOP1P5,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Config Error
pub enum ConfigError {
/// Baudrate too low
BaudrateTooLow,
/// Baudrate too high
BaudrateTooHigh,
/// Rx or Tx not enabled
RxOrTxNotEnabled,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Config
pub struct Config {
/// Baud rate
pub baudrate: u32,
/// Number of data bits
pub data_bits: DataBits,
/// Number of stop bits
pub stop_bits: StopBits,
/// Parity type
pub parity: Parity,
/// If true: on a read-like method, if there is a latent error pending,
/// the read will abort and the error will be reported and cleared
///
/// If false: the error is ignored and cleared
pub detect_previous_overrun: bool,
/// Set this to true if the line is considered noise free.
/// This will increase the receivers tolerance to clock deviations,
/// but will effectively disable noise detection.
#[cfg(not(usart_v1))]
pub assume_noise_free: bool,
/// Set this to true to swap the RX and TX pins.
#[cfg(any(usart_v3, usart_v4))]
pub swap_rx_tx: bool,
/// Set this to true to invert TX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
#[cfg(any(usart_v3, usart_v4))]
pub invert_tx: bool,
/// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
#[cfg(any(usart_v3, usart_v4))]
pub invert_rx: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 115200,
data_bits: DataBits::DataBits8,
stop_bits: StopBits::STOP1,
parity: Parity::ParityNone,
// historical behavior
detect_previous_overrun: false,
#[cfg(not(usart_v1))]
assume_noise_free: false,
#[cfg(any(usart_v3, usart_v4))]
swap_rx_tx: false,
#[cfg(any(usart_v3, usart_v4))]
invert_tx: false,
#[cfg(any(usart_v3, usart_v4))]
invert_rx: false,
}
}
}
/// Serial error
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
/// Framing error
Framing,
/// Noise error
Noise,
/// RX buffer overrun
Overrun,
/// Parity check error
Parity,
/// Buffer too large for DMA
BufferTooLong,
}
enum ReadCompletionEvent {
// DMA Read transfer completed first
DmaCompleted,
// Idle line detected first
Idle(usize),
}
/// Bidirectional UART Driver
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
tx: UartTx<'d, T, TxDma>,
rx: UartRx<'d, T, RxDma>,
}
impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> {
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)
}
}
/// Tx-only UART Driver
pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
phantom: PhantomData<&'d mut T>,
tx_dma: PeripheralRef<'d, TxDma>,
}
impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.set_config(config)
}
}
/// Rx-only UART Driver
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
_peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>,
detect_previous_overrun: bool,
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr,
}
impl<'d, T: BasicInstance, RxDma> SetConfig for UartRx<'d, T, RxDma> {
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.set_config(config)
}
}
impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
/// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power.
pub fn new(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
T::enable_and_reset();
Self::new_inner(peri, tx, tx_dma, config)
}
/// Create a new tx-only UART with a clear-to-send pin
pub fn new_with_cts(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
cts: impl Peripheral<P = impl CtsPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(cts);
T::enable_and_reset();
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_ctse(true);
});
Self::new_inner(peri, tx, tx_dma, config)
}
fn new_inner(
_peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(_peri, tx, tx_dma);
let r = T::regs();
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
configure(r, &config, T::frequency(), T::KIND, false, true)?;
// create state once!
let _s = T::state();
Ok(Self {
tx_dma,
phantom: PhantomData,
})
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
/// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where
TxDma: crate::usart::TxDma<T>,
{
let ch = &mut self.tx_dma;
let request = ch.request();
T::regs().cr3().modify(|reg| {
reg.set_dmat(true);
});
// If we don't assign future to a variable, the data register pointer
// is held across an await and makes the future non-Send.
let transfer = unsafe { Transfer::new_write(ch, request, buffer, tdr(T::regs()), Default::default()) };
transfer.await;
Ok(())
}
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
for &b in buffer {
while !sr(r).read().txe() {}
unsafe { tdr(r).write_volatile(b) };
}
Ok(())
}
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs();
while !sr(r).read().tc() {}
Ok(())
}
}
impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
/// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power.
pub fn new(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
T::enable_and_reset();
Self::new_inner(peri, rx, rx_dma, config)
}
/// Create a new rx-only UART with a request-to-send pin
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 RxPin<T>> + 'd,
rts: impl Peripheral<P = impl RtsPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(rts);
T::enable_and_reset();
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_rtse(true);
});
Self::new_inner(peri, rx, rx_dma, config)
}
fn new_inner(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(peri, rx, rx_dma);
let r = T::regs();
rx.set_as_af(rx.af_num(), AFType::Input);
configure(r, &config, T::frequency(), T::KIND, true, false)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
Ok(Self {
_peri: peri,
rx_dma,
detect_previous_overrun: config.detect_previous_overrun,
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr(0),
})
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
#[cfg(any(usart_v1, usart_v2))]
fn check_rx_flags(&mut self) -> Result<bool, Error> {
let r = T::regs();
loop {
// Handle all buffered error flags.
if self.buffered_sr.pe() {
self.buffered_sr.set_pe(false);
return Err(Error::Parity);
} else if self.buffered_sr.fe() {
self.buffered_sr.set_fe(false);
return Err(Error::Framing);
} else if self.buffered_sr.ne() {
self.buffered_sr.set_ne(false);
return Err(Error::Noise);
} else if self.buffered_sr.ore() {
self.buffered_sr.set_ore(false);
return Err(Error::Overrun);
} else if self.buffered_sr.rxne() {
self.buffered_sr.set_rxne(false);
return Ok(true);
} else {
// No error flags from previous iterations were set: Check the actual status register
let sr = r.sr().read();
if !sr.rxne() {
return Ok(false);
}
// Buffer the status register and let the loop handle the error flags.
self.buffered_sr = sr;
}
}
}
#[cfg(any(usart_v3, usart_v4))]
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_pe(true));
return Err(Error::Parity);
} else if sr.fe() {
r.icr().write(|w| w.set_fe(true));
return Err(Error::Framing);
} else if sr.ne() {
r.icr().write(|w| w.set_ne(true));
return Err(Error::Noise);
} else if sr.ore() {
r.icr().write(|w| w.set_ore(true));
return Err(Error::Overrun);
}
Ok(sr.rxne())
}
/// Initiate an asynchronous UART read
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.inner_read(buffer, false).await?;
Ok(())
}
/// Read a single u8 if there is one available, otherwise return WouldBlock
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs();
if self.check_rx_flags()? {
Ok(unsafe { rdr(r).read_volatile() })
} else {
Err(nb::Error::WouldBlock)
}
}
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs();
for b in buffer {
while !self.check_rx_flags()? {}
unsafe { *b = rdr(r).read_volatile() }
}
Ok(())
}
/// Initiate an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.inner_read(buffer, true).await
}
async fn inner_read_run(
&mut self,
buffer: &mut [u8],
enable_idle_line_detection: bool,
) -> Result<ReadCompletionEvent, Error>
where
RxDma: crate::usart::RxDma<T>,
{
let r = T::regs();
// make sure USART state is restored to neutral state when this future is dropped
let on_drop = OnDrop::new(move || {
// defmt::trace!("Clear all USART interrupts and DMA Read Request");
// 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);
});
});
let ch = &mut self.rx_dma;
let request = ch.request();
let buffer_len = buffer.len();
// Start USART DMA
// will not do anything yet because DMAR is not yet set
// future which will complete when DMA Read request completes
let transfer = unsafe { Transfer::new_read(ch, request, rdr(T::regs()), buffer, Default::default()) };
// clear ORE flag just before enabling DMA Rx Request: can be mandatory for the second transfer
if !self.detect_previous_overrun {
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
}
r.cr1().modify(|w| {
// disable RXNE interrupt
w.set_rxneie(false);
// enable parity interrupt if not ParityNone
w.set_peie(w.pce());
});
r.cr3().modify(|w| {
// enable Error Interrupt: (Frame error, Noise error, Overrun error)
w.set_eie(true);
// enable DMA Rx Request
w.set_dmar(true);
});
compiler_fence(Ordering::SeqCst);
// In case of errors already pending when reception started, interrupts may have already been raised
// and lead to reception abortion (Overrun error for instance). In such a case, all interrupts
// have been disabled in interrupt handler and DMA Rx Request has been disabled.
let cr3 = r.cr3().read();
if !cr3.dmar() {
// something went wrong
// because the only way to get this flag cleared is to have an interrupt
// DMA will be stopped when transfer is dropped
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
if sr.pe() {
return Err(Error::Parity);
}
if sr.fe() {
return Err(Error::Framing);
}
if sr.ne() {
return Err(Error::Noise);
}
if sr.ore() {
return Err(Error::Overrun);
}
unreachable!();
}
if enable_idle_line_detection {
// clear idle flag
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
// enable idle interrupt
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
// future which completes when idle line or error is detected
let abort = poll_fn(move |cx| {
let s = T::state();
s.rx_waker.register(cx.waker());
let sr = sr(r).read();
// This read also clears the error and idle interrupt flags on v1.
unsafe { rdr(r).read_volatile() };
clear_interrupt_flags(r, sr);
if enable_idle_line_detection {
// enable idle interrupt
r.cr1().modify(|w| {
w.set_idleie(true);
});
}
compiler_fence(Ordering::SeqCst);
let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
if has_errors {
// all Rx interrupts and Rx DMA Request have already been cleared in interrupt handler
if sr.pe() {
return Poll::Ready(Err(Error::Parity));
}
if sr.fe() {
return Poll::Ready(Err(Error::Framing));
}
if sr.ne() {
return Poll::Ready(Err(Error::Noise));
}
if sr.ore() {
return Poll::Ready(Err(Error::Overrun));
}
}
if enable_idle_line_detection && sr.idle() {
// Idle line detected
return Poll::Ready(Ok(()));
}
Poll::Pending
});
// wait for the first of DMA request or idle line detected to completes
// select consumes its arguments
// when transfer is dropped, it will stop the DMA request
let r = match select(transfer, abort).await {
// DMA transfer completed first
Either::Left(((), _)) => Ok(ReadCompletionEvent::DmaCompleted),
// Idle line detected first
Either::Right((Ok(()), transfer)) => Ok(ReadCompletionEvent::Idle(
buffer_len - transfer.get_remaining_transfers() as usize,
)),
// error occurred
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>
where
RxDma: crate::usart::RxDma<T>,
{
if buffer.is_empty() {
return Ok(0);
} else if buffer.len() > 0xFFFF {
return Err(Error::BufferTooLong);
}
let buffer_len = buffer.len();
// wait for DMA to complete or IDLE line detection if requested
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: BasicInstance, TxDma> Drop for UartTx<'d, T, TxDma> {
fn drop(&mut self) {
T::disable();
}
}
impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
fn drop(&mut self) {
T::disable();
}
}
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
/// Create a new bidirectional UART
pub fn new(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
}
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<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 = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(cts, rts);
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
cts.set_as_af(cts.af_num(), AFType::Input);
T::regs().cr3().write(|w| {
w.set_rtse(true);
w.set_ctse(true);
});
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
}
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
de: impl Peripheral<P = impl DePin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(de);
// UartRx and UartTx have one refcount ea.
T::enable_and_reset();
T::enable_and_reset();
de.set_as_af(de.af_num(), AFType::OutputPushPull);
T::regs().cr3().write(|w| {
w.set_dem(true);
});
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
}
fn new_inner(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
tx_dma: impl Peripheral<P = TxDma> + 'd,
rx_dma: impl Peripheral<P = RxDma> + 'd,
config: Config,
) -> Result<Self, ConfigError> {
into_ref!(peri, rx, tx, tx_dma, rx_dma);
let r = T::regs();
// Some chips do not have swap_rx_tx bit
cfg_if::cfg_if! {
if #[cfg(any(usart_v3, usart_v4))] {
if config.swap_rx_tx {
let (rx, tx) = (tx, rx);
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
} else {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
} else {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
}
configure(r, &config, T::frequency(), T::KIND, true, true)?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
// create state once!
let _s = T::state();
Ok(Self {
tx: UartTx {
tx_dma,
phantom: PhantomData,
},
rx: UartRx {
_peri: peri,
rx_dma,
detect_previous_overrun: config.detect_previous_overrun,
#[cfg(any(usart_v1, usart_v2))]
buffered_sr: stm32_metapac::usart::regs::Sr(0),
},
})
}
/// Initiate an asynchronous write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where
TxDma: crate::usart::TxDma<T>,
{
self.tx.write(buffer).await
}
/// Perform a blocking write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
}
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush()
}
/// Initiate an asynchronous read into `buffer`
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.rx.read(buffer).await
}
/// Read a single `u8` or return `WouldBlock`
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
self.rx.nb_read()
}
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer)
}
/// Initiate an an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
{
self.rx.read_until_idle(buffer).await
}
/// Split the Uart into a transmitter and receiver, which is
/// particularly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T, TxDma>, UartRx<'d, T, RxDma>) {
(self.tx, self.rx)
}
}
fn reconfigure<T: BasicInstance>(config: &Config) -> Result<(), ConfigError> {
T::Interrupt::disable();
let r = T::regs();
let cr = r.cr1().read();
configure(r, config, T::frequency(), T::KIND, cr.re(), cr.te())?;
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
Ok(())
}
fn configure(
r: Regs,
config: &Config,
pclk_freq: Hertz,
kind: Kind,
enable_rx: bool,
enable_tx: bool,
) -> Result<(), ConfigError> {
if !enable_rx && !enable_tx {
return Err(ConfigError::RxOrTxNotEnabled);
}
#[cfg(not(usart_v4))]
static DIVS: [(u16, ()); 1] = [(1, ())];
#[cfg(usart_v4)]
static DIVS: [(u16, vals::Presc); 12] = [
(1, vals::Presc::DIV1),
(2, vals::Presc::DIV2),
(4, vals::Presc::DIV4),
(6, vals::Presc::DIV6),
(8, vals::Presc::DIV8),
(10, vals::Presc::DIV10),
(12, vals::Presc::DIV12),
(16, vals::Presc::DIV16),
(32, vals::Presc::DIV32),
(64, vals::Presc::DIV64),
(128, vals::Presc::DIV128),
(256, vals::Presc::DIV256),
];
let (mul, brr_min, brr_max) = match kind {
#[cfg(any(usart_v3, usart_v4))]
Kind::Lpuart => (256, 0x300, 0x10_0000),
Kind::Uart => (1, 0x10, 0x1_0000),
};
fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 {
// The calculation to be done to get the BRR is `mul * pclk / presc / baud`
// To do this in 32-bit only we can't multiply `mul` and `pclk`
let clock = pclk / presc;
// The mul is applied as the last operation to prevent overflow
let brr = clock / baud * mul;
// The BRR calculation will be a bit off because of integer rounding.
// Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul.
let rounding = ((clock % baud) * mul + (baud / 2)) / baud;
brr + rounding
}
// UART must be disabled during configuration.
r.cr1().modify(|w| {
w.set_ue(false);
});
#[cfg(not(usart_v1))]
let mut over8 = false;
let mut found_brr = None;
for &(presc, _presc_val) in &DIVS {
let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul);
trace!(
"USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})",
presc,
brr,
brr >> 4,
brr & 0x0F
);
if brr < brr_min {
#[cfg(not(usart_v1))]
if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
over8 = true;
r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07)));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
found_brr = Some(brr);
break;
}
return Err(ConfigError::BaudrateTooHigh);
}
if brr < brr_max {
r.brr().write_value(regs::Brr(brr));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
found_brr = Some(brr);
break;
}
}
let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?;
#[cfg(not(usart_v1))]
let oversampling = if over8 { "8 bit" } else { "16 bit" };
#[cfg(usart_v1)]
let oversampling = "default";
trace!(
"Using {} oversampling, desired baudrate: {}, actual baudrate: {}",
oversampling,
config.baudrate,
pclk_freq.0 / brr * mul
);
r.cr2().write(|w| {
w.set_stop(match config.stop_bits {
StopBits::STOP0P5 => vals::Stop::STOP0P5,
StopBits::STOP1 => vals::Stop::STOP1,
StopBits::STOP1P5 => vals::Stop::STOP1P5,
StopBits::STOP2 => vals::Stop::STOP2,
});
#[cfg(any(usart_v3, usart_v4))]
{
w.set_txinv(config.invert_tx);
w.set_rxinv(config.invert_rx);
w.set_swap(config.swap_rx_tx);
}
});
#[cfg(not(usart_v1))]
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
});
r.cr1().write(|w| {
// enable uart
w.set_ue(true);
// enable transceiver
w.set_te(enable_tx);
// enable receiver
w.set_re(enable_rx);
// configure word size
// if using odd or even parity it must be configured to 9bits
w.set_m0(if config.parity != Parity::ParityNone {
vals::M0::BIT9
} else {
vals::M0::BIT8
});
// configure parity
w.set_pce(config.parity != Parity::ParityNone);
w.set_ps(match config.parity {
Parity::ParityOdd => vals::Ps::ODD,
Parity::ParityEven => vals::Ps::EVEN,
_ => vals::Ps::EVEN,
});
#[cfg(not(usart_v1))]
w.set_over8(vals::Over8::from_bits(over8 as _));
#[cfg(usart_v4)]
w.set_fifoen(true);
});
Ok(())
}
impl<'d, T: BasicInstance, RxDma> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, RxDma> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, TxDma> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, TxDma> {
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: BasicInstance, TxDma, RxDma> embedded_hal_02::serial::Read<u8> for Uart<'d, T, TxDma, RxDma> {
type Error = Error;
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, TxDma, RxDma> {
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: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> {
type Error = Error;
}
impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> {
type Error = Error;
}
impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> {
type Error = Error;
}
impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::Read for UartRx<'d, T, RxDma> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> {
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: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Read for Uart<'d, T, TxDma, RxDma> {
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
self.nb_read()
}
}
impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> {
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, TxDma, RxDma> embedded_io::ErrorType for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma> embedded_io::ErrorType for UartTx<'_, T, TxDma>
where
T: BasicInstance,
{
type Error = Error;
}
impl<T, TxDma, RxDma> embedded_io::Write for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
TxDma: crate::usart::TxDma<T>,
{
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, TxDma> embedded_io::Write for UartTx<'_, T, TxDma>
where
T: BasicInstance,
TxDma: crate::usart::TxDma<T>,
{
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, TxDma, RxDma> embedded_io_async::Write for Uart<'_, T, TxDma, RxDma>
where
T: BasicInstance,
TxDma: self::TxDma<T>,
{
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.blocking_flush()
}
}
impl<T, TxDma> embedded_io_async::Write for UartTx<'_, T, TxDma>
where
T: BasicInstance,
TxDma: self::TxDma<T>,
{
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.blocking_flush()
}
}
pub use buffered::*;
pub use crate::usart::buffered::InterruptHandler as BufferedInterruptHandler;
mod buffered;
#[cfg(not(gpdma))]
mod ringbuffered;
#[cfg(not(gpdma))]
pub use ringbuffered::RingBufferedUartRx;
use self::sealed::Kind;
#[cfg(any(usart_v1, usart_v2))]
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().as_ptr() as _
}
#[cfg(any(usart_v1, usart_v2))]
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().as_ptr() as _
}
#[cfg(any(usart_v1, usart_v2))]
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
r.sr()
}
#[cfg(any(usart_v1, usart_v2))]
#[allow(unused)]
fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
// On v1 the flags are cleared implicitly by reads and writes to DR.
}
#[cfg(any(usart_v3, usart_v4))]
fn tdr(r: Regs) -> *mut u8 {
r.tdr().as_ptr() as _
}
#[cfg(any(usart_v3, usart_v4))]
fn rdr(r: Regs) -> *mut u8 {
r.rdr().as_ptr() as _
}
#[cfg(any(usart_v3, usart_v4))]
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
r.isr()
}
#[cfg(any(usart_v3, usart_v4))]
#[allow(unused)]
fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
r.icr().write(|w| *w = regs::Icr(sr.0));
}
pub(crate) mod sealed {
use embassy_sync::waitqueue::AtomicWaker;
use super::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Uart,
#[cfg(any(usart_v3, usart_v4))]
Lpuart,
}
pub struct State {
pub rx_waker: AtomicWaker,
pub tx_waker: AtomicWaker,
}
impl State {
pub const fn new() -> Self {
Self {
rx_waker: AtomicWaker::new(),
tx_waker: AtomicWaker::new(),
}
}
}
pub trait BasicInstance: crate::rcc::RccPeripheral {
const KIND: Kind;
type Interrupt: interrupt::typelevel::Interrupt;
fn regs() -> Regs;
fn state() -> &'static State;
fn buffered_state() -> &'static buffered::State;
}
pub trait FullInstance: BasicInstance {
fn regs_uart() -> crate::pac::usart::Usart;
}
}
/// Basic UART driver instance
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
/// Full UART driver instance
pub trait FullInstance: sealed::FullInstance {}
pin_trait!(RxPin, BasicInstance);
pin_trait!(TxPin, BasicInstance);
pin_trait!(CtsPin, BasicInstance);
pin_trait!(RtsPin, BasicInstance);
pin_trait!(CkPin, BasicInstance);
pin_trait!(DePin, BasicInstance);
dma_trait!(TxDma, BasicInstance);
dma_trait!(RxDma, BasicInstance);
macro_rules! impl_usart {
($inst:ident, $irq:ident, $kind:expr) => {
impl sealed::BasicInstance for crate::peripherals::$inst {
const KIND: Kind = $kind;
type Interrupt = crate::interrupt::typelevel::$irq;
fn regs() -> Regs {
unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }
}
fn state() -> &'static crate::usart::sealed::State {
static STATE: crate::usart::sealed::State = crate::usart::sealed::State::new();
&STATE
}
fn buffered_state() -> &'static buffered::State {
static STATE: buffered::State = buffered::State::new();
&STATE
}
}
impl BasicInstance for peripherals::$inst {}
};
}
foreach_interrupt!(
($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
impl_usart!($inst, $irq, Kind::Lpuart);
};
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
impl_usart!($inst, $irq, Kind::Uart);
impl sealed::FullInstance for peripherals::$inst {
fn regs_uart() -> crate::pac::usart::Usart {
crate::pac::$inst
}
}
impl FullInstance for peripherals::$inst {}
};
);