Skip to main content

ws63_hal/
uart.rs

1//! UART driver for WS63 (UART0/1/2, 16C550-compatible with FIFO).
2//!
3//! Baud rate: div = (div_h << 8 | div_l) + div_fra / 64.
4//! Clock source: 240MHz system clock.
5
6use crate::peripherals::{Uart0, Uart1, Uart2};
7use core::marker::PhantomData;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum DataBits {
11    Five,
12    Six,
13    Seven,
14    Eight,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Parity {
19    None,
20    Even,
21    Odd,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum StopBits {
26    One,
27    Two,
28}
29
30#[derive(Debug, Clone, Copy)]
31pub struct Config {
32    pub baudrate: u32,
33    pub data_bits: DataBits,
34    pub parity: Parity,
35    pub stop_bits: StopBits,
36}
37
38impl Default for Config {
39    fn default() -> Self {
40        Self { baudrate: 115200, data_bits: DataBits::Eight, parity: Parity::None, stop_bits: StopBits::One }
41    }
42}
43
44pub struct Uart<'d, T> {
45    _peripheral: PhantomData<&'d T>,
46}
47
48#[allow(dead_code)]
49fn regs() -> &'static ws63_pac::uart0::RegisterBlock {
50    // SAFETY: PAC peripheral pointer is a static physical MMIO address, always valid
51    unsafe { &*Uart0::ptr() }
52}
53
54fn uart_ptr(idx: u8) -> *const ws63_pac::uart0::RegisterBlock {
55    match idx {
56        0 => Uart0::ptr(),
57        1 => Uart1::ptr(),
58        2 => Uart2::ptr(),
59        _ => unreachable!(),
60    }
61}
62
63fn uart_regs(idx: u8) -> &'static ws63_pac::uart0::RegisterBlock {
64    // SAFETY: uart_ptr(idx) returns valid PAC MMIO addresses (UART0/1/2 at 0x4401_0000/1000/2000)
65    unsafe { &*uart_ptr(idx) }
66}
67
68impl<'d> Uart<'d, Uart0<'d>> {
69    pub fn new_uart0(_uart: Uart0<'d>, config: Config) -> Self {
70        configure_uart(0, &config);
71        Self { _peripheral: PhantomData }
72    }
73}
74
75impl<'d> Uart<'d, Uart1<'d>> {
76    pub fn new_uart1(_uart: Uart1<'d>, config: Config) -> Self {
77        configure_uart(1, &config);
78        Self { _peripheral: PhantomData }
79    }
80}
81
82impl<'d> Uart<'d, Uart2<'d>> {
83    pub fn new_uart2(_uart: Uart2<'d>, config: Config) -> Self {
84        configure_uart(2, &config);
85        Self { _peripheral: PhantomData }
86    }
87}
88
89fn configure_uart(idx: u8, config: &Config) {
90    let r = uart_regs(idx);
91
92    // Enable divider access
93    r.uart_ctl().modify(|_, w| unsafe { w.bits(0) });
94    r.uart_ctl().write(|w| w.div_en().set_bit());
95
96    // Set baud rate: div = PCLK / (16 * baudrate)
97    // Valid range: div ∈ [1, 65535] (16-bit divider).
98    // At 240MHz PCLK, valid baud ∈ [229, 15_000_000].
99    let pclk = crate::soc::ws63::SYSTEM_CLOCK_HZ;
100    let min_baud = (pclk / (16 * 65535)) + 1;
101    let baudrate = if config.baudrate < min_baud { min_baud } else { config.baudrate };
102    let div = pclk / (16 * baudrate);
103    let div_l = (div & 0xFF) as u16;
104    let div_h = ((div >> 8) & 0xFF) as u16;
105    r.div_l().write(|w| unsafe { w.bits(div_l) });
106    r.div_h().write(|w| unsafe { w.bits(div_h) });
107    r.div_fra().write(|w| unsafe { w.bits(0) });
108
109    // Configure data bits, parity, stop bits
110    let mut ctl = 0u16;
111    ctl |= match config.data_bits {
112        DataBits::Five => 0,
113        DataBits::Six => 1 << 2,
114        DataBits::Seven => 2 << 2,
115        DataBits::Eight => 3 << 2,
116    };
117    match config.parity {
118        Parity::Even => {
119            ctl |= 1 << 5;
120            ctl |= 1 << 4;
121        }
122        Parity::Odd => {
123            ctl |= 1 << 5;
124        }
125        Parity::None => {}
126    }
127    if matches!(config.stop_bits, StopBits::Two) {
128        ctl |= 1 << 7;
129    }
130    r.uart_ctl().write(|w| unsafe { w.bits(ctl | (1 << 0)) }); // div_en=1
131
132    // Enable FIFO
133    r.fifo_ctl().write(|w| unsafe { w.bits(0x01) });
134
135    // Clear FIFO
136    r.fifo_ctl().write(|w| unsafe { w.bits(0x07) });
137}
138
139impl<T> Uart<'_, T> {
140    pub fn write_byte(&self, idx: u8, byte: u8) {
141        let r = uart_regs(idx);
142        while r.fifo_status().read().tx_fifo_full().bit_is_set() {}
143        r.data().write(|w| unsafe { w.bits(byte as u16) });
144    }
145
146    pub fn read_byte(&self, idx: u8) -> Option<u8> {
147        let r = uart_regs(idx);
148        if r.fifo_status().read().rx_fifo_empty().bit_is_set() { None } else { Some(r.data().read().bits() as u8) }
149    }
150
151    pub fn flush_tx(&self, idx: u8) {
152        let r = uart_regs(idx);
153        while !r.fifo_status().read().tx_fifo_empty().bit_is_set() {}
154    }
155
156    /// Non-blocking check: returns true if TX FIFO is fully drained.
157    pub fn tx_flushed(&self, idx: u8) -> bool {
158        uart_regs(idx).fifo_status().read().tx_fifo_empty().bit_is_set()
159    }
160
161    pub fn write(&self, idx: u8, data: &[u8]) {
162        for &b in data {
163            self.write_byte(idx, b);
164        }
165    }
166
167    pub fn uart_regs(&self, idx: u8) -> &'static ws63_pac::uart0::RegisterBlock {
168        uart_regs(idx)
169    }
170}
171
172impl embedded_io::ErrorType for Uart<'_, Uart0<'_>> {
173    type Error = core::convert::Infallible;
174}
175impl embedded_io::Write for Uart<'_, Uart0<'_>> {
176    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
177        for &b in buf {
178            self.write_byte(0, b);
179        }
180        Ok(buf.len())
181    }
182    fn flush(&mut self) -> Result<(), Self::Error> {
183        self.flush_tx(0);
184        Ok(())
185    }
186}
187impl embedded_io::Read for Uart<'_, Uart0<'_>> {
188    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
189        let mut n = 0;
190        for b in buf.iter_mut() {
191            if let Some(byte) = self.read_byte(0) {
192                *b = byte;
193                n += 1;
194            } else {
195                break;
196            }
197        }
198        Ok(n)
199    }
200}
201
202// UART1 embedded-io traits
203impl embedded_io::ErrorType for Uart<'_, Uart1<'_>> {
204    type Error = core::convert::Infallible;
205}
206impl embedded_io::Write for Uart<'_, Uart1<'_>> {
207    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
208        for &b in buf {
209            self.write_byte(1, b);
210        }
211        Ok(buf.len())
212    }
213    fn flush(&mut self) -> Result<(), Self::Error> {
214        self.flush_tx(1);
215        Ok(())
216    }
217}
218impl embedded_io::Read for Uart<'_, Uart1<'_>> {
219    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
220        let mut n = 0;
221        for b in buf.iter_mut() {
222            if let Some(byte) = self.read_byte(1) {
223                *b = byte;
224                n += 1;
225            } else {
226                break;
227            }
228        }
229        Ok(n)
230    }
231}
232
233// UART2 embedded-io traits
234impl embedded_io::ErrorType for Uart<'_, Uart2<'_>> {
235    type Error = core::convert::Infallible;
236}
237impl embedded_io::Write for Uart<'_, Uart2<'_>> {
238    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
239        for &b in buf {
240            self.write_byte(2, b);
241        }
242        Ok(buf.len())
243    }
244    fn flush(&mut self) -> Result<(), Self::Error> {
245        self.flush_tx(2);
246        Ok(())
247    }
248}
249impl embedded_io::Read for Uart<'_, Uart2<'_>> {
250    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
251        let mut n = 0;
252        for b in buf.iter_mut() {
253            if let Some(byte) = self.read_byte(2) {
254                *b = byte;
255                n += 1;
256            } else {
257                break;
258            }
259        }
260        Ok(n)
261    }
262}
263
264// ── embedded-hal-nb serial traits ──────────────────────────────
265
266macro_rules! impl_nb_serial {
267    ($uart:ty, $idx:expr) => {
268        impl embedded_hal_nb::serial::ErrorType for Uart<'_, $uart> {
269            type Error = core::convert::Infallible;
270        }
271        impl embedded_hal_nb::serial::Read for Uart<'_, $uart> {
272            fn read(&mut self) -> nb::Result<u8, Self::Error> {
273                match self.read_byte($idx) {
274                    Some(b) => Ok(b),
275                    None => Err(nb::Error::WouldBlock),
276                }
277            }
278        }
279        impl embedded_hal_nb::serial::Write for Uart<'_, $uart> {
280            fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
281                self.write_byte($idx, byte);
282                Ok(())
283            }
284            fn flush(&mut self) -> nb::Result<(), Self::Error> {
285                if self.tx_flushed($idx) { Ok(()) } else { Err(nb::Error::WouldBlock) }
286            }
287        }
288    };
289}
290
291impl_nb_serial!(Uart0<'_>, 0);
292impl_nb_serial!(Uart1<'_>, 1);
293impl_nb_serial!(Uart2<'_>, 2);