use core::fmt;
use core::marker::PhantomData;
use crate::dma;
use crate::dmamux::DmaMuxIndex;
use crate::gpio::AltFunction;
use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiod::*};
use crate::prelude::*;
use crate::rcc::Rcc;
use crate::stm32::*;
use cortex_m::interrupt;
use nb::block;
use crate::serial::config::*;
#[derive(Debug)]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
}
pub enum Event {
TXFT = 1 << 27,
RXFT = 1 << 26,
RXFF = 1 << 24,
TXFE = 1 << 23,
BUSY = 1 << 16,
RTOF = 1 << 11,
Txe = 1 << 7,
TC = 1 << 6,
Rxne = 1 << 5,
Idle = 1 << 4,
ORE = 1 << 3,
NE = 1 << 2,
FE = 1 << 1,
PE = 1 << 0,
}
impl Event {
fn val(self) -> u32 {
self as u32
}
}
pub struct Rx<USART, Config> {
_usart: PhantomData<USART>,
_config: PhantomData<Config>,
}
pub struct Tx<USART, Config> {
_usart: PhantomData<USART>,
_config: PhantomData<Config>,
}
pub struct Serial<USART, Config> {
tx: Tx<USART, Config>,
rx: Rx<USART, Config>,
usart: USART,
_config: PhantomData<Config>,
}
pub trait TxPin<USART> {
fn setup(&self);
}
pub trait RxPin<USART> {
fn setup(&self);
}
pub trait SerialExt<USART, Config> {
fn usart<TX, RX>(
self,
tx: TX,
rx: RX,
config: Config,
rcc: &mut Rcc,
) -> Result<Serial<USART, Config>, InvalidConfig>
where
TX: TxPin<USART>,
RX: RxPin<USART>;
}
impl<USART, Config> fmt::Write for Serial<USART, Config>
where
Serial<USART, Config>: hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last();
Ok(())
}
}
impl<USART, Config> fmt::Write for Tx<USART, Config>
where
Tx<USART, Config>: hal::serial::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last();
Ok(())
}
}
macro_rules! uart_shared {
($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident,
tx: [ $(($PTX:ident, $TAF:expr),)+ ],
rx: [ $(($PRX:ident, $RAF:expr),)+ ]) => {
$(
impl<MODE> TxPin<$USARTX> for $PTX<MODE> {
fn setup(&self) {
self.set_alt_mode($TAF)
}
}
)+
$(
impl<MODE> RxPin<$USARTX> for $PRX<MODE> {
fn setup(&self) {
self.set_alt_mode($RAF)
}
}
)+
impl<Config> Rx<$USARTX, Config> {
pub fn listen(&mut self) {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.cr1.modify(|_, w| w.rxneie().set_bit());
}
pub fn unlisten(&mut self) {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.cr1.modify(|_, w| w.rxneie().clear_bit());
}
}
impl<Config> hal::serial::Read<u8> for Rx<$USARTX, Config> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let usart = unsafe { &(*$USARTX::ptr()) };
let isr = usart.isr.read();
Err(
if isr.pe().bit_is_set() {
usart.icr.write(|w| w.pecf().set_bit());
nb::Error::Other(Error::Parity)
} else if isr.fe().bit_is_set() {
usart.icr.write(|w| w.fecf().set_bit());
nb::Error::Other(Error::Framing)
} else if isr.nf().bit_is_set() {
usart.icr.write(|w| w.ncf().set_bit());
nb::Error::Other(Error::Noise)
} else if isr.ore().bit_is_set() {
usart.icr.write(|w| w.orecf().set_bit());
nb::Error::Other(Error::Overrun)
} else if isr.rxne().bit_is_set() {
return Ok(usart.rdr.read().bits() as u8)
} else {
nb::Error::WouldBlock
}
)
}
}
impl<Config> hal::serial::Read<u8> for Serial<$USARTX, Config> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
self.rx.read()
}
}
impl<Config> Tx<$USARTX, Config> {
pub fn listen(&mut self) {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.cr1.modify(|_, w| w.txeie().set_bit());
}
pub fn unlisten(&mut self) {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.cr1.modify(|_, w| w.txeie().clear_bit());
}
}
impl<Config> hal::serial::Write<u8> for Tx<$USARTX, Config> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let usart = unsafe { &(*$USARTX::ptr()) };
if usart.isr.read().tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let usart = unsafe { &(*$USARTX::ptr()) };
if usart.isr.read().txe().bit_is_set() {
usart.tdr.write(|w| unsafe { w.bits(byte as u32) });
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<Config> hal::serial::Write<u8> for Serial<$USARTX, Config> {
type Error = Error;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
self.tx.write(byte)
}
}
impl<Config> Serial<$USARTX, Config> {
pub fn split(self) -> (Tx<$USARTX, Config>, Rx<$USARTX, Config>) {
(self.tx, self.rx)
}
}
impl<Config> dma::Target for Rx<$USARTX, Config> {
fn dmamux(&self) -> DmaMuxIndex {
DmaMuxIndex::$dmamux_rx
}
fn enable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmar().set_bit());
});
}
fn disable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmar().clear_bit());
});
}
}
impl<Config> dma::Target for Tx<$USARTX, Config> {
fn dmamux(&self) -> DmaMuxIndex {
DmaMuxIndex::$dmamux_tx
}
fn enable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmat().set_bit());
});
}
fn disable_dma(&mut self) {
interrupt::free(|_| unsafe {
let cr3 = &(*$USARTX::ptr()).cr3;
cr3.modify(|_, w| w.dmat().clear_bit());
});
}
}
}
}
macro_rules! uart_basic {
($USARTX:ident,
$usartX:ident, $apbXenr:ident, $usartXen:ident, $clk_mul:expr
) => {
impl SerialExt<$USARTX, BasicConfig> for $USARTX {
fn usart<TX, RX>(
self,
tx: TX,
rx: RX,
config: BasicConfig,
rcc: &mut Rcc,
) -> Result<Serial<$USARTX, BasicConfig>, InvalidConfig>
where
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
Serial::$usartX(self, tx, rx, config, rcc)
}
}
impl Serial<$USARTX, BasicConfig> {
pub fn $usartX<TX, RX>(
usart: $USARTX,
tx: TX,
rx: RX,
config: BasicConfig,
rcc: &mut Rcc,
) -> Result<Self, InvalidConfig>
where
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
tx.setup();
rx.setup();
rcc.rb.$apbXenr.modify(|_, w| w.$usartXen().set_bit());
let clk = rcc.clocks.apb_clk.0 as u64;
let bdr = config.baudrate.0 as u64;
let div = ($clk_mul * clk) / bdr;
usart.brr.write(|w| unsafe { w.bits(div as u32) });
usart.cr2.reset();
usart.cr3.reset();
usart.cr1.modify(|_, w| w.ue().clear_bit());
usart.cr1.write(|w| {
w.te()
.set_bit()
.re()
.set_bit()
.m0()
.bit(config.wordlength == WordLength::DataBits9)
.m1()
.bit(config.wordlength == WordLength::DataBits7)
.pce()
.bit(config.parity != Parity::ParityNone)
.ps()
.bit(config.parity == Parity::ParityOdd)
});
usart.cr2.write(|w| unsafe {
w.stop()
.bits(match config.stopbits {
StopBits::STOP1 => 0b00,
StopBits::STOP0P5 => 0b01,
StopBits::STOP2 => 0b10,
StopBits::STOP1P5 => 0b11,
})
.swap()
.bit(config.swap)
});
usart.cr1.modify(|_, w| w.ue().set_bit());
Ok(Serial {
tx: Tx {
_usart: PhantomData,
_config: PhantomData,
},
rx: Rx {
_usart: PhantomData,
_config: PhantomData,
},
usart,
_config: PhantomData,
})
}
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()),
_ => {}
}
}
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()),
_ => {}
}
}
pub fn is_pending(&mut self, event: Event) -> bool {
(self.usart.isr.read().bits() & event.val()) != 0
}
pub fn unpend(&mut self, event: Event) {
let mask: u32 = 0x123BFF;
self.usart
.icr
.write(|w| unsafe { w.bits(event.val() & mask) });
}
}
};
}
macro_rules! uart_full {
($USARTX:ident,
$usartX:ident, $apbXenr:ident, $usartXen:ident, $clk_mul:expr
) => {
impl SerialExt<$USARTX, FullConfig> for $USARTX {
fn usart<TX, RX>(
self,
tx: TX,
rx: RX,
config: FullConfig,
rcc: &mut Rcc,
) -> Result<Serial<$USARTX, FullConfig>, InvalidConfig>
where
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
Serial::$usartX(self, tx, rx, config, rcc)
}
}
impl Serial<$USARTX, FullConfig> {
pub fn $usartX<TX, RX>(
usart: $USARTX,
tx: TX,
rx: RX,
config: FullConfig,
rcc: &mut Rcc,
) -> Result<Self, InvalidConfig>
where
TX: TxPin<$USARTX>,
RX: RxPin<$USARTX>,
{
tx.setup();
rx.setup();
rcc.rb.$apbXenr.modify(|_, w| w.$usartXen().set_bit());
let clk = rcc.clocks.apb_clk.0 as u64;
let bdr = config.baudrate.0 as u64;
let clk_mul = 1;
let div = (clk_mul * clk) / bdr;
usart.brr.write(|w| unsafe { w.bits(div as u32) });
usart.cr1.reset();
usart.cr2.reset();
usart.cr3.reset();
usart.cr2.write(|w| unsafe {
w.stop()
.bits(config.stopbits.bits())
.swap()
.bit(config.swap)
});
if let Some(timeout) = config.receiver_timeout {
usart.cr1.write(|w| w.rtoie().set_bit());
usart.cr2.modify(|_, w| w.rtoen().set_bit());
usart.rtor.write(|w| unsafe { w.rto().bits(timeout) });
}
usart.cr3.write(|w| unsafe {
w.txftcfg()
.bits(config.tx_fifo_threshold.bits())
.rxftcfg()
.bits(config.rx_fifo_threshold.bits())
.txftie()
.bit(config.tx_fifo_interrupt)
.rxftie()
.bit(config.rx_fifo_interrupt)
});
usart.cr1.modify(|_, w| {
w.ue()
.set_bit()
.te()
.set_bit()
.re()
.set_bit()
.m0()
.bit(config.wordlength == WordLength::DataBits7)
.m1()
.bit(config.wordlength == WordLength::DataBits9)
.pce()
.bit(config.parity != Parity::ParityNone)
.ps()
.bit(config.parity == Parity::ParityOdd)
.fifoen()
.bit(config.fifo_enable)
});
Ok(Serial {
tx: Tx {
_usart: PhantomData,
_config: PhantomData,
},
rx: Rx {
_usart: PhantomData,
_config: PhantomData,
},
usart,
_config: PhantomData,
})
}
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()),
_ => {}
}
}
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()),
_ => {}
}
}
pub fn is_pending(&mut self, event: Event) -> bool {
(self.usart.isr.read().bits() & event.val()) != 0
}
pub fn unpend(&mut self, event: Event) {
let mask: u32 = 0x123BFF;
self.usart
.icr
.write(|w| unsafe { w.bits(event.val() & mask) });
}
}
impl Tx<$USARTX, FullConfig> {
pub fn fifo_threshold_reached(&self) -> bool {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.isr.read().txft().bit_is_set()
}
}
impl Rx<$USARTX, FullConfig> {
pub fn timeout_lapsed(&self) -> bool {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.isr.read().rtof().bit_is_set()
}
pub fn clear_timeout(&mut self) {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.icr.write(|w| w.rtocf().set_bit());
}
pub fn fifo_threshold_reached(&self) -> bool {
let usart = unsafe { &(*$USARTX::ptr()) };
usart.isr.read().rxft().bit_is_set()
}
}
};
}
uart_shared!(USART1, USART1_RX, USART1_TX,
tx: [
(PA9, AltFunction::AF1),
(PB6, AltFunction::AF0),
(PC4, AltFunction::AF1),
],
rx: [
(PA10, AltFunction::AF1),
(PB7, AltFunction::AF0),
(PC5, AltFunction::AF1),
]);
uart_shared!(USART2, USART2_RX, USART2_TX,
tx: [
(PA2, AltFunction::AF1),
(PA14, AltFunction::AF1),
(PD5, AltFunction::AF0),
],
rx: [
(PA3, AltFunction::AF1),
(PA15, AltFunction::AF1),
(PD6, AltFunction::AF0),
]
);
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
uart_shared!(USART3, USART3_RX, USART3_TX,
tx: [
(PA5, AltFunction::AF4),
(PB2, AltFunction::AF4),
(PB8, AltFunction::AF4),
(PB10, AltFunction::AF4),
(PC4, AltFunction::AF1),
(PC10, AltFunction::AF1),
(PD8, AltFunction::AF1),
],
rx: [
(PB0, AltFunction::AF4),
(PB9, AltFunction::AF4),
(PB11, AltFunction::AF4),
(PC5, AltFunction::AF1),
(PC11, AltFunction::AF1),
(PD9, AltFunction::AF1),
]
);
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
uart_shared!(USART4, USART4_RX, USART4_TX,
tx: [
(PA0, AltFunction::AF4),
(PC10, AltFunction::AF1),
],
rx: [
(PC11, AltFunction::AF1),
(PA1, AltFunction::AF4),
]
);
#[cfg(feature = "stm32g0x1")]
uart_shared!(LPUART, LPUART_RX, LPUART_TX,
tx: [
(PA2, AltFunction::AF6),
(PB11, AltFunction::AF1),
(PC1, AltFunction::AF1),
],
rx: [
(PA3, AltFunction::AF6),
(PB10, AltFunction::AF1),
(PC0, AltFunction::AF1),
]
);
uart_full!(USART1, usart1, apbenr2, usart1en, 1);
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
uart_full!(USART2, usart2, apbenr1, usart2en, 1);
#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041"))]
uart_basic!(USART2, usart2, apbenr1, usart2en, 1);
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
uart_basic!(USART3, usart3, apbenr1, usart3en, 1);
#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
uart_basic!(USART4, usart4, apbenr1, usart4en, 1);
#[cfg(feature = "stm32g0x1")]
uart_basic!(LPUART, lpuart, apbenr1, lpuart1en, 256);