use as_slice::AsMutSlice;
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::DerefMut;
use core::ptr;
use core::sync::atomic::{self, Ordering};
use generic_array::ArrayLength;
use stable_deref_trait::StableDeref;
use embedded_hal::serial::{Read, Write};
use crate::{
dma::{dma1, CircBuffer, DMAFrame, FrameReader, FrameSender},
pac::{self, RCC},
rcc_en_reset,
traits::ClockCfg,
};
use paste::paste;
#[cfg(any(feature = "stm32l4x5", feature = "stm32l4x6",))]
use crate::dma::dma2;
pub enum Event {
Rxne,
Txe,
Idle,
CharacterMatch,
ReceiverTimeout,
}
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
}
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
pub enum StopBits {
STOP1,
STOP0P5,
STOP2,
STOP1P5,
}
pub enum Oversampling {
Over8,
Over16,
}
pub struct Config {
baudrate: u32,
parity: Parity,
stopbits: StopBits,
oversampling: Oversampling,
character_match: Option<u8>,
receiver_timeout: Option<u32>,
disable_overrun: bool,
onebit_sampling: bool,
}
impl Config {
pub fn baudrate(mut self, baudrate: u32) -> Self {
self.baudrate = baudrate;
self
}
pub fn parity_none(mut self) -> Self {
self.parity = Parity::ParityNone;
self
}
pub fn parity_even(mut self) -> Self {
self.parity = Parity::ParityEven;
self
}
pub fn parity_odd(mut self) -> Self {
self.parity = Parity::ParityOdd;
self
}
pub fn stopbits(mut self, stopbits: StopBits) -> Self {
self.stopbits = stopbits;
self
}
pub fn oversampling(mut self, oversampling: Oversampling) -> Self {
self.oversampling = oversampling;
self
}
pub fn character_match(mut self, character_match: u8) -> Self {
self.character_match = Some(character_match);
self
}
pub fn receiver_timeout(mut self, receiver_timeout: u32) -> Self {
assert!(receiver_timeout < 1 << 24);
self.receiver_timeout = Some(receiver_timeout);
self
}
pub fn with_overrun_disabled(mut self) -> Self {
self.disable_overrun = true;
self
}
pub fn with_onebit_sampling(mut self) -> Self {
self.onebit_sampling = true;
self
}
}
impl Default for Config {
fn default() -> Config {
let baudrate = 115_200;
Config {
baudrate,
parity: Parity::ParityNone,
stopbits: StopBits::STOP1,
oversampling: Oversampling::Over16,
character_match: None,
receiver_timeout: None,
disable_overrun: false,
onebit_sampling: false,
}
}
}
pub struct Serial<USART> {
usart: USART,
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
macro_rules! hal {
(
$USARTX:ident,
$usart:ident,
$apb:expr,
$dmacst:ident,
$tx_chan:path,
$dmacsr:ident,
$rx_chan:path
) => {
impl Serial<pac::$USARTX> {
paste! {
pub fn [<new_ $usart>]<C: ClockCfg>(
usart: pac::$USARTX,
config: Config,
clocks: &C,
rcc: &mut RCC,
) -> Self
where {
rcc_en_reset!($apb, $usart, rcc);
usart.cr1.reset();
usart.cr2.reset();
usart.cr3.reset();
match config.oversampling {
Oversampling::Over8 => {
let uartdiv = 2 * clocks.[<apb $apb>]() / config.baudrate;
assert!(uartdiv >= 16, "impossible baud rate");
let lower = (uartdiv & 0xf) >> 1;
let brr = (uartdiv & !0xf) | lower;
usart.cr1.modify(|_, w| w.over8().set_bit());
usart.brr.write(|w| unsafe { w.bits(brr) });
}
Oversampling::Over16 => {
let brr = clocks.[<apb $apb>]() / config.baudrate;
assert!(brr >= 16, "impossible baud rate");
usart.brr.write(|w| unsafe { w.bits(brr) });
}
}
if let Some(val) = config.receiver_timeout {
usart.rtor.modify(|_, w| w.rto().bits(val));
}
usart.cr3.modify(|_, w| w.dmat().set_bit().dmar().set_bit());
usart.cr3.modify(|_, w| w.rtse().clear_bit().ctse().clear_bit());
usart.cr3.modify(|_, w| {
if config.onebit_sampling {
w.onebit().set_bit();
}
if config.disable_overrun {
w.ovrdis().set_bit();
}
w
});
let (word_length, parity_control_enable, parity) = match config.parity {
Parity::ParityNone => (false, false, false),
Parity::ParityEven => (true, true, false),
Parity::ParityOdd => (true, true, true),
};
usart.cr1.modify(|_r, w| {
w
.m0().bit(word_length)
.ps().bit(parity)
.pce().bit(parity_control_enable)
});
let stop_bits = match config.stopbits {
StopBits::STOP1 => 0b00,
StopBits::STOP0P5 => 0b01,
StopBits::STOP2 => 0b10,
StopBits::STOP1P5 => 0b11,
};
usart.cr2.modify(|_r, w| {
w.stop().bits(stop_bits);
if let Some(c) = config.character_match {
w.add().bits(c);
}
if config.receiver_timeout.is_some() {
w.rtoen().set_bit();
}
w
});
usart
.cr1
.modify(|_, w| w.ue().set_bit().re().set_bit().te().set_bit());
Serial { usart }
}
}
pub fn listen(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().set_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().set_bit()),
Event::Idle => self.usart.cr1.modify(|_, w| w.idleie().set_bit()),
Event::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().set_bit()),
Event::ReceiverTimeout => self.usart.cr1.modify(|_, w| w.rtoie().set_bit()),
}
}
pub fn check_for_error() -> Result<(), Error> {
let mut rx: Rx<pac::$USARTX> = Rx {
_usart: PhantomData,
};
rx.check_for_error()
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().clear_bit()),
Event::Idle => self.usart.cr1.modify(|_, w| w.idleie().clear_bit()),
Event::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().clear_bit()),
Event::ReceiverTimeout => self.usart.cr1.modify(|_, w| w.rtoie().clear_bit()),
}
}
pub fn split(self) -> (Tx<pac::$USARTX>, Rx<pac::$USARTX>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
pub fn release(self) -> pac::$USARTX {
self.usart
}
}
impl Read<u8> for Serial<pac::$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let mut rx: Rx<pac::$USARTX> = Rx {
_usart: PhantomData,
};
rx.read()
}
}
impl Read<u8> for Rx<pac::$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
self.check_for_error()?;
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
if isr.rxne().bit_is_set() {
return Ok(unsafe {
ptr::read_volatile(&(*pac::$USARTX::ptr()).rdr as *const _ as *const _)
});
}
Err(nb::Error::WouldBlock)
}
}
impl Write<u8> for Serial<pac::$USARTX> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Error> {
let mut tx: Tx<pac::$USARTX> = Tx {
_usart: PhantomData,
};
tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
let mut tx: Tx<pac::$USARTX> = Tx {
_usart: PhantomData,
};
tx.write(byte)
}
}
impl Write<u8> for Tx<pac::$USARTX> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Error> {
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
if isr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Error> {
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
if isr.txe().bit_is_set() {
unsafe {
ptr::write_volatile(&(*pac::$USARTX::ptr()).tdr as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl embedded_hal::blocking::serial::write::Default<u8> for Tx<pac::$USARTX> {}
impl Rx<pac::$USARTX> {
pub fn circ_read<B, H>(
&self,
mut chan: $rx_chan,
mut buffer: B,
) -> CircBuffer<B, $rx_chan>
where
B: StableDeref<Target = [H; 2]> + DerefMut + 'static,
H: AsMutSlice<Element = u8>,
{
let buf = buffer[0].as_mut_slice();
chan.set_peripheral_address(
unsafe { &(*pac::$USARTX::ptr()).rdr as *const _ as u32 },
false,
);
chan.set_memory_address(buf.as_ptr() as u32, true);
chan.set_transfer_length((buf.len() * 2) as u16);
chan.cselr().modify(|_, w| {
w.$dmacsr().bits(0b0010)
});
chan.ccr().modify(|_, w| unsafe {
w.mem2mem()
.clear_bit()
.pl()
.bits(0b01)
.msize()
.bits(0b00)
.psize()
.bits(0b00)
.circ()
.set_bit()
.dir()
.clear_bit()
});
atomic::compiler_fence(Ordering::Release);
chan.start();
CircBuffer::new(buffer, chan)
}
pub fn frame_read<BUFFER, N>(
&self,
mut channel: $rx_chan,
buffer: BUFFER,
) -> FrameReader<BUFFER, $rx_chan, N>
where
BUFFER: Sized + StableDeref<Target = DMAFrame<N>> + DerefMut + 'static,
N: ArrayLength<MaybeUninit<u8>>,
{
let usart = unsafe { &(*pac::$USARTX::ptr()) };
let buf = &*buffer;
channel.set_peripheral_address(&usart.rdr as *const _ as u32, false);
channel.set_memory_address(unsafe { buf.buffer_address_for_dma() } as u32, true);
channel.set_transfer_length(buf.max_len() as u16);
channel.cselr().modify(|_, w| {
w.$dmacsr().bits(0b0010)
});
channel.ccr().modify(|_, w| unsafe {
w.mem2mem()
.clear_bit()
.pl()
.bits(0b01)
.msize()
.bits(0b00)
.psize()
.bits(0b00)
.dir()
.clear_bit()
});
atomic::compiler_fence(Ordering::Release);
channel.start();
FrameReader::new(buffer, channel, usart.cr2.read().add().bits())
}
pub fn is_idle(&mut self, clear: bool) -> bool {
let isr = unsafe { &(*pac::$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
if isr.idle().bit_is_set() {
if clear {
icr.write(|w| w.idlecf().set_bit());
}
true
} else {
false
}
}
pub fn is_character_match(&mut self, clear: bool) -> bool {
let isr = unsafe { &(*pac::$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
if isr.cmf().bit_is_set() {
if clear {
icr.write(|w| w.cmcf().set_bit());
}
true
} else {
false
}
}
pub fn is_receiver_timeout(&mut self, clear: bool) -> bool {
let isr = unsafe { &(*pac::$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
if isr.rtof().bit_is_set() {
if clear {
icr.write(|w| w.rtocf().set_bit());
}
true
} else {
false
}
}
pub fn check_for_error(&mut self) -> Result<(), Error> {
let isr = unsafe { (*pac::$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*pac::$USARTX::ptr()).icr };
if isr.pe().bit_is_set() {
icr.write(|w| w.pecf().set_bit());
return Err(Error::Parity);
}
if isr.fe().bit_is_set() {
icr.write(|w| w.fecf().set_bit());
return Err(Error::Framing);
}
if isr.nf().bit_is_set() {
icr.write(|w| w.ncf().set_bit());
return Err(Error::Noise);
}
if isr.ore().bit_is_set() {
icr.write(|w| w.orecf().set_bit());
return Err(Error::Overrun);
}
Ok(())
}
}
impl Tx<pac::$USARTX> {
pub fn frame_sender<BUFFER, N>(
&self,
mut channel: $tx_chan,
) -> FrameSender<BUFFER, $tx_chan, N>
where
BUFFER: Sized + StableDeref<Target = DMAFrame<N>> + DerefMut + 'static,
N: ArrayLength<MaybeUninit<u8>>,
{
let usart = unsafe { &(*pac::$USARTX::ptr()) };
channel.set_peripheral_address(&usart.tdr as *const _ as u32, false);
channel.cselr().modify(|_, w| {
w.$dmacst().bits(0b0010)
});
channel.ccr().modify(|_, w| unsafe {
w.mem2mem()
.clear_bit()
.pl()
.bits(0b01)
.msize()
.bits(0b00)
.psize()
.bits(0b00)
.dir()
.set_bit()
});
FrameSender::new(channel)
}
}
};
}
hal!(USART1, usart1, 2, c4s, dma1::C4, c5s, dma1::C5);
hal!(USART2, usart2, 1, c7s, dma1::C7, c6s, dma1::C6);
#[cfg(any(
feature = "stm32l4x2",
feature = "stm32l4x3",
feature = "stm32l4x5",
feature = "stm32l4x6",
))]
hal!(USART3, usart3, 1, c2s, dma1::C2, c3s, dma1::C3);
#[cfg(any(feature = "stm32l4x5", feature = "stm32l4x6",))]
hal!(UART4, uart4, 1, c3s, dma2::C3, c5s, dma2::C5);
#[cfg(any(feature = "stm32l4x5", feature = "stm32l4x6",))]
hal!(UART5, uart5, 1, c1s, dma2::C1, c2s, dma2::C2);
impl<USART> fmt::Write for Serial<USART>
where
Serial<USART>: Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s
.as_bytes()
.iter()
.map(|c| nb::block!(self.write(*c)))
.last();
Ok(())
}
}
impl<USART> fmt::Write for Tx<USART>
where
Tx<USART>: Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s
.as_bytes()
.iter()
.map(|c| nb::block!(self.write(*c)))
.last();
Ok(())
}
}