#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs)]
use core::convert::Infallible;
use registers::Control;
pub mod registers;
pub mod tx;
pub use tx::*;
pub mod rx;
pub use rx::*;
pub mod tx_async;
pub use tx_async::*;
pub const FIFO_DEPTH: usize = 16;
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub struct RxErrorsCounted {
parity: u8,
frame: u8,
overrun: u8,
}
impl RxErrorsCounted {
pub const fn new() -> Self {
Self {
parity: 0,
frame: 0,
overrun: 0,
}
}
pub const fn parity(&self) -> u8 {
self.parity
}
pub const fn frame(&self) -> u8 {
self.frame
}
pub const fn overrun(&self) -> u8 {
self.overrun
}
pub fn has_errors(&self) -> bool {
self.parity > 0 || self.frame > 0 || self.overrun > 0
}
}
pub struct AxiUartlite {
rx: Rx,
tx: Tx,
errors: RxErrorsCounted,
}
impl AxiUartlite {
pub const unsafe fn new(base_addr: u32) -> Self {
let regs = unsafe { registers::Registers::new_mmio_at(base_addr as usize) };
Self {
rx: Rx {
regs: unsafe { regs.clone() },
errors: None,
},
tx: Tx { regs, errors: None },
errors: RxErrorsCounted::new(),
}
}
#[inline(always)]
pub const fn regs(&mut self) -> &mut registers::MmioRegisters<'static> {
&mut self.tx.regs
}
#[inline]
pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
self.tx.write_fifo(data).unwrap();
if let Some(errors) = self.tx.errors {
self.handle_status_reg_errors(errors);
}
Ok(())
}
#[inline(always)]
pub fn write_fifo_unchecked(&mut self, data: u8) {
self.tx.write_fifo_unchecked(data);
}
#[inline]
pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
let val = self.rx.read_fifo()?;
if let Some(errors) = self.rx.errors {
self.handle_status_reg_errors(errors);
}
Ok(val)
}
#[inline(always)]
pub fn read_fifo_unchecked(&mut self) -> u8 {
self.rx.read_fifo_unchecked()
}
#[inline(always)]
pub fn tx_fifo_empty(&self) -> bool {
self.tx.fifo_empty()
}
#[inline(always)]
pub fn tx_fifo_full(&self) -> bool {
self.tx.fifo_full()
}
#[inline(always)]
pub fn rx_has_data(&self) -> bool {
self.rx.has_data()
}
pub fn read_and_clear_errors(&mut self) -> RxErrorsCounted {
let errors = self.errors;
self.errors = RxErrorsCounted::new();
errors
}
#[inline(always)]
fn handle_status_reg_errors(&mut self, errors: RxErrors) {
if errors.frame() {
self.errors.frame = self.errors.frame.saturating_add(1);
}
if errors.parity() {
self.errors.parity = self.errors.parity.saturating_add(1);
}
if errors.overrun() {
self.errors.overrun = self.errors.overrun.saturating_add(1);
}
}
#[inline]
pub fn reset_rx_fifo(&mut self) {
self.regs().write_ctrl_reg(
Control::builder()
.with_enable_interrupt(false)
.with_reset_rx_fifo(true)
.with_reset_tx_fifo(false)
.build(),
);
}
#[inline]
pub fn reset_tx_fifo(&mut self) {
self.regs().write_ctrl_reg(
Control::builder()
.with_enable_interrupt(false)
.with_reset_rx_fifo(false)
.with_reset_tx_fifo(true)
.build(),
);
}
#[inline]
pub fn split(self) -> (Tx, Rx) {
(self.tx, self.rx)
}
#[inline]
pub fn enable_interrupt(&mut self) {
self.regs().write_ctrl_reg(
Control::builder()
.with_enable_interrupt(true)
.with_reset_rx_fifo(false)
.with_reset_tx_fifo(false)
.build(),
);
}
#[inline]
pub fn disable_interrupt(&mut self) {
self.regs().write_ctrl_reg(
Control::builder()
.with_enable_interrupt(false)
.with_reset_rx_fifo(false)
.with_reset_tx_fifo(false)
.build(),
);
}
}
impl embedded_hal_nb::serial::ErrorType for AxiUartlite {
type Error = Infallible;
}
impl embedded_hal_nb::serial::Write for AxiUartlite {
#[inline]
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.tx.write(word)
}
#[inline]
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.tx.flush()
}
}
impl embedded_hal_nb::serial::Read for AxiUartlite {
#[inline]
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.rx.read()
}
}
impl embedded_io::ErrorType for AxiUartlite {
type Error = Infallible;
}
impl embedded_io::Read for AxiUartlite {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.read(buf)
}
}
impl embedded_io::Write for AxiUartlite {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.tx.flush()
}
}