axi_uartlite/
lib.rs

1//! # AXI UART Lite v2.0 driver
2//!
3//! This is a native Rust driver for the AMD AXI UART Lite v2.0 IP core.
4//!
5//! # Features
6//!
7//! If asynchronous TX operations are used, the number of wakers  which defaults to 1 waker can
8//! also be configured. The [tx_async] module provides more details on the meaning of this number.
9//!
10//! - `1-waker` which is also a `default` feature
11//! - `2-wakers`
12//! - `4-wakers`
13//! - `8-wakers`
14//! - `16-wakers`
15//! - `32-wakers`
16#![no_std]
17#![cfg_attr(docsrs, feature(doc_cfg))]
18#![deny(missing_docs)]
19
20use core::convert::Infallible;
21use registers::Control;
22pub mod registers;
23
24pub mod tx;
25pub use tx::*;
26
27pub mod rx;
28pub use rx::*;
29
30pub mod tx_async;
31pub use tx_async::*;
32
33/// Maximum FIFO depth of the AXI UART Lite.
34pub const FIFO_DEPTH: usize = 16;
35
36/// RX error structure.
37#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
38pub struct RxErrorsCounted {
39    parity: u8,
40    frame: u8,
41    overrun: u8,
42}
43
44impl RxErrorsCounted {
45    /// Create a new empty RX error counter.
46    pub const fn new() -> Self {
47        Self {
48            parity: 0,
49            frame: 0,
50            overrun: 0,
51        }
52    }
53
54    /// Parity error count.
55    pub const fn parity(&self) -> u8 {
56        self.parity
57    }
58
59    /// Frame error count.
60    pub const fn frame(&self) -> u8 {
61        self.frame
62    }
63
64    /// Overrun error count.
65    pub const fn overrun(&self) -> u8 {
66        self.overrun
67    }
68
69    /// Some error has occurred.
70    pub fn has_errors(&self) -> bool {
71        self.parity > 0 || self.frame > 0 || self.overrun > 0
72    }
73}
74
75/// AXI UART Lite peripheral driver.
76pub struct AxiUartlite {
77    rx: Rx,
78    tx: Tx,
79    errors: RxErrorsCounted,
80}
81
82impl AxiUartlite {
83    /// Create a new AXI UART Lite peripheral driver.
84    ///
85    /// # Safety
86    ///
87    /// - The `base_addr` must be a valid memory-mapped register address of an AXI UART Lite peripheral.
88    /// - Dereferencing an invalid or misaligned address results in **undefined behavior**.
89    /// - The caller must ensure that no other code concurrently modifies the same peripheral registers
90    ///   in an unsynchronized manner to prevent data races.
91    /// - This function does not enforce uniqueness of driver instances. Creating multiple instances
92    ///   with the same `base_addr` can lead to unintended behavior if not externally synchronized.
93    /// - The driver performs **volatile** reads and writes to the provided address.
94    pub const unsafe fn new(base_addr: u32) -> Self {
95        let regs = unsafe { registers::Registers::new_mmio_at(base_addr as usize) };
96        Self {
97            rx: Rx {
98                regs: unsafe { regs.clone() },
99                errors: None,
100            },
101            tx: Tx { regs, errors: None },
102            errors: RxErrorsCounted::new(),
103        }
104    }
105
106    /// Direct register access.
107    #[inline(always)]
108    pub const fn regs(&mut self) -> &mut registers::MmioRegisters<'static> {
109        &mut self.tx.regs
110    }
111
112    /// Write into the UART Lite.
113    ///
114    /// Returns [nb::Error::WouldBlock] if the TX FIFO is full.
115    #[inline]
116    pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
117        self.tx.write_fifo(data).unwrap();
118        if let Some(errors) = self.tx.errors {
119            self.handle_status_reg_errors(errors);
120        }
121        Ok(())
122    }
123
124    /// Write into the FIFO without checking the FIFO fill status.
125    ///
126    /// This can be useful to completely fill the FIFO if it is known to be empty.
127    #[inline(always)]
128    pub fn write_fifo_unchecked(&mut self, data: u8) {
129        self.tx.write_fifo_unchecked(data);
130    }
131
132    /// Read from the UART Lite.
133    ///
134    /// Offers a
135    #[inline]
136    pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
137        let val = self.rx.read_fifo()?;
138        if let Some(errors) = self.rx.errors {
139            self.handle_status_reg_errors(errors);
140        }
141        Ok(val)
142    }
143
144    /// Read from the FIFO without checking the FIFO fill status.
145    #[inline(always)]
146    pub fn read_fifo_unchecked(&mut self) -> u8 {
147        self.rx.read_fifo_unchecked()
148    }
149
150    /// Is the TX FIFO empty?
151    #[inline(always)]
152    pub fn tx_fifo_empty(&self) -> bool {
153        self.tx.fifo_empty()
154    }
155
156    /// TX FIFO full status.
157    #[inline(always)]
158    pub fn tx_fifo_full(&self) -> bool {
159        self.tx.fifo_full()
160    }
161
162    /// RX FIFO has data.
163    #[inline(always)]
164    pub fn rx_has_data(&self) -> bool {
165        self.rx.has_data()
166    }
167
168    /// Read the error counters and also resets them.
169    pub fn read_and_clear_errors(&mut self) -> RxErrorsCounted {
170        let errors = self.errors;
171        self.errors = RxErrorsCounted::new();
172        errors
173    }
174
175    #[inline(always)]
176    fn handle_status_reg_errors(&mut self, errors: RxErrors) {
177        if errors.frame() {
178            self.errors.frame = self.errors.frame.saturating_add(1);
179        }
180        if errors.parity() {
181            self.errors.parity = self.errors.parity.saturating_add(1);
182        }
183        if errors.overrun() {
184            self.errors.overrun = self.errors.overrun.saturating_add(1);
185        }
186    }
187
188    /// Reset the RX FIFO.
189    #[inline]
190    pub fn reset_rx_fifo(&mut self) {
191        self.regs().write_ctrl_reg(
192            Control::builder()
193                .with_enable_interrupt(false)
194                .with_reset_rx_fifo(true)
195                .with_reset_tx_fifo(false)
196                .build(),
197        );
198    }
199
200    /// Reset the TX FIFO.
201    #[inline]
202    pub fn reset_tx_fifo(&mut self) {
203        self.regs().write_ctrl_reg(
204            Control::builder()
205                .with_enable_interrupt(false)
206                .with_reset_rx_fifo(false)
207                .with_reset_tx_fifo(true)
208                .build(),
209        );
210    }
211
212    /// Split the driver into [Tx] and [Rx] halves.
213    #[inline]
214    pub fn split(self) -> (Tx, Rx) {
215        (self.tx, self.rx)
216    }
217
218    /// Enable UART Lite interrupts.
219    #[inline]
220    pub fn enable_interrupt(&mut self) {
221        self.regs().write_ctrl_reg(
222            Control::builder()
223                .with_enable_interrupt(true)
224                .with_reset_rx_fifo(false)
225                .with_reset_tx_fifo(false)
226                .build(),
227        );
228    }
229
230    /// Disable UART Lite interrupts.
231    #[inline]
232    pub fn disable_interrupt(&mut self) {
233        self.regs().write_ctrl_reg(
234            Control::builder()
235                .with_enable_interrupt(false)
236                .with_reset_rx_fifo(false)
237                .with_reset_tx_fifo(false)
238                .build(),
239        );
240    }
241}
242
243impl embedded_hal_nb::serial::ErrorType for AxiUartlite {
244    type Error = Infallible;
245}
246
247impl embedded_hal_nb::serial::Write for AxiUartlite {
248    #[inline]
249    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
250        self.tx.write(word)
251    }
252
253    #[inline]
254    fn flush(&mut self) -> nb::Result<(), Self::Error> {
255        self.tx.flush()
256    }
257}
258
259impl embedded_hal_nb::serial::Read for AxiUartlite {
260    #[inline]
261    fn read(&mut self) -> nb::Result<u8, Self::Error> {
262        self.rx.read()
263    }
264}
265
266impl embedded_io::ErrorType for AxiUartlite {
267    type Error = Infallible;
268}
269
270impl embedded_io::Read for AxiUartlite {
271    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
272        self.rx.read(buf)
273    }
274}
275
276impl embedded_io::Write for AxiUartlite {
277    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
278        self.tx.write(buf)
279    }
280
281    fn flush(&mut self) -> Result<(), Self::Error> {
282        self.tx.flush()
283    }
284}