use embedded_time::rate::{Extensions, Baud};
use crate::pac;
use crate::clock::Clocks;
#[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)]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum StopBits {
STOP1,
STOP0P5,
STOP2,
STOP1P5,
}
#[derive(Copy, Clone, Debug, PartialEq)]
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 uart_clk = clocks.uart_clk();
let baud = config.baudrate.0;
let divisor = {
let ans = uart_clk.0 / baud;
if !(ans >= 1 && ans <= 65535) {
panic!("impossible baudrate");
}
ans as u16
};
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)
.cr_utx_prt_sel().bit(parity_type)
.cr_utx_bit_cnt_d().bits(data_bits_cfg)
.cr_utx_bit_cnt_p().bits(stop_bits_cfg)
.cr_utx_frm_en().set_bit()
.cr_utx_cts_en().bit(PINS::HAS_CTS)
.cr_utx_en().bit(PINS::HAS_TX)
});
uart.urx_config.write(|w| unsafe { w
.cr_urx_prt_en().bit(parity_enable)
.cr_urx_prt_sel().bit(parity_type)
.cr_urx_bit_cnt_d().bits(data_bits_cfg)
.cr_urx_deg_en().clear_bit()
.cr_urx_rts_sw_mode().clear_bit()
.cr_urx_en().bit(PINS::HAS_RX)
});
Serial { uart, pins }
}
pub fn free(self) -> (pac::UART, PINS) {
(self.uart, self.pins)
}
}
impl<PINS> embedded_hal::serial::Write<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn try_write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.uart.uart_fifo_wdata.write(|w| unsafe {
w.bits(word as u32)
});
Ok(())
}
fn try_flush(&mut self) -> nb::Result<(), Self::Error> {
if self.uart.uart_fifo_config_1.read().tx_fifo_cnt().bits() < 1 {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
impl<PINS> embedded_hal::serial::Read<u8> for Serial<pac::UART, PINS> {
type Error = Error;
fn try_read(&mut self) -> nb::Result<u8, Self::Error> {
let ans = self.uart.uart_fifo_rdata.read().bits();
Ok((ans & 0xff) as u8)
}
}
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;
}