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: the 160 MHz PLL-derived UART clock ([`crate::soc::ws63::UART_CLOCK_HZ`]),
5//! NOT the 240 MHz CPU clock (vendor `clock_init` sets the baud base to 160 MHz).
6
7use crate::peripherals::{Uart0, Uart1, Uart2};
8use core::marker::PhantomData;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum DataBits {
12    Five,
13    Six,
14    Seven,
15    Eight,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Parity {
20    None,
21    Even,
22    Odd,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum StopBits {
27    One,
28    Two,
29}
30
31#[derive(Debug, Clone, Copy)]
32pub struct Config {
33    pub baudrate: u32,
34    pub data_bits: DataBits,
35    pub parity: Parity,
36    pub stop_bits: StopBits,
37}
38
39impl Default for Config {
40    fn default() -> Self {
41        Self { baudrate: 115200, data_bits: DataBits::Eight, parity: Parity::None, stop_bits: StopBits::One }
42    }
43}
44
45pub struct Uart<'d, T> {
46    _peripheral: PhantomData<&'d T>,
47}
48
49#[allow(dead_code)]
50fn regs() -> &'static ws63_pac::uart0::RegisterBlock {
51    // SAFETY: PAC peripheral pointer is a static physical MMIO address, always valid
52    unsafe { &*Uart0::ptr() }
53}
54
55fn uart_ptr(idx: u8) -> *const ws63_pac::uart0::RegisterBlock {
56    match idx {
57        0 => Uart0::ptr(),
58        1 => Uart1::ptr(),
59        2 => Uart2::ptr(),
60        _ => unreachable!(),
61    }
62}
63
64fn uart_regs(idx: u8) -> &'static ws63_pac::uart0::RegisterBlock {
65    // SAFETY: uart_ptr(idx) returns valid PAC MMIO addresses (UART0/1/2 at 0x4401_0000/1000/2000)
66    unsafe { &*uart_ptr(idx) }
67}
68
69impl<'d> Uart<'d, Uart0<'d>> {
70    pub fn new_uart0(_uart: Uart0<'d>, config: Config) -> Self {
71        configure_uart(0, &config);
72        Self { _peripheral: PhantomData }
73    }
74}
75
76impl<'d> Uart<'d, Uart1<'d>> {
77    pub fn new_uart1(_uart: Uart1<'d>, config: Config) -> Self {
78        configure_uart(1, &config);
79        Self { _peripheral: PhantomData }
80    }
81}
82
83impl<'d> Uart<'d, Uart2<'d>> {
84    pub fn new_uart2(_uart: Uart2<'d>, config: Config) -> Self {
85        configure_uart(2, &config);
86        Self { _peripheral: PhantomData }
87    }
88}
89
90fn configure_uart(idx: u8, config: &Config) {
91    let r = uart_regs(idx);
92
93    // Enable divider access
94    r.uart_ctl().modify(|_, w| unsafe { w.bits(0) });
95    r.uart_ctl().write(|w| w.div_en().set_bit());
96
97    // Set baud rate: div = UART_CLK / (16 * baudrate)
98    // Valid range: div ∈ [1, 65535] (16-bit divider).
99    // At 160MHz UART clock, valid baud ∈ [153, 10_000_000].
100    let pclk = crate::soc::ws63::UART_CLOCK_HZ;
101    let min_baud = (pclk / (16 * 65535)) + 1;
102    let baudrate = if config.baudrate < min_baud { min_baud } else { config.baudrate };
103    let div = pclk / (16 * baudrate);
104    let div_l = (div & 0xFF) as u16;
105    let div_h = ((div >> 8) & 0xFF) as u16;
106    r.div_l().write(|w| unsafe { w.bits(div_l) });
107    r.div_h().write(|w| unsafe { w.bits(div_h) });
108    r.div_fra().write(|w| unsafe { w.bits(0) });
109
110    // Configure data bits, parity, stop bits
111    let mut ctl = 0u16;
112    ctl |= match config.data_bits {
113        DataBits::Five => 0,
114        DataBits::Six => 1 << 2,
115        DataBits::Seven => 2 << 2,
116        DataBits::Eight => 3 << 2,
117    };
118    match config.parity {
119        Parity::Even => {
120            ctl |= 1 << 5;
121            ctl |= 1 << 4;
122        }
123        Parity::Odd => {
124            ctl |= 1 << 5;
125        }
126        Parity::None => {}
127    }
128    if matches!(config.stop_bits, StopBits::Two) {
129        ctl |= 1 << 7;
130    }
131    r.uart_ctl().write(|w| unsafe { w.bits(ctl | (1 << 0)) }); // div_en=1
132
133    // Enable FIFO
134    r.fifo_ctl().write(|w| unsafe { w.bits(0x01) });
135
136    // Clear FIFO
137    r.fifo_ctl().write(|w| unsafe { w.bits(0x07) });
138}
139
140impl<T> Uart<'_, T> {
141    pub fn write_byte(&self, idx: u8, byte: u8) {
142        let r = uart_regs(idx);
143        while r.fifo_status().read().tx_fifo_full().bit_is_set() {}
144        r.data().write(|w| unsafe { w.bits(byte as u16) });
145    }
146
147    pub fn read_byte(&self, idx: u8) -> Option<u8> {
148        let r = uart_regs(idx);
149        if r.fifo_status().read().rx_fifo_empty().bit_is_set() { None } else { Some(r.data().read().bits() as u8) }
150    }
151
152    pub fn flush_tx(&self, idx: u8) {
153        let r = uart_regs(idx);
154        while !r.fifo_status().read().tx_fifo_empty().bit_is_set() {}
155    }
156
157    /// Non-blocking check: returns true if TX FIFO is fully drained.
158    pub fn tx_flushed(&self, idx: u8) -> bool {
159        uart_regs(idx).fifo_status().read().tx_fifo_empty().bit_is_set()
160    }
161
162    pub fn write(&self, idx: u8, data: &[u8]) {
163        for &b in data {
164            self.write_byte(idx, b);
165        }
166    }
167
168    pub fn uart_regs(&self, idx: u8) -> &'static ws63_pac::uart0::RegisterBlock {
169        uart_regs(idx)
170    }
171}
172
173impl embedded_io::ErrorType for Uart<'_, Uart0<'_>> {
174    type Error = core::convert::Infallible;
175}
176impl embedded_io::Write for Uart<'_, Uart0<'_>> {
177    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
178        for &b in buf {
179            self.write_byte(0, b);
180        }
181        Ok(buf.len())
182    }
183    fn flush(&mut self) -> Result<(), Self::Error> {
184        self.flush_tx(0);
185        Ok(())
186    }
187}
188impl embedded_io::Read for Uart<'_, Uart0<'_>> {
189    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
190        let mut n = 0;
191        for b in buf.iter_mut() {
192            if let Some(byte) = self.read_byte(0) {
193                *b = byte;
194                n += 1;
195            } else {
196                break;
197            }
198        }
199        Ok(n)
200    }
201}
202
203// UART1 embedded-io traits
204impl embedded_io::ErrorType for Uart<'_, Uart1<'_>> {
205    type Error = core::convert::Infallible;
206}
207impl embedded_io::Write for Uart<'_, Uart1<'_>> {
208    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
209        for &b in buf {
210            self.write_byte(1, b);
211        }
212        Ok(buf.len())
213    }
214    fn flush(&mut self) -> Result<(), Self::Error> {
215        self.flush_tx(1);
216        Ok(())
217    }
218}
219impl embedded_io::Read for Uart<'_, Uart1<'_>> {
220    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
221        let mut n = 0;
222        for b in buf.iter_mut() {
223            if let Some(byte) = self.read_byte(1) {
224                *b = byte;
225                n += 1;
226            } else {
227                break;
228            }
229        }
230        Ok(n)
231    }
232}
233
234// UART2 embedded-io traits
235impl embedded_io::ErrorType for Uart<'_, Uart2<'_>> {
236    type Error = core::convert::Infallible;
237}
238impl embedded_io::Write for Uart<'_, Uart2<'_>> {
239    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
240        for &b in buf {
241            self.write_byte(2, b);
242        }
243        Ok(buf.len())
244    }
245    fn flush(&mut self) -> Result<(), Self::Error> {
246        self.flush_tx(2);
247        Ok(())
248    }
249}
250impl embedded_io::Read for Uart<'_, Uart2<'_>> {
251    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
252        let mut n = 0;
253        for b in buf.iter_mut() {
254            if let Some(byte) = self.read_byte(2) {
255                *b = byte;
256                n += 1;
257            } else {
258                break;
259            }
260        }
261        Ok(n)
262    }
263}
264
265// ── embedded-hal-nb serial traits ──────────────────────────────
266
267macro_rules! impl_nb_serial {
268    ($uart:ty, $idx:expr) => {
269        impl embedded_hal_nb::serial::ErrorType for Uart<'_, $uart> {
270            type Error = core::convert::Infallible;
271        }
272        impl embedded_hal_nb::serial::Read for Uart<'_, $uart> {
273            fn read(&mut self) -> nb::Result<u8, Self::Error> {
274                match self.read_byte($idx) {
275                    Some(b) => Ok(b),
276                    None => Err(nb::Error::WouldBlock),
277                }
278            }
279        }
280        impl embedded_hal_nb::serial::Write for Uart<'_, $uart> {
281            fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
282                self.write_byte($idx, byte);
283                Ok(())
284            }
285            fn flush(&mut self) -> nb::Result<(), Self::Error> {
286                if self.tx_flushed($idx) { Ok(()) } else { Err(nb::Error::WouldBlock) }
287            }
288        }
289    };
290}
291
292impl_nb_serial!(Uart0<'_>, 0);
293impl_nb_serial!(Uart1<'_>, 1);
294impl_nb_serial!(Uart2<'_>, 2);
295
296// ── Async UART (embedded-io-async) ──────────────────────────────────────────
297#[cfg(feature = "async")]
298mod asynch_impl {
299    use super::{Uart, uart_regs};
300    use crate::asynch::IrqSignal;
301    use crate::peripherals::{Uart0, Uart1, Uart2};
302    use core::cell::Cell;
303    use core::future::Future;
304    use core::pin::Pin;
305    use core::task::{Context, Poll};
306    use critical_section::Mutex;
307    use embedded_io_async::{Read, Write};
308
309    static UART_RX: [IrqSignal; 3] = [IrqSignal::new(), IrqSignal::new(), IrqSignal::new()];
310    static UART_BYTE: [Mutex<Cell<u8>>; 3] = [const { Mutex::new(Cell::new(0)) }; 3];
311
312    fn uart_base(idx: u8) -> usize {
313        match idx {
314            0 => 0x4401_0000,
315            1 => 0x4401_1000,
316            _ => 0x4401_2000,
317        }
318    }
319
320    /// UART trap hook: read the received byte (which de-asserts the RX IRQ) and
321    /// wake the awaiting reader. Call from the trap when `mcause` is UART0..2_INT
322    /// (IRQ 53..55). Reading in the ISR avoids a level-triggered RX storm.
323    pub fn on_interrupt(idx: u8) {
324        let r = uart_regs(idx);
325        if !r.fifo_status().read().rx_fifo_empty().bit_is_set() {
326            let b = r.data().read().bits() as u8;
327            critical_section::with(|cs| UART_BYTE[idx as usize].borrow(cs).set(b));
328            UART_RX[idx as usize].signal();
329        }
330    }
331
332    struct RxFuture {
333        idx: u8,
334    }
335    impl Future for RxFuture {
336        type Output = ();
337        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
338            if UART_RX[self.idx as usize].take_fired() {
339                Poll::Ready(())
340            } else {
341                UART_RX[self.idx as usize].register(cx.waker());
342                Poll::Pending
343            }
344        }
345    }
346
347    async fn read_one(uart: &Uart<'_, impl Sized>, idx: u8) -> u8 {
348        let r = uart_regs(idx);
349        if !r.fifo_status().read().rx_fifo_empty().bit_is_set() {
350            return r.data().read().bits() as u8; // byte already waiting
351        }
352        UART_RX[idx as usize].reset();
353        // Enable the UART RX interrupt (INTR_EN @ +0x18) so a byte raises the IRQ.
354        unsafe { core::ptr::write_volatile((uart_base(idx) + 0x18) as *mut u32, 1) };
355        let _ = uart; // keep the &Uart borrow for the await's lifetime
356        RxFuture { idx }.await;
357        critical_section::with(|cs| UART_BYTE[idx as usize].borrow(cs).get())
358    }
359
360    macro_rules! async_uart {
361        ($uart:ty, $idx:expr) => {
362            // embedded_io::ErrorType is already implemented for the blocking impls;
363            // the async Read/Write traits reuse it.
364            impl Write for Uart<'_, $uart> {
365                async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
366                    // WS63 UART TX drains immediately on this model; write_byte polls
367                    // tx_fifo_full, so this completes without parking.
368                    for &b in buf {
369                        self.write_byte($idx, b);
370                    }
371                    Ok(buf.len())
372                }
373                async fn flush(&mut self) -> Result<(), Self::Error> {
374                    self.flush_tx($idx);
375                    Ok(())
376                }
377            }
378            impl Read for Uart<'_, $uart> {
379                async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
380                    if buf.is_empty() {
381                        return Ok(0);
382                    }
383                    buf[0] = read_one(self, $idx).await;
384                    Ok(1)
385                }
386            }
387        };
388    }
389    async_uart!(Uart0<'_>, 0);
390    async_uart!(Uart1<'_>, 1);
391    async_uart!(Uart2<'_>, 2);
392}
393
394#[cfg(feature = "async")]
395pub use asynch_impl::on_interrupt;