use crate::{
gpio::{gpioa, gpiob, gpioc, AF7},
hal::{blocking, serial},
pac::{USART1, USART2, USART3},
rcc::{Clocks, APB1, APB2},
time::Bps,
};
use cfg_if::cfg_if;
use core::{convert::Infallible, marker::PhantomData, ptr};
cfg_if! {
if #[cfg(any(feature = "stm32f302", feature = "stm32f303"))] {
use crate::dma;
use cortex_m::interrupt;
}
}
pub enum Event {
Rxne,
Txe,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
}
pub unsafe trait TxPin<USART> {}
pub unsafe trait RxPin<USART> {}
unsafe impl TxPin<USART1> for gpioa::PA9<AF7> {}
unsafe impl TxPin<USART1> for gpiob::PB6<AF7> {}
unsafe impl TxPin<USART1> for gpioc::PC4<AF7> {}
unsafe impl RxPin<USART1> for gpioa::PA10<AF7> {}
unsafe impl RxPin<USART1> for gpiob::PB7<AF7> {}
unsafe impl RxPin<USART1> for gpioc::PC5<AF7> {}
unsafe impl TxPin<USART2> for gpioa::PA2<AF7> {}
unsafe impl TxPin<USART2> for gpiob::PB3<AF7> {}
unsafe impl RxPin<USART2> for gpioa::PA3<AF7> {}
unsafe impl RxPin<USART2> for gpiob::PB4<AF7> {}
unsafe impl TxPin<USART3> for gpiob::PB10<AF7> {}
unsafe impl TxPin<USART3> for gpioc::PC10<AF7> {}
unsafe impl RxPin<USART3> for gpioc::PC11<AF7> {}
cfg_if! {
if #[cfg(any(feature = "gpio-f303", feature = "gpio-f303e", feature = "gpio-f373"))] {
use crate::gpio::{gpiod, gpioe};
unsafe impl TxPin<USART1> for gpioe::PE0<AF7> {}
unsafe impl RxPin<USART1> for gpioe::PE1<AF7> {}
unsafe impl TxPin<USART2> for gpiod::PD5<AF7> {}
unsafe impl RxPin<USART2> for gpiod::PD6<AF7> {}
unsafe impl TxPin<USART3> for gpiod::PD8<AF7> {}
unsafe impl RxPin<USART3> for gpiod::PD9<AF7> {}
unsafe impl RxPin<USART3> for gpioe::PE15<AF7> {}
}
}
cfg_if! {
if #[cfg(not(feature = "gpio-f373"))] {
unsafe impl TxPin<USART2> for gpioa::PA14<AF7> {}
unsafe impl RxPin<USART2> for gpioa::PA15<AF7> {}
unsafe impl RxPin<USART3> for gpiob::PB11<AF7> {}
}
}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
macro_rules! hal {
($(
$USARTX:ident: ($usartX:ident, $APB:ident, $usartXen:ident, $usartXrst:ident, $pclkX:ident),
)+) => {
$(
impl<TX, RX> Serial<$USARTX, (TX, RX)> {
pub fn $usartX(
usart: $USARTX,
pins: (TX, RX),
baud_rate: Bps,
clocks: Clocks,
apb: &mut $APB,
) -> Self
where
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
apb.enr().modify(|_, w| w.$usartXen().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
let brr = clocks.$pclkX().0 / baud_rate.0;
crate::assert!(brr >= 16, "impossible baud rate");
usart.brr.write(|w| unsafe { w.bits(brr) });
usart.cr1.modify(|_, w| {
w.ue().enabled();
w.re().enabled();
w.te().enabled()
});
Serial { usart, pins }
}
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())
},
}
}
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())
},
}
}
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
pub fn free(self) -> ($USARTX, (TX, RX)) {
(self.usart, self.pins)
}
}
impl serial::Read<u8> for Rx<$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
let icr = unsafe { &(*$USARTX::ptr()).icr };
Err(if isr.pe().bit_is_set() {
icr.write(|w| w.pecf().clear());
nb::Error::Other(Error::Parity)
} else if isr.fe().bit_is_set() {
icr.write(|w| w.fecf().clear());
nb::Error::Other(Error::Framing)
} else if isr.nf().bit_is_set() {
icr.write(|w| w.ncf().clear());
nb::Error::Other(Error::Noise)
} else if isr.ore().bit_is_set() {
icr.write(|w| w.orecf().clear());
nb::Error::Other(Error::Overrun)
} else if isr.rxne().bit_is_set() {
return Ok(unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _ as *const _)
});
} else {
nb::Error::WouldBlock
})
}
}
impl serial::Write<u8> for Tx<$USARTX> {
type Error = Infallible;
fn flush(&mut self) -> nb::Result<(), Infallible> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
if isr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
if isr.txe().bit_is_set() {
unsafe {
ptr::write_volatile(&(*$USARTX::ptr()).tdr as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl blocking::serial::write::Default<u8> for Tx<$USARTX> {}
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
impl Rx<$USARTX> {
pub fn read_exact<B, C>(
self,
buffer: B,
mut channel: C
) -> dma::Transfer<B, C, Self>
where
Self: dma::OnChannel<C>,
B: dma::WriteBuffer<Word = u8> + 'static,
C: dma::Channel,
{
let pa = unsafe { &(*$USARTX::ptr()).rdr } as *const _ as u32;
unsafe { channel.set_peripheral_address(pa, dma::Increment::Disable) };
dma::Transfer::start_write(buffer, channel, self)
}
}
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
impl Tx<$USARTX> {
pub fn write_all<B, C>(
self,
buffer: B,
mut channel: C
) -> dma::Transfer<B, C, Self>
where
Self: dma::OnChannel<C>,
B: dma::ReadBuffer<Word = u8> + 'static,
C: dma::Channel,
{
let pa = unsafe { &(*$USARTX::ptr()).tdr } as *const _ as u32;
unsafe { channel.set_peripheral_address(pa, dma::Increment::Disable) };
dma::Transfer::start_read(buffer, channel, self)
}
}
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
impl dma::Target for Rx<$USARTX> {
fn enable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmar().enabled());
});
}
fn disable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmar().disabled());
});
}
}
#[cfg(any(feature = "stm32f302", feature = "stm32f303"))]
impl dma::Target for Tx<$USARTX> {
fn enable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmat().enabled());
});
}
fn disable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmat().disabled());
});
}
}
)+
}
}
hal! {
USART1: (usart1, APB2, usart1en, usart1rst, pclk2),
USART2: (usart2, APB1, usart2en, usart2rst, pclk1),
USART3: (usart3, APB1, usart3en, usart3rst, pclk1),
}