use crate::clock::Clocks;
use crate::pac;
use core::fmt;
use embedded_hal::serial::nb::Read as ReadOne;
use embedded_hal::serial::nb::Write as WriteOne;
use embedded_time::rate::{Baud, Extensions};
use nb::block;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Config {
pub baudrate: Baud,
pub order: Order,
pub parity: Parity,
pub stopbits: StopBits,
pub wordlength: WordLength,
}
impl Config {
pub fn baudrate(mut self, baudrate: impl Into<Baud>) -> Self {
self.baudrate = baudrate.into();
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
}
}
impl Default for Config {
fn default() -> Config {
Config {
baudrate: 115_200_u32.Bd(),
order: Order::LsbFirst,
parity: Parity::ParityNone,
stopbits: StopBits::STOP1,
wordlength: WordLength::Eight,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Order {
LsbFirst,
MsbFirst,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum StopBits {
STOP1,
STOP0P5,
STOP2,
STOP1P5,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum WordLength {
Five,
Six,
Seven,
Eight,
}
pub enum Event {
RxFifoError,
TxFifoError,
RxParityError,
RxTimeout,
RxFifoReady,
TxFifoReady,
RxTransferEnd,
TxTransferEnd,
}
pub struct Serial<UART, PINS> {
uart: UART,
pins: PINS,
}
impl<PINS> Serial<pac::UART, PINS>
where
PINS: Pins<pac::UART>,
{
pub fn uart0(uart: pac::UART, config: Config, pins: PINS, _clocks: Clocks) -> Self {
let divisor = 48;
uart.utx_config.modify(|_, w| w.cr_utx_en().clear_bit());
uart.urx_config.modify(|_, w| w.cr_urx_en().clear_bit());
uart.uart_bit_prd.write(|w| unsafe {
w.cr_urx_bit_prd()
.bits(divisor - 1)
.cr_utx_bit_prd()
.bits(divisor - 1)
});
let order_cfg = match config.order {
Order::LsbFirst => false,
Order::MsbFirst => true,
};
uart.data_config
.write(|w| w.cr_uart_bit_inv().bit(order_cfg));
let data_bits_cfg = match config.wordlength {
WordLength::Five => 4,
WordLength::Six => 5,
WordLength::Seven => 6,
WordLength::Eight => 7,
};
let stop_bits_cfg = match config.stopbits {
StopBits::STOP0P5 => 0,
StopBits::STOP1 => 1,
StopBits::STOP1P5 => 2,
StopBits::STOP2 => 3,
};
let (parity_enable, parity_type) = match config.parity {
Parity::ParityNone => (false, false),
Parity::ParityEven => (true, false), Parity::ParityOdd => (true, true), };
uart.utx_config.write(|w| unsafe {
w.cr_utx_prt_en().bit(parity_enable);
w.cr_utx_prt_sel().bit(parity_type);
w.cr_utx_bit_cnt_d().bits(data_bits_cfg);
w.cr_utx_bit_cnt_p().bits(stop_bits_cfg);
w.cr_utx_frm_en().set_bit(); w.cr_utx_cts_en().bit(false); w
});
uart.utx_config
.modify(|_, w| w.cr_utx_en().bit(PINS::HAS_TX));
uart.urx_config.write(|w| unsafe {
w.cr_urx_prt_en().bit(parity_enable);
w.cr_urx_prt_sel().bit(parity_type);
w.cr_urx_bit_cnt_d().bits(data_bits_cfg);
w.cr_urx_deg_en().clear_bit();
w.cr_urx_en().bit(PINS::HAS_RX);
w
});
uart.urx_config
.modify(|_, w| unsafe { w.cr_urx_deg_cnt().bits(15) });
Serial { uart, pins }
}
pub fn free(self) -> (pac::UART, PINS) {
(self.uart, self.pins)
}
}
impl<PINS> embedded_hal::serial::nb::Write<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.uart.uart_fifo_config_1.read().tx_fifo_cnt().bits() == 0 {
Err(nb::Error::WouldBlock)
} else {
self.uart
.uart_fifo_wdata
.write(|w| unsafe { w.bits(word as u32) });
Ok(())
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.uart.uart_fifo_config_1.read().tx_fifo_cnt().bits() != 32
|| self.uart.uart_status.read().sts_utx_bus_busy().bit_is_set()
{
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
impl<PINS> embedded_hal::serial::nb::Read<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if self.uart.uart_fifo_config_1.read().rx_fifo_cnt().bits() == 0 {
Err(nb::Error::WouldBlock)
} else {
let ans = self.uart.uart_fifo_rdata.read().bits();
Ok((ans & 0xff) as u8)
}
}
}
impl<PINS> embedded_hal_zero::serial::Write<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
WriteOne::write(self, word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
WriteOne::flush(self)
}
}
impl<PINS> embedded_hal_zero::serial::Read<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
ReadOne::read(self)
}
}
impl<UART, PINS> fmt::Write for Serial<UART, PINS>
where
Serial<UART, PINS>: embedded_hal::serial::nb::Write<u8>,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
s.as_bytes()
.iter()
.try_for_each(|c| block!(self.write(*c)))
.map_err(|_| fmt::Error)
}
}
pub unsafe trait TxPin<UART> {}
pub unsafe trait RxPin<UART> {}
pub unsafe trait RtsPin<UART> {}
pub unsafe trait CtsPin<UART> {}
macro_rules! impl_uart_pin {
($(($UartSigi: ident, $UartMuxi: ident),)+) => {
use crate::gpio::*;
$(
unsafe impl<PIN: UartPin<$UartSigi>> TxPin<pac::UART> for (PIN, $UartMuxi<Uart0Tx>) {}
unsafe impl<PIN: UartPin<$UartSigi>> RxPin<pac::UART> for (PIN, $UartMuxi<Uart0Rx>) {}
unsafe impl<PIN: UartPin<$UartSigi>> RtsPin<pac::UART> for (PIN, $UartMuxi<Uart0Rts>) {}
unsafe impl<PIN: UartPin<$UartSigi>> CtsPin<pac::UART> for (PIN, $UartMuxi<Uart0Cts>) {}
)+
};
}
impl_uart_pin!(
(UartSig0, UartMux0),
(UartSig1, UartMux1),
(UartSig2, UartMux2),
(UartSig3, UartMux3),
(UartSig4, UartMux4),
(UartSig5, UartMux5),
(UartSig6, UartMux6),
(UartSig7, UartMux7),
);
pub unsafe trait Pins<UART> {
const HAS_TX: bool;
const HAS_RX: bool;
const HAS_RTS: bool;
const HAS_CTS: bool;
}
unsafe impl<UART, TX, RX> Pins<UART> for (TX, RX)
where
TX: TxPin<UART>,
RX: RxPin<UART>,
{
const HAS_TX: bool = true;
const HAS_RX: bool = true;
const HAS_RTS: bool = false;
const HAS_CTS: bool = false;
}
unsafe impl<UART, TX, RX, RTS, CTS> Pins<UART> for (TX, RX, RTS, CTS)
where
TX: TxPin<UART>,
RX: RxPin<UART>,
RTS: RxPin<UART>,
CTS: RxPin<UART>,
{
const HAS_TX: bool = true;
const HAS_RX: bool = true;
const HAS_RTS: bool = true;
const HAS_CTS: bool = true;
}