use crate::ccm;
use crate::iomuxc::consts::{Unsigned, U1, U2, U3, U4, U5, U6, U7, U8};
use crate::iomuxc::uart;
use crate::ral;
use core::marker::PhantomData;
pub struct Uninit<M: Unsigned> {
effective_clock: ccm::Frequency,
_module: PhantomData<M>,
reg: ral::lpuart::Instance,
}
impl<M: Unsigned> Uninit<M> {
fn new(effective_clock: ccm::Frequency, reg: ral::lpuart::Instance) -> Self {
Uninit {
effective_clock,
_module: PhantomData,
reg,
}
}
}
pub struct UARTs {
pub uart1: Uninit<U1>,
pub uart2: Uninit<U2>,
pub uart3: Uninit<U3>,
pub uart4: Uninit<U4>,
pub uart5: Uninit<U5>,
pub uart6: Uninit<U6>,
pub uart7: Uninit<U7>,
pub uart8: Uninit<U8>,
}
#[allow(dead_code)]
pub struct Unclocked {
pub(crate) uart1: ral::lpuart::Instance,
pub(crate) uart2: ral::lpuart::Instance,
pub(crate) uart3: ral::lpuart::Instance,
pub(crate) uart4: ral::lpuart::Instance,
pub(crate) uart5: ral::lpuart::Instance,
pub(crate) uart6: ral::lpuart::Instance,
pub(crate) uart7: ral::lpuart::Instance,
pub(crate) uart8: ral::lpuart::Instance,
}
impl Unclocked {
pub fn clock(
self,
ccm: &mut ccm::Handle,
clock_select: ccm::uart::ClockSelect,
prescalar: ccm::uart::PrescalarSelect,
) -> UARTs {
let (ccm, _) = ccm.raw();
ral::modify_reg!(
ral::ccm,
ccm,
CCGR5,
CG12: 0,
CG13: 0
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR0,
CG14: 0,
CG6: 0
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR1,
CG12: 0
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR3,
CG1: 0,
CG3: 0
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR6,
CG7: 0
);
ral::modify_reg!(
ral::ccm,
ccm,
CSCDR1,
UART_CLK_SEL: (clock_select as u32),
UART_CLK_PODF: (prescalar as u32)
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR5,
CG12: 0b11,
CG13: 0b11
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR0,
CG14: 0b11,
CG6: 0b11
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR1,
CG12: 0b11
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR3,
CG1: 0b11,
CG3: 0b11
);
ral::modify_reg!(
ral::ccm,
ccm,
CCGR6,
CG7: 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),
}
}
}
trait ModuleExtension {
unsafe fn steal() -> ral::lpuart::Instance;
}
impl<U> ModuleExtension for U
where
U: Unsigned,
{
unsafe fn steal() -> ral::lpuart::Instance {
match U::USIZE {
1 => ral::lpuart::LPUART1::steal(),
2 => ral::lpuart::LPUART2::steal(),
3 => ral::lpuart::LPUART3::steal(),
4 => ral::lpuart::LPUART4::steal(),
5 => ral::lpuart::LPUART5::steal(),
6 => ral::lpuart::LPUART6::steal(),
7 => ral::lpuart::LPUART7::steal(),
8 => ral::lpuart::LPUART8::steal(),
_ => unreachable!("there are only eight UART peripherals"),
}
}
}
impl<M> Uninit<M>
where
M: Unsigned,
{
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>,
{
crate::iomuxc::uart::prepare(&mut tx);
crate::iomuxc::uart::prepare(&mut rx);
UART::start(self.reg, self.effective_clock, baud)
}
}
pub struct UART<M: Unsigned> {
reg: ral::lpuart::Instance,
effective_clock: ccm::Frequency,
_module: PhantomData<M>,
}
pub struct Tx<M: Unsigned>(UART<M>);
pub struct Rx<M: Unsigned>(UART<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: Unsigned,
{
fn start(
reg: ral::lpuart::Instance,
effective_clock: ccm::Frequency,
baud: u32,
) -> Result<Self, ccm::uart::TimingsError> {
let mut uart = UART {
reg,
effective_clock,
_module: PhantomData,
};
uart.set_baud(baud)?;
ral::modify_reg!(ral::lpuart, uart.reg, CTRL, TE: TE_1, RE: RE_1);
Ok(uart)
}
pub fn split(self) -> (Tx<M>, Rx<M>) {
let rx_half = UART {
reg: unsafe { M::steal() },
effective_clock: self.effective_clock,
_module: self._module,
};
(Tx(self), Rx(rx_half))
}
pub fn join(tx: Tx<M>, _rx: Rx<M>) -> Self {
UART {
reg: tx.0.reg,
effective_clock: tx.0.effective_clock,
_module: tx.0._module,
}
}
pub fn set_parity(&mut self, parity: Option<Parity>) {
self.while_disabled(|this| {
ral::modify_reg!(
ral::lpuart,
this.reg,
CTRL,
PE: u32::from(parity.is_some()),
M: u32::from(parity.is_some()),
PT: u32::from(parity.map(|p| p.bit()).unwrap_or(false))
);
});
}
pub fn set_rx_inversion(&mut self, inverted: bool) {
self.while_disabled(|this| {
ral::modify_reg!(ral::lpuart, this.reg, STAT, RXINV: u32::from(inverted));
});
}
pub fn set_tx_inversion(&mut self, inverted: bool) {
self.while_disabled(|this| {
ral::modify_reg!(ral::lpuart, this.reg, CTRL, TXINV: u32::from(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 << ral::read_reg!(ral::lpuart, this.reg, PARAM, TXFIFO);
let tx_fifo_size = max_size.min(requested_size.get());
ral::modify_reg!(
ral::lpuart,
this.reg,
WATER,
TXWATER: (tx_fifo_size.saturating_sub(1) as u32)
);
ral::modify_reg!(ral::lpuart, this.reg, FIFO, TXFE: TXFE_1);
tx_fifo_size
} else {
ral::modify_reg!(ral::lpuart, this.reg, WATER, TXWATER: 0);
ral::modify_reg!(ral::lpuart, this.reg, FIFO, TXFE: TXFE_0);
0
}
})
}
pub fn set_rx_fifo(&mut self, enable: bool) {
self.while_disabled(|this| {
ral::modify_reg!(ral::lpuart, this.reg, FIFO, RXFE: u32::from(enable));
})
}
fn while_disabled<F: FnMut(&mut Self) -> R, R>(&mut self, mut act: F) -> R {
ral::modify_reg!(
ral::lpuart,
self.reg,
FIFO,
TXFLUSH: TXFLUSH_1,
RXFLUSH: RXFLUSH_1
);
let (te, re) = ral::read_reg!(ral::lpuart, self.reg, CTRL, TE, RE);
ral::modify_reg!(ral::lpuart, self.reg, CTRL, TE: TE_0, RE: RE_0);
let res = act(self);
ral::modify_reg!(ral::lpuart, self.reg, CTRL, TE: te, RE: re);
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| {
ral::modify_reg!(
ral::lpuart,
this.reg,
BAUD,
OSR: u32::from(timings.osr),
SBR: u32::from(timings.sbr),
BOTHEDGE: u32::from(timings.both_edge)
);
});
Ok(())
}
fn clear_status(&mut self) {
ral::modify_reg!(
ral::lpuart,
self.reg,
STAT,
IDLE: IDLE_1,
OR: OR_1,
NF: NF_1,
FE: FE_1,
PF: PF_1
);
}
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 ral::read_reg!(ral::lpuart, this.reg, FIFO, RXFE == RXFE_1)
&& watermark > 0
{
let max_size = 1 << ral::read_reg!(ral::lpuart, this.reg, PARAM, RXFIFO);
let fifo_size = max_size.min(watermark);
ral::modify_reg!(ral::lpuart, this.reg, WATER, RXWATER: fifo_size as u32);
fifo_size
} else {
0
};
ral::modify_reg!(ral::lpuart, this.reg, CTRL, RIE: RIE_1);
rx_fifo_size
} else {
ral::modify_reg!(ral::lpuart, this.reg, WATER, RXWATER: 0);
ral::modify_reg!(ral::lpuart, this.reg, CTRL, RIE: RIE_0);
0
}
})
}
}
use embedded_hal::serial;
impl<M> serial::Write<u8> for UART<M>
where
M: Unsigned,
{
type Error = core::convert::Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.flush()?;
ral::write_reg!(ral::lpuart, self.reg, DATA, word as u32);
Ok(())
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if ral::read_reg!(ral::lpuart, self.reg, STAT, TDRE == TDRE_0) {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
impl<M> serial::Write<u8> for Tx<M>
where
M: Unsigned,
{
type Error = core::convert::Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.0.write(word)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.0.flush()
}
}
bitflags::bitflags! {
pub struct ReadErrorFlags : u8 {
const NOISY = 1 << 7;
const PARITY = 1 << 6;
const FRAME_ERROR = 1 << 5;
const OVERRUN = 1 << 4;
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReadError {
pub flags: ReadErrorFlags,
pub raw: u8,
}
impl<M> serial::Read<u8> for UART<M>
where
M: Unsigned,
{
type Error = ReadError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
use ral::lpuart::DATA::*;
let data = ral::read_reg!(ral::lpuart, self.reg, DATA);
if data & RXEMPT::mask != 0 {
Err(nb::Error::WouldBlock)
} else {
let mut flags = ReadErrorFlags::empty();
flags.set(
ReadErrorFlags::OVERRUN,
ral::read_reg!(ral::lpuart, self.reg, STAT, OR == OR_1),
);
flags.set(ReadErrorFlags::PARITY, data & PARITYE::mask != 0);
flags.set(ReadErrorFlags::FRAME_ERROR, data & FRETSC::mask != 0);
flags.set(ReadErrorFlags::NOISY, data & NOISY::mask != 0);
let raw = (data & 0xFF) as u8;
self.clear_status();
if flags.is_empty() {
Ok(raw)
} else {
Err(nb::Error::Other(ReadError { flags, raw }))
}
}
}
}
impl<M> serial::Read<u8> for Rx<M>
where
M: Unsigned,
{
type Error = ReadError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.0.read()
}
}
use crate::dma;
const DMA_TX_REQUEST_LOOKUP: [u32; 8] = [2, 66, 4, 68, 6, 70, 8, 72];
const DMA_RX_REQUEST_LOOKUP: [u32; 8] = [3, 67, 5, 69, 7, 71, 9, 73];
impl<M> dma::peripheral::Source<u8> for UART<M>
where
M: Unsigned,
{
type Error = void::Void;
const SOURCE_REQUEST_SIGNAL: u32 = DMA_RX_REQUEST_LOOKUP[M::USIZE - 1];
fn source(&self) -> *const u8 {
&self.reg.DATA as *const _ as *const u8
}
fn enable_source(&mut self) -> Result<(), Self::Error> {
self.clear_status();
ral::modify_reg!(ral::lpuart, self.reg, BAUD, RDMAE: 1);
Ok(())
}
fn disable_source(&mut self) {
while ral::read_reg!(ral::lpuart, self.reg, BAUD, RDMAE == 1) {
ral::modify_reg!(ral::lpuart, self.reg, BAUD, RDMAE: 0);
}
}
}
impl<M> dma::peripheral::Source<u8> for Rx<M>
where
M: Unsigned,
{
type Error = void::Void;
const SOURCE_REQUEST_SIGNAL: u32 = DMA_RX_REQUEST_LOOKUP[M::USIZE - 1];
fn source(&self) -> *const u8 {
self.0.source()
}
fn enable_source(&mut self) -> Result<(), Self::Error> {
self.0.enable_source()
}
fn disable_source(&mut self) {
self.0.disable_source()
}
}
impl<M> dma::peripheral::Destination<u8> for UART<M>
where
M: Unsigned,
{
type Error = void::Void;
const DESTINATION_REQUEST_SIGNAL: u32 = DMA_TX_REQUEST_LOOKUP[M::USIZE - 1];
fn destination(&self) -> *const u8 {
&self.reg.DATA as *const _ as *const u8
}
fn enable_destination(&mut self) -> Result<(), Self::Error> {
ral::modify_reg!(ral::lpuart, self.reg, BAUD, TDMAE: 1);
Ok(())
}
fn disable_destination(&mut self) {
while ral::read_reg!(ral::lpuart, self.reg, BAUD, TDMAE == 1) {
ral::modify_reg!(ral::lpuart, self.reg, BAUD, TDMAE: 0);
}
}
}
impl<M> dma::peripheral::Destination<u8> for Tx<M>
where
M: Unsigned,
{
type Error = void::Void;
const DESTINATION_REQUEST_SIGNAL: u32 = DMA_TX_REQUEST_LOOKUP[M::USIZE - 1];
fn destination(&self) -> *const u8 {
self.0.destination()
}
fn enable_destination(&mut self) -> Result<(), Self::Error> {
self.0.enable_destination()
}
fn disable_destination(&mut self) {
self.0.disable_destination()
}
}
use embedded_hal::blocking::serial::write::Default as BlockingWrite;
impl<M> BlockingWrite<u8> for UART<M> where M: Unsigned {}
impl<M> BlockingWrite<u8> for Tx<M> where M: Unsigned {}