use core::marker::PhantomData;
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin;
use crate::{pac, peripherals, Peripheral};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum DataBits {
DataBits5,
DataBits6,
DataBits7,
DataBits8,
}
impl DataBits {
fn bits(&self) -> u8 {
match self {
Self::DataBits5 => 0b00,
Self::DataBits6 => 0b01,
Self::DataBits7 => 0b10,
Self::DataBits8 => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
#[doc = "2 stop bits"]
STOP2,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
pub baudrate: u32,
pub data_bits: DataBits,
pub stop_bits: StopBits,
pub parity: Parity,
}
impl Default for Config {
fn default() -> Self {
Self {
baudrate: 115200,
data_bits: DataBits::DataBits8,
stop_bits: StopBits::STOP1,
parity: Parity::ParityNone,
}
}
}
/// Serial error
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
/// Triggered when the FIFO (or shift-register) is overflowed.
Overrun,
/// Triggered when a break is received
Break,
/// Triggered when there is a parity mismatch between what's received and
/// our settings.
Parity,
/// Triggered when the received character didn't have a valid stop bit.
Framing,
}
pub struct Uart<'d, T: Instance> {
tx: UartTx<'d, T>,
rx: UartRx<'d, T>,
}
pub struct UartTx<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
}
pub struct UartRx<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: Instance> UartTx<'d, T> {
fn new() -> Self {
Self { phantom: PhantomData }
}
pub async fn write(&mut self, _buffer: &[u8]) -> Result<(), Error> {
todo!()
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
unsafe {
for &b in buffer {
while r.uartfr().read().txff() {}
r.uartdr().write(|w| w.set_data(b));
}
}
Ok(())
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs();
unsafe { while r.uartfr().read().txff() {} }
Ok(())
}
}
impl<'d, T: Instance> UartRx<'d, T> {
fn new() -> Self {
Self { phantom: PhantomData }
}
pub async fn read(&mut self, _buffer: &mut [u8]) -> Result<(), Error> {
todo!();
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs();
unsafe {
for b in buffer {
*b = loop {
let dr = r.uartdr().read();
if dr.oe() {
return Err(Error::Overrun);
} else if dr.be() {
return Err(Error::Break);
} else if dr.pe() {
return Err(Error::Parity);
} else if dr.fe() {
return Err(Error::Framing);
} else if dr.fe() {
break dr.data();
}
};
}
}
Ok(())
}
}
impl<'d, T: Instance> Uart<'d, T> {
/// Create a new UART without hardware flow control
pub fn new(
uart: impl Peripheral
+ 'd,
tx: impl Peripheral
> + 'd,
rx: impl Peripheral
> + 'd,
config: Config,
) -> Self {
into_ref!(tx, rx);
Self::new_inner(uart, rx.map_into(), tx.map_into(), None, None, config)
}
/// Create a new UART with hardware flow control (RTS/CTS)
pub fn new_with_rtscts(
uart: impl Peripheral
+ 'd,
tx: impl Peripheral
> + 'd,
rx: impl Peripheral
> + 'd,
cts: impl Peripheral
> + 'd,
rts: impl Peripheral
> + 'd,
config: Config,
) -> Self {
into_ref!(tx, rx, cts, rts);
Self::new_inner(
uart,
rx.map_into(),
tx.map_into(),
Some(cts.map_into()),
Some(rts.map_into()),
config,
)
}
fn new_inner(
_uart: impl Peripheral
+ 'd,
tx: PeripheralRef<'d, AnyPin>,
rx: PeripheralRef<'d, AnyPin>,
cts: Option>,
rts: Option>,
config: Config,
) -> Self {
into_ref!(_uart);
unsafe {
let r = T::regs();
let clk_base = crate::clocks::clk_peri_freq();
let baud_rate_div = (8 * clk_base) / config.baudrate;
let mut baud_ibrd = baud_rate_div >> 7;
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
if baud_ibrd == 0 {
baud_ibrd = 1;
baud_fbrd = 0;
} else if baud_ibrd >= 65535 {
baud_ibrd = 65535;
baud_fbrd = 0;
}
// Load PL011's baud divisor registers
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
let (pen, eps) = match config.parity {
Parity::ParityNone => (false, false),
Parity::ParityEven => (true, true),
Parity::ParityOdd => (true, false),
};
r.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits.bits());
w.set_stp2(config.stop_bits == StopBits::STOP2);
w.set_pen(pen);
w.set_eps(eps);
w.set_fen(true);
});
r.uartcr().write(|w| {
w.set_uarten(true);
w.set_rxe(true);
w.set_txe(true);
w.set_ctsen(cts.is_some());
w.set_rtsen(rts.is_some());
});
tx.io().ctrl().write(|w| w.set_funcsel(2));
rx.io().ctrl().write(|w| w.set_funcsel(2));
if let Some(pin) = &cts {
pin.io().ctrl().write(|w| w.set_funcsel(2));
}
if let Some(pin) = &rts {
pin.io().ctrl().write(|w| w.set_funcsel(2));
}
}
Self {
tx: UartTx::new(),
rx: UartRx::new(),
}
}
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.write(buffer).await
}
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
}
pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush()
}
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.read(buffer).await
}
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer)
}
/// Split the Uart into a transmitter and receiver, which is
/// particuarly useful when having two tasks correlating to
/// transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) {
(self.tx, self.rx)
}
}
mod eh02 {
use super::*;
impl<'d, T: Instance> embedded_hal_02::serial::Read for UartRx<'d, T> {
type Error = Error;
fn read(&mut self) -> Result> {
let r = T::regs();
unsafe {
let dr = r.uartdr().read();
if dr.oe() {
Err(nb::Error::Other(Error::Overrun))
} else if dr.be() {
Err(nb::Error::Other(Error::Break))
} else if dr.pe() {
Err(nb::Error::Other(Error::Parity))
} else if dr.fe() {
Err(nb::Error::Other(Error::Framing))
} else if dr.fe() {
Ok(dr.data())
} else {
Err(nb::Error::WouldBlock)
}
}
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for UartTx<'d, T> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
impl<'d, T: Instance> embedded_hal_02::serial::Read for Uart<'d, T> {
type Error = Error;
fn read(&mut self) -> Result> {
embedded_hal_02::serial::Read::read(&mut self.rx)
}
}
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for Uart<'d, T> {
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(buffer)
}
fn bflush(&mut self) -> Result<(), Self::Error> {
self.blocking_flush()
}
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl embedded_hal_1::serial::Error for Error {
fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
match *self {
Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat,
Self::Break => embedded_hal_1::serial::ErrorKind::Other,
Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun,
Self::Parity => embedded_hal_1::serial::ErrorKind::Parity,
}
}
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uart<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartTx<'d, T> {
type Error = Error;
}
impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UartRx<'d, T> {
type Error = Error;
}
}
cfg_if::cfg_if! {
if #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "_todo_embedded_hal_serial"))] {
use core::future::Future;
impl<'d, T: Instance> embedded_hal_async::serial::Write for UartTx<'d, T>
{
type WriteFuture<'a> = impl Future