1use core::convert::Infallible;
11
12use arbitrary_int::u3;
13use libm::round;
14use zynq7000::{
15 slcr::reset::DualRefAndClockReset,
16 uart::{
17 BaudRateDivisor, Baudgen, ChMode, ClockSelect, FifoTrigger, InterruptControl, MmioUart,
18 Mode, UART_0_BASE, UART_1_BASE,
19 },
20};
21
22use crate::{
23 enable_amba_peripheral_clock,
24 gpio::{
25 IoPeriphPin,
26 mio::{
27 Mio8, Mio9, Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31,
28 Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Mio52, Mio53,
29 MioPin, MuxConfig, Pin,
30 },
31 },
32 slcr::Slcr,
33};
34
35#[cfg(not(feature = "7z010-7z007s-clg225"))]
36use crate::gpio::mio::{
37 Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27, Mio40,
38 Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
39};
40
41use super::{clocks::IoClocks, time::Hertz};
42
43pub mod tx;
44pub use tx::*;
45
46pub mod tx_async;
47pub use tx_async::*;
48
49pub mod rx;
50pub use rx::*;
51
52pub const FIFO_DEPTH: usize = 64;
53pub const DEFAULT_RX_TRIGGER_LEVEL: u8 = 32;
54pub const UART_MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b111));
55
56#[derive(Debug, Copy, Clone, PartialEq, Eq)]
57pub enum UartId {
58 Uart0 = 0,
59 Uart1 = 1,
60}
61
62pub trait PsUart {
63 fn reg_block(&self) -> MmioUart<'static>;
64 fn uart_id(&self) -> Option<UartId>;
65}
66
67impl PsUart for MmioUart<'static> {
68 #[inline]
69 fn reg_block(&self) -> MmioUart<'static> {
70 unsafe { self.clone() }
71 }
72
73 fn uart_id(&self) -> Option<UartId> {
74 let base_addr = unsafe { self.ptr() } as usize;
75 if base_addr == UART_0_BASE {
76 return Some(UartId::Uart0);
77 } else if base_addr == UART_1_BASE {
78 return Some(UartId::Uart1);
79 }
80 None
81 }
82}
83
84impl UartId {
85 pub const unsafe fn regs(&self) -> MmioUart<'static> {
91 match self {
92 UartId::Uart0 => unsafe { zynq7000::uart::Uart::new_mmio_fixed_0() },
93 UartId::Uart1 => unsafe { zynq7000::uart::Uart::new_mmio_fixed_1() },
94 }
95 }
96}
97
98pub trait RxPin: MioPin {
99 const UART_IDX: UartId;
100}
101pub trait TxPin: MioPin {
102 const UART_IDX: UartId;
103}
104
105pub trait UartPins {}
106
107#[derive(Debug, thiserror::Error)]
108#[error("divisor is zero")]
109pub struct DivisorZero;
110
111macro_rules! pin_pairs {
112 ($UartPeriph:path, ($( [$(#[$meta:meta], )? $TxMio:ident, $RxMio:ident] ),+ $(,)? )) => {
113 $(
114 $( #[$meta] )?
115 impl TxPin for Pin<$TxMio> {
116 const UART_IDX: UartId = $UartPeriph;
117 }
118
119 $( #[$meta] )?
120 impl RxPin for Pin<$RxMio> {
121 const UART_IDX: UartId = $UartPeriph;
122 }
123
124 impl UartPins for (Pin<$TxMio>, Pin<$RxMio>) {}
125 )+
126 };
127}
128
129pin_pairs!(
130 UartId::Uart0,
131 (
132 [Mio11, Mio10],
133 [Mio15, Mio14],
134 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio19, Mio18],
135 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio23, Mio22],
136 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio27, Mio26],
137 [Mio31, Mio30],
138 [Mio35, Mio34],
139 [Mio39, Mio38],
140 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio43, Mio42],
141 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio47, Mio46],
142 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio51, Mio50],
143 )
144);
145
146pin_pairs!(
147 UartId::Uart1,
148 (
149 [Mio8, Mio9],
150 [Mio12, Mio13],
151 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio16, Mio17],
152 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio20, Mio21],
153 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio24, Mio25],
154 [Mio28, Mio29],
155 [Mio32, Mio33],
156 [Mio36, Mio37],
157 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio40, Mio41],
158 [#[cfg(not(feature ="7z010-7z007s-clg225"))], Mio44, Mio45],
159 [Mio48, Mio49],
160 [Mio52, Mio53],
161 )
162);
163
164pub const MAX_BAUD_RATE: u32 = 6240000;
166pub const MIN_BAUD_RATE: u32 = 110;
168
169pub const MAX_BAUDERROR_RATE: f32 = 0.005;
170
171#[derive(Debug, Default, Clone, Copy)]
172pub enum Parity {
173 Even,
174 Odd,
175 #[default]
176 None,
177}
178
179#[derive(Debug, Default, Clone, Copy)]
180pub enum Stopbits {
181 #[default]
182 One,
183 OnePointFive,
184 Two,
185}
186
187#[derive(Debug, Default, Clone, Copy)]
188pub enum CharLen {
189 SixBits,
190 SevenBits,
191 #[default]
192 EightBits,
193}
194
195#[derive(Debug, Clone, Copy)]
196pub struct ClockConfig {
197 cd: u16,
198 bdiv: u8,
199}
200
201#[cfg(feature = "alloc")]
202pub fn calculate_viable_configs(
203 mut uart_clk: Hertz,
204 clk_sel: ClockSelect,
205 target_baud: u32,
206) -> alloc::vec::Vec<(ClockConfig, f64)> {
207 let mut viable_cfgs = alloc::vec::Vec::new();
208 if clk_sel == ClockSelect::UartRefClkDiv8 {
209 uart_clk /= 8;
210 }
211 let mut current_clk_config = ClockConfig::default();
212 for bdiv in 4..u8::MAX {
213 let cd =
214 round(uart_clk.raw() as f64 / ((bdiv as u32 + 1) as f64 * target_baud as f64)) as u64;
215 if cd > u16::MAX as u64 {
216 continue;
217 }
218 current_clk_config.cd = cd as u16;
219 current_clk_config.bdiv = bdiv;
220 let baud = current_clk_config.actual_baud(uart_clk);
221 let error = ((baud - target_baud as f64).abs() / target_baud as f64) * 100.0;
222 if error < MAX_BAUDERROR_RATE as f64 {
223 viable_cfgs.push((current_clk_config, error));
224 }
225 }
226
227 viable_cfgs
228}
229
230pub fn calculate_raw_baud_cfg_smallest_error(
235 mut uart_clk: Hertz,
236 clk_sel: ClockSelect,
237 target_baud: u32,
238) -> Result<(ClockConfig, f64), DivisorZero> {
239 if target_baud == 0 {
240 return Err(DivisorZero);
241 }
242 if clk_sel == ClockSelect::UartRefClkDiv8 {
243 uart_clk /= 8;
244 }
245 let mut current_clk_config = ClockConfig::default();
246 let mut best_clk_config = ClockConfig::default();
247 let mut smallest_error: f64 = 100.0;
248 for bdiv in 4..u8::MAX {
249 let cd =
250 round(uart_clk.raw() as f64 / ((bdiv as u32 + 1) as f64 * target_baud as f64)) as u64;
251 if cd > u16::MAX as u64 {
252 continue;
253 }
254 current_clk_config.cd = cd as u16;
255 current_clk_config.bdiv = bdiv;
256 let baud = current_clk_config.actual_baud(uart_clk);
257 let error = ((baud - target_baud as f64).abs() / target_baud as f64) * 100.0;
258 if error < smallest_error {
259 best_clk_config = current_clk_config;
260 smallest_error = error;
261 }
262 }
263
264 Ok((best_clk_config, smallest_error))
265}
266
267impl ClockConfig {
268 #[inline]
269 pub const fn new(cd: u16, bdiv: u8) -> Result<Self, DivisorZero> {
270 if cd == 0 {
271 return Err(DivisorZero);
272 }
273 Ok(ClockConfig { cd, bdiv })
274 }
275
276 pub fn new_autocalc_with_error(
282 io_clks: &IoClocks,
283 target_baud: u32,
284 ) -> Result<(Self, f64), DivisorZero> {
285 Self::new_autocalc_generic(io_clks, ClockSelect::UartRefClk, target_baud)
286 }
287
288 pub fn new_autocalc_generic(
289 io_clks: &IoClocks,
290 clk_sel: ClockSelect,
291 target_baud: u32,
292 ) -> Result<(Self, f64), DivisorZero> {
293 Self::new_autocalc_with_raw_clk(io_clks.uart_clk(), clk_sel, target_baud)
294 }
295
296 pub fn new_autocalc_with_raw_clk(
297 uart_clk: Hertz,
298 clk_sel: ClockSelect,
299 target_baud: u32,
300 ) -> Result<(Self, f64), DivisorZero> {
301 calculate_raw_baud_cfg_smallest_error(uart_clk, clk_sel, target_baud)
302 }
303
304 #[inline]
305 pub const fn cd(&self) -> u16 {
306 self.cd
307 }
308
309 #[inline]
310 pub const fn bdiv(&self) -> u8 {
311 self.bdiv
312 }
313
314 #[inline]
315 pub fn rounded_baud(&self, sel_clk: Hertz) -> u32 {
316 round(self.actual_baud(sel_clk)) as u32
317 }
318
319 #[inline]
320 pub fn actual_baud(&self, sel_clk: Hertz) -> f64 {
321 sel_clk.raw() as f64 / (self.cd as f64 * (self.bdiv + 1) as f64)
322 }
323}
324
325impl Default for ClockConfig {
326 #[inline]
327 fn default() -> Self {
328 ClockConfig::new(1, 0).unwrap()
329 }
330}
331
332#[derive(Debug)]
333pub struct Config {
334 clk_config: ClockConfig,
335 chmode: ChMode,
336 parity: Parity,
337 stopbits: Stopbits,
338 chrl: CharLen,
339 clk_sel: ClockSelect,
340}
341
342impl Config {
343 pub fn new_with_clk_config(clk_config: ClockConfig) -> Self {
344 Self::new(
345 clk_config,
346 ChMode::default(),
347 Parity::default(),
348 Stopbits::default(),
349 CharLen::default(),
350 ClockSelect::default(),
351 )
352 }
353
354 #[inline]
355 pub const fn new(
356 clk_config: ClockConfig,
357 chmode: ChMode,
358 parity: Parity,
359 stopbits: Stopbits,
360 chrl: CharLen,
361 clk_sel: ClockSelect,
362 ) -> Self {
363 Config {
364 clk_config,
365 chmode,
366 parity,
367 stopbits,
368 chrl,
369 clk_sel,
370 }
371 }
372
373 #[inline]
374 pub const fn raw_clk_config(&self) -> ClockConfig {
375 self.clk_config
376 }
377
378 #[inline]
379 pub const fn chmode(&self) -> ChMode {
380 self.chmode
381 }
382
383 #[inline]
384 pub const fn parity(&self) -> Parity {
385 self.parity
386 }
387
388 #[inline]
389 pub const fn stopbits(&self) -> Stopbits {
390 self.stopbits
391 }
392
393 #[inline]
394 pub const fn chrl(&self) -> CharLen {
395 self.chrl
396 }
397
398 #[inline]
399 pub const fn clksel(&self) -> ClockSelect {
400 self.clk_sel
401 }
402}
403
404pub struct Uart {
406 rx: Rx,
407 tx: Tx,
408 cfg: Config,
409}
410
411#[derive(Debug, thiserror::Error)]
412#[error("invalid UART ID")]
413pub struct InvalidPsUart;
414
415#[derive(Debug, thiserror::Error)]
416pub enum UartConstructionError {
417 #[error("invalid UART ID")]
418 InvalidPsUart(#[from] InvalidPsUart),
419 #[error("missmatch between pins index and passed index")]
420 IdxMissmatch,
421 #[error("invalid pin mux conf for UART")]
422 InvalidMuxConf(MuxConfig),
423}
424
425impl Uart {
426 pub fn new_with_emio(uart: impl PsUart, cfg: Config) -> Result<Uart, InvalidPsUart> {
432 if uart.uart_id().is_none() {
433 return Err(InvalidPsUart);
434 }
435 Ok(Self::new_generic_unchecked(
436 uart.reg_block(),
437 uart.uart_id().unwrap(),
438 cfg,
439 ))
440 }
441
442 pub fn new_with_mio<TxPinI: TxPin, RxPinI: RxPin>(
444 uart: impl PsUart,
445 cfg: Config,
446 pins: (TxPinI, RxPinI),
447 ) -> Result<Self, UartConstructionError>
448 where
449 (TxPinI, RxPinI): UartPins,
450 {
451 let id = uart.uart_id();
452 if id.is_none() {
453 return Err(InvalidPsUart.into());
454 }
455 if id.unwrap() != TxPinI::UART_IDX || id.unwrap() != RxPinI::UART_IDX {
456 return Err(UartConstructionError::IdxMissmatch);
457 }
458 IoPeriphPin::new(pins.0, UART_MUX_CONF, None);
459 IoPeriphPin::new(pins.1, UART_MUX_CONF, None);
460 Ok(Self::new_generic_unchecked(
461 uart.reg_block(),
462 id.unwrap(),
463 cfg,
464 ))
465 }
466
467 pub fn new_generic_unchecked(
472 mut reg_block: MmioUart<'static>,
473 uart_id: UartId,
474 cfg: Config,
475 ) -> Uart {
476 let periph_sel = match uart_id {
477 UartId::Uart0 => crate::PeriphSelect::Uart0,
478 UartId::Uart1 => crate::PeriphSelect::Uart1,
479 };
480 enable_amba_peripheral_clock(periph_sel);
481 reset(uart_id);
482 reg_block.modify_cr(|mut v| {
483 v.set_tx_dis(true);
484 v.set_rx_dis(true);
485 v
486 });
487 reg_block.write_idr(InterruptControl::new_with_raw_value(0xFFFF_FFFF));
489 let mode = Mode::builder()
490 .with_chmode(cfg.chmode)
491 .with_nbstop(match cfg.stopbits {
492 Stopbits::One => zynq7000::uart::Stopbits::One,
493 Stopbits::OnePointFive => zynq7000::uart::Stopbits::OnePointFive,
494 Stopbits::Two => zynq7000::uart::Stopbits::Two,
495 })
496 .with_par(match cfg.parity {
497 Parity::Even => zynq7000::uart::Parity::Even,
498 Parity::Odd => zynq7000::uart::Parity::Odd,
499 Parity::None => zynq7000::uart::Parity::NoParity,
500 })
501 .with_chrl(match cfg.chrl {
502 CharLen::SixBits => zynq7000::uart::CharLen::SixBits,
503 CharLen::SevenBits => zynq7000::uart::CharLen::SevenBits,
504 CharLen::EightBits => zynq7000::uart::CharLen::EightBits,
505 })
506 .with_clksel(cfg.clk_sel)
507 .build();
508 reg_block.write_mr(mode);
509 reg_block.write_baudgen(
510 Baudgen::builder()
511 .with_cd(cfg.raw_clk_config().cd())
512 .build(),
513 );
514 reg_block.write_baud_rate_div(
515 BaudRateDivisor::builder()
516 .with_bdiv(cfg.raw_clk_config().bdiv())
517 .build(),
518 );
519 reg_block.modify_cr(|mut v| {
521 v.set_tx_rst(true);
522 v.set_rx_rst(true);
523 v
524 });
525
526 reg_block.write_rx_fifo_trigger(FifoTrigger::new_with_raw_value(
528 DEFAULT_RX_TRIGGER_LEVEL as u32,
529 ));
530
531 reg_block.modify_cr(|mut v| {
533 v.set_tx_dis(false);
534 v.set_rx_dis(false);
535 v.set_tx_en(true);
536 v.set_rx_en(true);
537 v
538 });
539
540 Uart {
541 rx: Rx {
542 regs: unsafe { reg_block.clone() },
543 },
544 tx: Tx {
545 regs: reg_block,
546 idx: uart_id,
547 },
548 cfg,
549 }
550 }
551
552 #[inline]
553 pub fn set_mode(&mut self, mode: ChMode) {
554 self.regs().modify_mr(|mut mr| {
555 mr.set_chmode(mode);
556 mr
557 });
558 }
559
560 #[inline]
561 pub const fn regs(&mut self) -> &mut MmioUart<'static> {
562 &mut self.rx.regs
563 }
564
565 #[inline]
566 pub const fn cfg(&self) -> &Config {
567 &self.cfg
568 }
569
570 #[inline]
571 pub const fn split(self) -> (Tx, Rx) {
572 (self.tx, self.rx)
573 }
574}
575
576impl embedded_hal_nb::serial::ErrorType for Uart {
577 type Error = Infallible;
578}
579
580impl embedded_hal_nb::serial::Write for Uart {
581 #[inline]
582 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
583 self.tx.write(word)
584 }
585
586 fn flush(&mut self) -> nb::Result<(), Self::Error> {
587 embedded_hal_nb::serial::Write::flush(&mut self.tx)
588 }
589}
590
591impl embedded_hal_nb::serial::Read for Uart {
592 #[inline]
598 fn read(&mut self) -> nb::Result<u8, Self::Error> {
599 self.rx.read()
600 }
601}
602
603impl embedded_io::ErrorType for Uart {
604 type Error = Infallible;
605}
606
607impl embedded_io::Write for Uart {
608 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
609 self.tx.write(buf)
610 }
611
612 fn flush(&mut self) -> Result<(), Self::Error> {
613 self.tx.flush();
614 Ok(())
615 }
616}
617
618impl embedded_io::Read for Uart {
619 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
620 self.rx.read(buf)
621 }
622}
623
624#[inline]
629pub fn reset(id: UartId) {
630 let assert_reset = match id {
631 UartId::Uart0 => DualRefAndClockReset::builder()
632 .with_periph1_ref_rst(false)
633 .with_periph0_ref_rst(true)
634 .with_periph1_cpu1x_rst(false)
635 .with_periph0_cpu1x_rst(true)
636 .build(),
637 UartId::Uart1 => DualRefAndClockReset::builder()
638 .with_periph1_ref_rst(true)
639 .with_periph0_ref_rst(false)
640 .with_periph1_cpu1x_rst(true)
641 .with_periph0_cpu1x_rst(false)
642 .build(),
643 };
644 unsafe {
645 Slcr::with(|regs| {
646 regs.reset_ctrl().write_uart(assert_reset);
647 cortex_ar::asm::nop();
649 regs.reset_ctrl().write_uart(DualRefAndClockReset::DEFAULT);
650 });
651 }
652}
653
654#[cfg(test)]
655mod tests {
656 use super::*;
657 use approx::abs_diff_eq;
658 use fugit::HertzU32;
659 use zynq7000::uart::ClockSelect;
660
661 const REF_UART_CLK: HertzU32 = HertzU32::from_raw(50_000_000);
662 const REF_UART_CLK_DIV_8: HertzU32 = HertzU32::from_raw(6_250_000);
663
664 #[test]
665 fn test_error_calc_0() {
666 let cfg_0 = ClockConfig::new(10417, 7).unwrap();
668 let actual_baud_0 = cfg_0.actual_baud(REF_UART_CLK);
669 assert!(abs_diff_eq!(actual_baud_0, 599.980, epsilon = 0.01));
670 }
671
672 #[test]
673 fn test_error_calc_1() {
674 let cfg = ClockConfig::new(81, 7).unwrap();
676 let actual_baud = cfg.actual_baud(REF_UART_CLK_DIV_8);
677 assert!(abs_diff_eq!(actual_baud, 9645.061, epsilon = 0.01));
678 }
679
680 #[test]
681 fn test_error_calc_2() {
682 let cfg = ClockConfig::new(651, 7).unwrap();
684 let actual_baud = cfg.actual_baud(REF_UART_CLK);
685 assert!(abs_diff_eq!(actual_baud, 9600.614, epsilon = 0.01));
686 }
687
688 #[test]
689 fn test_error_calc_3() {
690 let cfg = ClockConfig::new(347, 4).unwrap();
692 let actual_baud = cfg.actual_baud(REF_UART_CLK);
693 assert!(abs_diff_eq!(actual_baud, 28818.44, epsilon = 0.01));
694 }
695
696 #[test]
697 fn test_error_calc_4() {
698 let cfg = ClockConfig::new(9, 5).unwrap();
700 let actual_baud = cfg.actual_baud(REF_UART_CLK);
701 assert!(abs_diff_eq!(actual_baud, 925925.92, epsilon = 0.01));
702 }
703
704 #[test]
705 fn test_best_calc_0() {
706 let result =
707 ClockConfig::new_autocalc_with_raw_clk(REF_UART_CLK, ClockSelect::UartRefClk, 600);
708 assert!(result.is_ok());
709 let (cfg, _error) = result.unwrap();
710 assert_eq!(cfg.cd(), 499);
711 assert_eq!(cfg.bdiv(), 166);
712 }
713
714 #[test]
715 #[cfg(feature = "alloc")]
716 fn test_viable_config_calculation() {
717 let cfgs = calculate_viable_configs(REF_UART_CLK, ClockSelect::UartRefClk, 115200);
718 assert!(
719 cfgs.iter()
720 .find(|(cfg, _error)| { cfg.cd() == 62 && cfg.bdiv() == 6 })
721 .is_some()
722 );
723 }
724}