1#![no_std]
18#![cfg_attr(docsrs, feature(doc_cfg))]
19#![deny(missing_docs)]
20
21use core::convert::Infallible;
22
23use registers::{FifoControl, InterruptEnable, LineControl, RxFifoTrigger, StopBits, WordLen};
24pub mod registers;
25
26pub mod tx;
27pub use tx::*;
28
29pub mod tx_async;
30pub use tx_async::*;
31
32pub mod rx;
33pub use rx::*;
34
35pub const FIFO_DEPTH: usize = 16;
37
38pub const DEFAULT_RX_TRIGGER_LEVEL: RxFifoTrigger = RxFifoTrigger::EightBytes;
40
41#[derive(Debug, PartialEq, Eq, Clone, Copy)]
43pub struct ClockConfig {
44 pub div: u16,
46}
47
48#[derive(Debug, thiserror::Error, PartialEq, Eq)]
50#[error("divisor is zero")]
51pub struct DivisorZeroError;
52
53#[inline]
56pub fn calculate_error_rate_from_div(
57 clk_in: fugit::HertzU32,
58 baudrate: u32,
59 div: u16,
60) -> Result<f32, DivisorZeroError> {
61 if baudrate == 0 || div == 0 {
62 return Err(DivisorZeroError);
63 }
64 let actual = (clk_in.raw() as f32) / (16.0 * div as f32);
65 Ok(libm::fabsf(actual - baudrate as f32) / baudrate as f32)
66}
67
68#[derive(Debug, thiserror::Error, PartialEq, Eq)]
71#[error("divisor too large")]
72pub enum ClockConfigError {
73 DivisorTooLargeError(u32),
75 DivisorZero(#[from] DivisorZeroError),
77}
78
79impl ClockConfig {
80 pub fn new(div: u16) -> Self {
82 Self { div }
83 }
84
85 #[inline(always)]
87 pub fn div_msb(&self) -> u8 {
88 (self.div >> 8) as u8
89 }
90
91 #[inline(always)]
93 pub fn div_lsb(&self) -> u8 {
94 self.div as u8
95 }
96
97 #[inline]
100 pub fn new_autocalc_with_error(
101 clk_in: fugit::HertzU32,
102 baudrate: u32,
103 ) -> Result<(Self, f32), ClockConfigError> {
104 let cfg = Self::new_autocalc(clk_in, baudrate)?;
105 Ok((cfg, cfg.calculate_error_rate(clk_in, baudrate)?))
106 }
107
108 #[inline]
114 pub fn new_autocalc(clk_in: fugit::HertzU32, baudrate: u32) -> Result<Self, ClockConfigError> {
115 let div = Self::calc_div_with_integer_div(clk_in, baudrate)?;
116 if div > u16::MAX as u32 {
117 return Err(ClockConfigError::DivisorTooLargeError(div));
118 }
119 Ok(Self { div: div as u16 })
120 }
121
122 #[inline]
125 pub fn calculate_error_rate(
126 &self,
127 clk_in: fugit::HertzU32,
128 baudrate: u32,
129 ) -> Result<f32, DivisorZeroError> {
130 calculate_error_rate_from_div(clk_in, baudrate, self.div)
131 }
132
133 #[inline(always)]
135 pub const fn calc_div_with_integer_div(
136 clk_in: fugit::HertzU32,
137 baudrate: u32,
138 ) -> Result<u32, DivisorZeroError> {
139 if baudrate == 0 {
140 return Err(DivisorZeroError);
141 }
142 Ok((clk_in.raw() + (8 * baudrate)) / (16 * baudrate))
144 }
145}
146
147#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
149pub enum Parity {
150 #[default]
152 None,
153 Odd,
155 Even,
157}
158
159pub struct AxiUart16550 {
161 rx: Rx,
162 tx: Tx,
163 config: UartConfig,
164}
165
166#[derive(Debug, PartialEq, Eq, Clone, Copy)]
168pub struct UartConfig {
169 clk: ClockConfig,
170 word_len: WordLen,
171 parity: Parity,
172 stop_bits: StopBits,
173}
174
175impl UartConfig {
176 pub const fn new_with_clk_config(clk: ClockConfig) -> Self {
178 Self {
179 clk,
180 word_len: WordLen::Eight,
181 parity: Parity::None,
182 stop_bits: StopBits::One,
183 }
184 }
185
186 pub const fn new(
188 clk: ClockConfig,
189 word_len: WordLen,
190 parity: Parity,
191 stop_bits: StopBits,
192 ) -> Self {
193 Self {
194 clk,
195 word_len,
196 parity,
197 stop_bits,
198 }
199 }
200}
201
202impl AxiUart16550 {
203 pub unsafe fn new(base_addr: u32, config: UartConfig) -> Self {
216 let mut regs = unsafe { registers::Registers::new_mmio_at(base_addr as usize) };
217 regs.write_lcr(LineControl::new_for_divisor_access());
219 regs.write_fifo_or_dll(config.clk.div_lsb() as u32);
220 regs.write_ier_or_dlm(config.clk.div_msb() as u32);
221 regs.write_lcr(
224 LineControl::builder()
225 .with_div_access_latch(false)
226 .with_set_break(false)
227 .with_stick_parity(false)
228 .with_even_parity(config.parity == Parity::Even)
229 .with_parity_enable(config.parity != Parity::None)
230 .with_stop_bits(config.stop_bits)
231 .with_word_len(config.word_len)
232 .build(),
233 );
234 regs.write_ier_or_dlm(InterruptEnable::new_with_raw_value(0x0).raw_value());
236 regs.write_iir_or_fcr(
238 FifoControl::builder()
239 .with_rx_fifo_trigger(DEFAULT_RX_TRIGGER_LEVEL)
240 .with_dma_mode_sel(false)
241 .with_reset_tx_fifo(true)
242 .with_reset_rx_fifo(true)
243 .with_fifo_enable(true)
244 .build()
245 .raw_value(),
246 );
247 Self {
248 rx: Rx::new(unsafe { regs.clone() }),
249 tx: Tx::new(regs),
250 config,
251 }
252 }
253
254 #[inline(always)]
256 pub const fn regs(&mut self) -> &mut registers::MmioRegisters<'static> {
257 &mut self.rx.regs
258 }
259
260 #[inline(always)]
262 pub const fn config(&mut self) -> &UartConfig {
263 &self.config
264 }
265
266 #[inline]
270 pub fn write_fifo(&mut self, data: u8) -> nb::Result<(), Infallible> {
271 self.tx.write_fifo(data)
272 }
273
274 #[inline(always)]
276 pub fn thr_empty(&self) -> bool {
277 self.tx.thr_empty()
278 }
279
280 #[inline(always)]
282 pub fn tx_empty(&self) -> bool {
283 self.tx.tx_empty()
284 }
285
286 #[inline(always)]
288 pub fn rx_has_data(&self) -> bool {
289 self.rx.has_data()
290 }
291
292 #[inline(always)]
296 pub fn write_fifo_unchecked(&mut self, data: u8) {
297 self.tx.write_fifo_unchecked(data);
298 }
299
300 #[inline]
305 pub fn read_fifo(&mut self) -> nb::Result<u8, Infallible> {
306 self.rx.read_fifo()
307 }
308
309 #[inline(always)]
311 pub fn read_fifo_unchecked(&mut self) -> u8 {
312 self.rx.read_fifo_unchecked()
313 }
314
315 #[inline(always)]
317 pub fn enable_interrupts(&mut self, ier: InterruptEnable) {
318 self.regs().write_ier_or_dlm(ier.raw_value());
319 }
320
321 pub fn split(self) -> (Tx, Rx) {
323 (self.tx, self.rx)
324 }
325}
326
327impl embedded_hal_nb::serial::ErrorType for AxiUart16550 {
328 type Error = Infallible;
329}
330
331impl embedded_hal_nb::serial::Write for AxiUart16550 {
332 #[inline]
333 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
334 self.tx.write(word)
335 }
336
337 #[inline]
338 fn flush(&mut self) -> nb::Result<(), Self::Error> {
339 self.tx.flush()
340 }
341}
342
343impl embedded_hal_nb::serial::Read for AxiUart16550 {
344 #[inline]
345 fn read(&mut self) -> nb::Result<u8, Self::Error> {
346 self.rx.read()
347 }
348}
349
350impl embedded_io::ErrorType for AxiUart16550 {
351 type Error = Infallible;
352}
353
354impl embedded_io::Read for AxiUart16550 {
355 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
356 self.rx.read(buf)
357 }
358}
359
360impl embedded_io::Write for AxiUart16550 {
361 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
362 self.tx.write(buf)
363 }
364
365 fn flush(&mut self) -> Result<(), Self::Error> {
366 self.tx.flush()
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use crate::ClockConfigError;
373
374 use super::{DivisorZeroError, calculate_error_rate_from_div};
376
377 use super::ClockConfig;
378 use approx::abs_diff_eq;
379 use fugit::RateExtU32;
380
381 #[test]
382 fn test_clk_calc_example_0() {
383 let clk_cfg = ClockConfig::new_autocalc(100.MHz(), 56000).unwrap();
384 assert_eq!(clk_cfg.div, 0x0070);
386 assert_eq!(clk_cfg.div_msb(), 0x00);
387 assert_eq!(clk_cfg.div_lsb(), 0x70);
388 let error = clk_cfg.calculate_error_rate(100.MHz(), 56000).unwrap();
389 assert!(abs_diff_eq!(error, 0.0035, epsilon = 0.001));
390 let (clk_cfg_checked, error_checked) =
391 ClockConfig::new_autocalc_with_error(100.MHz(), 56000).unwrap();
392 assert_eq!(clk_cfg, clk_cfg_checked);
393 assert!(abs_diff_eq!(error, error_checked, epsilon = 0.001));
394 let error_calc = calculate_error_rate_from_div(100.MHz(), 56000, clk_cfg.div).unwrap();
395 assert!(abs_diff_eq!(error, error_calc, epsilon = 0.001));
396 }
397
398 #[test]
399 fn test_clk_calc_example_1() {
400 let clk_cfg = ClockConfig::new_autocalc(1843200.Hz(), 56000).unwrap();
401 assert_eq!(clk_cfg.div, 0x0002);
402 assert_eq!(clk_cfg.div_msb(), 0x00);
403 assert_eq!(clk_cfg.div_lsb(), 0x02);
404 }
405
406 #[test]
407 fn test_invalid_baud() {
408 let clk_cfg = ClockConfig::new_autocalc_with_error(100.MHz(), 0);
409 assert_eq!(
410 clk_cfg,
411 Err(ClockConfigError::DivisorZero(DivisorZeroError))
412 );
413 }
414
415 #[test]
416 fn test_invalid_div() {
417 let error = calculate_error_rate_from_div(100.MHz(), 115200, 0);
418 assert_eq!(error.unwrap_err(), DivisorZeroError);
419 let error = calculate_error_rate_from_div(100.MHz(), 0, 0);
420 assert_eq!(error.unwrap_err(), DivisorZeroError);
421 let error = calculate_error_rate_from_div(100.MHz(), 0, 16);
422 assert_eq!(error.unwrap_err(), DivisorZeroError);
423 }
424}