bl702_hal/
uart.rs

1//! UART driver
2//!
3//! Only supports UART0. Only supports 2MBaud.
4use crate::clock::Clocks;
5use crate::pac;
6use core::fmt;
7use embedded_hal::serial::nb::Read as ReadOne;
8use embedded_hal::serial::nb::Write as WriteOne;
9use embedded_time::rate::{Baud, Extensions};
10use nb::block;
11
12/// UART error
13#[derive(Debug)]
14#[non_exhaustive]
15pub enum Error {
16    /// Framing error
17    Framing,
18    /// Noise error
19    Noise,
20    /// RX buffer overrun
21    Overrun,
22    /// Parity check error
23    Parity,
24}
25
26/// Serial configuration
27#[derive(Copy, Clone, Debug, PartialEq)]
28pub struct Config {
29    pub baudrate: Baud,
30    pub order: Order,
31    pub parity: Parity,
32    pub stopbits: StopBits,
33    pub wordlength: WordLength,
34}
35
36impl Config {
37    /// Sets the target baudrate
38    pub fn baudrate(mut self, baudrate: impl Into<Baud>) -> Self {
39        self.baudrate = baudrate.into();
40
41        self
42    }
43
44    /// Sets parity to no parity check
45    pub fn parity_none(mut self) -> Self {
46        self.parity = Parity::ParityNone;
47
48        self
49    }
50
51    /// Sets parity check to even
52    pub fn parity_even(mut self) -> Self {
53        self.parity = Parity::ParityEven;
54
55        self
56    }
57
58    /// Sets parity check to odd
59    pub fn parity_odd(mut self) -> Self {
60        self.parity = Parity::ParityOdd;
61
62        self
63    }
64
65    /// Sets the target stopbits
66    pub fn stopbits(mut self, stopbits: StopBits) -> Self {
67        self.stopbits = stopbits;
68
69        self
70    }
71}
72
73impl Default for Config {
74    fn default() -> Config {
75        Config {
76            baudrate: 115_200_u32.Bd(),
77            order: Order::LsbFirst,
78            parity: Parity::ParityNone,
79            stopbits: StopBits::STOP1,
80            wordlength: WordLength::Eight,
81        }
82    }
83}
84
85/// Order of the bits transmitted and received on the wire
86#[derive(Debug, Copy, Clone, Eq, PartialEq)]
87pub enum Order {
88    /// Each byte is sent out LSB-first
89    LsbFirst,
90    /// Each byte is sent out MSB-first
91    MsbFirst,
92}
93
94/// Parity check
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum Parity {
97    /// No parity check
98    ParityNone,
99    /// Even parity bit
100    ParityEven,
101    /// Odd parity bit
102    ParityOdd,
103}
104
105/// Stop bits
106#[derive(Copy, Clone, Debug, PartialEq, Eq)]
107pub enum StopBits {
108    /// 1 stop bit
109    STOP1,
110    /// 0.5 stop bits
111    STOP0P5,
112    /// 2 stop bits
113    STOP2,
114    /// 1.5 stop bits
115    STOP1P5,
116}
117
118/// Word length
119#[derive(Copy, Clone, Debug, PartialEq, Eq)]
120pub enum WordLength {
121    Five,
122    Six,
123    Seven,
124    Eight,
125}
126
127/// Interrupt event
128pub enum Event {
129    /// UART RX FIFO error interrupt
130    RxFifoError,
131    /// UART TX FIFO error interrupt
132    TxFifoError,
133    /// UART RX parity check error interrupt
134    RxParityError,
135    /// UART RX Time-out interrupt
136    RxTimeout,
137    /// UART RX FIFO ready (rx_fifo_cnt > rx_fifo_th) interrupt
138    RxFifoReady,
139    /// UART TX FIFO ready (tx_fifo_cnt > tx_fifo_th) interrupt
140    TxFifoReady,
141    /// UART RX transfer end interrupt
142    RxTransferEnd,
143    /// UART TX transfer end interrupt
144    TxTransferEnd,
145}
146
147/// Serial abstraction
148pub struct Serial<UART, PINS> {
149    uart: UART,
150    pins: PINS,
151}
152
153impl<PINS> Serial<pac::UART, PINS>
154where
155    PINS: Pins<pac::UART>,
156{
157    // todo: there is UART0 and UART1
158    // todo: use clocks
159    pub fn uart0(uart: pac::UART, config: Config, pins: PINS, _clocks: Clocks) -> Self {
160        // Initialize clocks and baudrate
161        // let uart_clk = clocks.uart_clk();
162        // let mut baud = config.baudrate.0;
163        let divisor = 48; // bring uart down from 96MHz to 2Mhz
164
165        // Disable uart first
166        uart.utx_config.modify(|_, w| w.cr_utx_en().clear_bit());
167        uart.urx_config.modify(|_, w| w.cr_urx_en().clear_bit());
168
169        uart.uart_bit_prd.write(|w| unsafe {
170            w.cr_urx_bit_prd()
171                .bits(divisor - 1)
172                .cr_utx_bit_prd()
173                .bits(divisor - 1)
174        });
175
176        // Bit inverse configuration; MsbFirst => 1, LsbFirst => 0
177        let order_cfg = match config.order {
178            Order::LsbFirst => false,
179            Order::MsbFirst => true,
180        };
181
182        uart.data_config
183            .write(|w| w.cr_uart_bit_inv().bit(order_cfg));
184
185        // UART TX config
186        let data_bits_cfg = match config.wordlength {
187            WordLength::Five => 4,
188            WordLength::Six => 5,
189            WordLength::Seven => 6,
190            WordLength::Eight => 7,
191        };
192        let stop_bits_cfg = match config.stopbits {
193            StopBits::STOP0P5 => 0,
194            StopBits::STOP1 => 1,
195            StopBits::STOP1P5 => 2,
196            StopBits::STOP2 => 3,
197        };
198        let (parity_enable, parity_type) = match config.parity {
199            Parity::ParityNone => (false, false),
200            Parity::ParityEven => (true, false), // even => 0
201            Parity::ParityOdd => (true, true),   // odd => 1
202        };
203
204        uart.utx_config.write(|w| unsafe {
205            w.cr_utx_prt_en().bit(parity_enable);
206            w.cr_utx_prt_sel().bit(parity_type);
207            w.cr_utx_bit_cnt_d().bits(data_bits_cfg);
208            w.cr_utx_bit_cnt_p().bits(stop_bits_cfg);
209            w.cr_utx_frm_en().set_bit(); // [!] freerun on // todo
210            w.cr_utx_cts_en().bit(false); // force CTS off for testing
211            w
212        });
213        uart.utx_config
214            .modify(|_, w| w.cr_utx_en().bit(PINS::HAS_TX));
215
216        // UART RX config
217        uart.urx_config.write(|w| unsafe {
218            w.cr_urx_prt_en().bit(parity_enable);
219            w.cr_urx_prt_sel().bit(parity_type);
220            w.cr_urx_bit_cnt_d().bits(data_bits_cfg);
221            w.cr_urx_deg_en().clear_bit();
222            // no rx input de-glitch // todo
223            // .cr_urx_rts_sw_mode()
224            // .clear_bit() // no RTS // todo
225            w.cr_urx_en().bit(PINS::HAS_RX);
226            w
227        });
228
229        uart.urx_config
230            .modify(|_, w| unsafe { w.cr_urx_deg_cnt().bits(15) });
231
232        Serial { uart, pins }
233    }
234
235    pub fn free(self) -> (pac::UART, PINS) {
236        // todo!
237        (self.uart, self.pins)
238    }
239}
240
241impl<PINS> embedded_hal::serial::nb::Write<u8> for Serial<pac::UART, PINS> {
242    type Error = Error;
243
244    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
245        // If there's no room to write a byte or more to the FIFO, return WouldBlock
246        if self.uart.uart_fifo_config_1.read().tx_fifo_cnt().bits() == 0 {
247            Err(nb::Error::WouldBlock)
248        } else {
249            self.uart
250                .uart_fifo_wdata
251                .write(|w| unsafe { w.bits(word as u32) });
252            Ok(())
253        }
254    }
255
256    fn flush(&mut self) -> nb::Result<(), Self::Error> {
257        // If we're still transmitting or have data in our 32 byte FIFO, return WouldBlock
258        if self.uart.uart_fifo_config_1.read().tx_fifo_cnt().bits() != 32
259            || self.uart.uart_status.read().sts_utx_bus_busy().bit_is_set()
260        {
261            Err(nb::Error::WouldBlock)
262        } else {
263            Ok(())
264        }
265    }
266}
267
268impl<PINS> embedded_hal::serial::nb::Read<u8> for Serial<pac::UART, PINS> {
269    type Error = Error;
270
271    fn read(&mut self) -> nb::Result<u8, Self::Error> {
272        if self.uart.uart_fifo_config_1.read().rx_fifo_cnt().bits() == 0 {
273            Err(nb::Error::WouldBlock)
274        } else {
275            let ans = self.uart.uart_fifo_rdata.read().bits();
276            Ok((ans & 0xff) as u8)
277        }
278    }
279}
280
281impl<PINS> embedded_hal_zero::serial::Write<u8> for Serial<pac::UART, PINS> {
282    type Error = Error;
283
284    fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
285        WriteOne::write(self, word)
286    }
287
288    fn flush(&mut self) -> nb::Result<(), Self::Error> {
289        WriteOne::flush(self)
290    }
291}
292
293impl<PINS> embedded_hal_zero::serial::Read<u8> for Serial<pac::UART, PINS> {
294    type Error = Error;
295
296    fn read(&mut self) -> nb::Result<u8, Self::Error> {
297        ReadOne::read(self)
298    }
299}
300
301impl<UART, PINS> fmt::Write for Serial<UART, PINS>
302where
303    Serial<UART, PINS>: embedded_hal::serial::nb::Write<u8>,
304{
305    fn write_str(&mut self, s: &str) -> fmt::Result {
306        s.as_bytes()
307            .iter()
308            .try_for_each(|c| block!(self.write(*c)))
309            .map_err(|_| fmt::Error)
310    }
311}
312
313// TODO: make these sealed instead of unsafe
314/// Serial transmit pins - DO NOT IMPLEMENT THIS TRAIT
315pub unsafe trait TxPin<UART> {}
316/// Serial receive pins - DO NOT IMPLEMENT THIS TRAIT
317pub unsafe trait RxPin<UART> {}
318/// Serial rts pins - DO NOT IMPLEMENT THIS TRAIT
319pub unsafe trait RtsPin<UART> {}
320/// Serial cts pins - DO NOT IMPLEMENT THIS TRAIT
321pub unsafe trait CtsPin<UART> {}
322
323macro_rules! impl_uart_pin {
324    ($(($UartSigi: ident, $UartMuxi: ident),)+) => {
325        use crate::gpio::*;
326        $(
327        unsafe impl<PIN: UartPin<$UartSigi>> TxPin<pac::UART> for (PIN, $UartMuxi<Uart0Tx>) {}
328        unsafe impl<PIN: UartPin<$UartSigi>> RxPin<pac::UART> for (PIN, $UartMuxi<Uart0Rx>) {}
329        unsafe impl<PIN: UartPin<$UartSigi>> RtsPin<pac::UART> for (PIN, $UartMuxi<Uart0Rts>) {}
330        unsafe impl<PIN: UartPin<$UartSigi>> CtsPin<pac::UART> for (PIN, $UartMuxi<Uart0Cts>) {}
331        )+
332    };
333}
334
335impl_uart_pin!(
336    (UartSig0, UartMux0),
337    (UartSig1, UartMux1),
338    (UartSig2, UartMux2),
339    (UartSig3, UartMux3),
340    (UartSig4, UartMux4),
341    (UartSig5, UartMux5),
342    (UartSig6, UartMux6),
343    (UartSig7, UartMux7),
344);
345
346/// Serial pins - DO NOT IMPLEMENT THIS TRAIT
347// TODO: make these sealed instead of unsafe
348pub unsafe trait Pins<UART> {
349    const HAS_TX: bool;
350    const HAS_RX: bool;
351    const HAS_RTS: bool;
352    const HAS_CTS: bool;
353}
354
355unsafe impl<UART, TX, RX> Pins<UART> for (TX, RX)
356where
357    TX: TxPin<UART>,
358    RX: RxPin<UART>,
359{
360    const HAS_TX: bool = true;
361    const HAS_RX: bool = true;
362    const HAS_RTS: bool = false;
363    const HAS_CTS: bool = false;
364}
365
366unsafe impl<UART, TX, RX, RTS, CTS> Pins<UART> for (TX, RX, RTS, CTS)
367where
368    TX: TxPin<UART>,
369    RX: RxPin<UART>,
370    RTS: RxPin<UART>,
371    CTS: RxPin<UART>,
372{
373    const HAS_TX: bool = true;
374    const HAS_RX: bool = true;
375    const HAS_RTS: bool = true;
376    const HAS_CTS: bool = true;
377}