use crate::ccm;
pub use crate::iomuxc::uart::{self, module};
use crate::pac;
use core::marker::PhantomData;
pub struct Uninit<M: module::Module> {
effective_clock: ccm::Frequency,
_module: PhantomData<M>,
reg: M::Reg,
}
impl<M: module::Module> Uninit<M> {
fn new(effective_clock: ccm::Frequency, reg: M::Reg) -> Self {
Uninit {
effective_clock,
_module: PhantomData,
reg,
}
}
}
pub struct UARTs {
pub uart1: Uninit<module::_1>,
pub uart2: Uninit<module::_2>,
pub uart3: Uninit<module::_3>,
pub uart4: Uninit<module::_4>,
pub uart5: Uninit<module::_5>,
pub uart6: Uninit<module::_6>,
pub uart7: Uninit<module::_7>,
pub uart8: Uninit<module::_8>,
}
#[allow(dead_code)]
pub struct Unclocked {
pub(crate) uart1: pac::LPUART1,
pub(crate) uart2: pac::LPUART2,
pub(crate) uart3: pac::LPUART3,
pub(crate) uart4: pac::LPUART4,
pub(crate) uart5: pac::LPUART5,
pub(crate) uart6: pac::LPUART6,
pub(crate) uart7: pac::LPUART7,
pub(crate) uart8: pac::LPUART8,
}
impl Unclocked {
pub fn clock(
self,
ccm: &mut ccm::Handle,
clock_select: ccm::uart::ClockSelect,
prescalar: ccm::uart::PrescalarSelect,
) -> UARTs {
let (ccm, _) = ccm.raw();
ccm.ccgr5.modify(|_, w| unsafe {
w.cg12()
.bits(0b00)
.cg13()
.bits(0b00)
});
ccm.ccgr0.modify(|_, w| unsafe {
w.cg14()
.bits(0b00)
.cg6()
.bits(0b00)
});
ccm.ccgr1.modify(|_, w| unsafe { w.cg12().bits(0b00) });
ccm.ccgr3.modify(|_, w| unsafe {
w.cg1()
.bits(0b00)
.cg3()
.bits(0b00)
});
ccm.ccgr6.modify(|_, w| unsafe { w.cg7().bits(0b00) });
ccm.cscdr1.write(|w| {
w.uart_clk_sel()
.variant(clock_select.into())
.uart_clk_podf()
.variant(prescalar)
});
ccm.ccgr5.modify(|_, w| unsafe {
w.cg12()
.bits(0b11)
.cg13()
.bits(0b11)
});
ccm.ccgr0.modify(|_, w| unsafe {
w.cg14()
.bits(0b11)
.cg6()
.bits(0b11)
});
ccm.ccgr1.modify(|_, w| unsafe { w.cg12().bits(0b11) });
ccm.ccgr3.modify(|_, w| unsafe {
w.cg1()
.bits(0b11)
.cg3()
.bits(0b11)
});
ccm.ccgr6.modify(|_, w| unsafe { w.cg7().bits(0b11) });
let effective_clock = ccm::Frequency::from(clock_select) / ccm::Divider::from(prescalar);
UARTs {
uart1: Uninit::new(effective_clock, self.uart1),
uart2: Uninit::new(effective_clock, self.uart2),
uart3: Uninit::new(effective_clock, self.uart3),
uart4: Uninit::new(effective_clock, self.uart4),
uart5: Uninit::new(effective_clock, self.uart5),
uart6: Uninit::new(effective_clock, self.uart6),
uart7: Uninit::new(effective_clock, self.uart7),
uart8: Uninit::new(effective_clock, self.uart8),
}
}
}
impl<M> Uninit<M>
where
M: module::Module,
{
pub fn init<TX, RX>(
self,
mut tx: TX,
mut rx: RX,
baud: u32,
) -> Result<UART<M>, ccm::uart::TimingsError>
where
TX: uart::Pin<Direction = uart::TX, Module = M>,
RX: uart::Pin<Direction = uart::RX, Module = M>,
{
tx.configure();
rx.configure();
UART::start(self.reg, self.effective_clock, baud)
}
}
pub struct UART<M: module::Module> {
reg: M::Reg,
effective_clock: ccm::Frequency,
_module: PhantomData<M>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Parity {
Even,
Odd,
}
impl Parity {
fn bit(self) -> bool {
self == Parity::Odd
}
}
impl<M> UART<M>
where
M: module::Module,
{
fn start(
reg: M::Reg,
effective_clock: ccm::Frequency,
baud: u32,
) -> Result<Self, ccm::uart::TimingsError> {
let mut uart = UART {
reg,
effective_clock,
_module: PhantomData,
};
uart.set_baud(baud)?;
let reg: &M::Reg = &uart.reg;
reg.ctrl.modify(|_, w| w.te().set_bit().re().set_bit());
Ok(uart)
}
pub fn set_parity(&mut self, parity: Option<Parity>) {
self.while_disabled(|this| {
this.reg.ctrl.modify(|_, w| {
w.pe()
.bit(parity.is_some())
.m()
.bit(parity.is_some())
.pt()
.bit(parity.map(|p| p.bit()).unwrap_or(false))
});
});
}
pub fn set_rx_inversion(&mut self, inverted: bool) {
self.while_disabled(|this| {
this.reg.stat.modify(|_, w| w.rxinv().bit(inverted));
});
}
pub fn set_tx_inversion(&mut self, inverted: bool) {
self.while_disabled(|this| {
this.reg.ctrl.modify(|_, w| w.txinv().bit(inverted));
});
}
pub fn set_tx_fifo(&mut self, size: Option<core::num::NonZeroU8>) -> u8 {
self.while_disabled(|this| {
if let Some(requested_size) = size {
let max_size = 1 << this.reg.param.read().txfifo().bits();
let tx_fifo_size = max_size.min(requested_size.get());
this.reg.water.modify(|_, w| unsafe {
w.txwater().bits(tx_fifo_size - 1)
});
this.reg.fifo.modify(|_, w| w.txfe().set_bit());
tx_fifo_size
} else {
this.reg.fifo.modify(|_, w| w.txfe().clear_bit());
0
}
})
}
pub fn set_rx_fifo(&mut self, enable: bool) {
self.while_disabled(|this| {
this.reg.fifo.modify(|_, w| w.rxfe().bit(enable));
})
}
fn while_disabled<F: FnMut(&mut Self) -> R, R>(&mut self, mut act: F) -> R {
let mut was_enabled = false;
self.reg
.fifo
.modify(|_, w| w.txflush().set_bit().rxflush().set_bit());
self.reg.ctrl.modify(|r, w| {
was_enabled = r.te().bit_is_set() && r.re().bit_is_set();
w.te().clear_bit().re().clear_bit()
});
let res = act(self);
self.reg
.ctrl
.modify(|_, w| w.te().bit(was_enabled).re().bit(was_enabled));
res
}
pub fn set_baud(&mut self, baud: u32) -> Result<(), ccm::uart::TimingsError> {
let timings = ccm::uart::timings(self.effective_clock, baud)?;
self.while_disabled(|this| {
this.reg.baud.modify(|_, w| unsafe {
w.osr()
.bits(timings.osr)
.sbr()
.bits(timings.sbr)
.bothedge()
.bit(timings.both_edge)
});
this.reg.ctrl.modify(|_, w| w.te().set_bit().re().set_bit());
});
Ok(())
}
fn clear_status(&mut self) {
self.reg.stat.modify(|_, w| {
w.idle()
.set_bit()
.or()
.set_bit()
.nf()
.set_bit()
.fe()
.set_bit()
.pf()
.set_bit()
});
}
pub fn set_receiver_interrupt(&mut self, watermark: Option<u8>) -> u8 {
self.while_disabled(|this| {
if let Some(watermark) = watermark {
let rx_fifo_size = if this.reg.fifo.read().rxfe().bit_is_set() && watermark > 0 {
let max_size = 1 << this.reg.param.read().rxfifo().bits();
let fifo_size = max_size.min(watermark);
this.reg.water.modify(|_, w| unsafe {
w.rxwater().bits(fifo_size)
});
fifo_size
} else {
0
};
this.reg.ctrl.modify(|_, w| w.rie().set_bit());
rx_fifo_size
} else {
this.reg.ctrl.modify(|_, w| w.rie().clear_bit());
0
}
})
}
}
use embedded_hal::serial;
impl<M> serial::Write<u8> for UART<M>
where
M: module::Module,
{
type Error = core::convert::Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.flush()?;
self.reg.data.write(|w| unsafe { w.bits(word as u32) });
Ok(())
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.reg.stat.read().tdre().is_tdre_0() {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
bitflags::bitflags! {
pub struct ReadErrorFlags : u8 {
const NOISY = 1 << 7;
const PARITY = 1 << 6;
const FRAME_ERROR = 1 << 5;
const OVERRUN = 1 << 4;
}
}
pub struct ReadError {
pub flags: ReadErrorFlags,
pub raw: u8,
}
impl<M> serial::Read<u8> for UART<M>
where
M: module::Module,
{
type Error = ReadError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let data = self.reg.data.read();
if data.rxempt().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
let mut flags = ReadErrorFlags::empty();
flags.set(ReadErrorFlags::OVERRUN, self.reg.stat.read().or().bit());
flags.set(ReadErrorFlags::PARITY, data.paritye().bit());
flags.set(ReadErrorFlags::FRAME_ERROR, data.fretsc().bit());
flags.set(ReadErrorFlags::NOISY, data.noisy().bit());
let raw = (data.bits() & 0xFF) as u8;
self.clear_status();
if flags.is_empty() {
Ok(raw)
} else {
Err(nb::Error::Other(ReadError { flags, raw }))
}
}
}
}