lpc55_hal/drivers/
serial.rs

1use core::fmt;
2use core::marker::PhantomData;
3use core::ops::Deref;
4
5use crate::{
6    time::Hertz,
7    traits::wg::serial,
8    typestates::pin::{
9        flexcomm::{
10            // Trait marking USART peripherals and pins
11            Usart,
12            UsartPins,
13        },
14        PinId,
15    },
16};
17
18pub mod config;
19
20/// Serial error
21#[derive(Debug)]
22#[non_exhaustive]
23pub enum Error {
24    /// Framing error
25    Framing,
26    /// Noise error
27    Noise,
28    /// RX buffer overrun
29    Overrun,
30    /// Parity check error
31    Parity,
32}
33
34// /// Interrupt event
35// pub enum Event {
36//     /// New data has been received
37//     Rxne,
38//     /// New data can be sent
39//     Txe,
40//     /// Idle line state detected
41//     Idle,
42// }
43
44/// USART peripheral operating as serial
45pub struct Serial<TX, RX, USART, PINS>
46where
47    TX: PinId,
48    RX: PinId,
49    USART: Usart,
50    PINS: UsartPins<TX, RX, USART>,
51{
52    usart: USART,
53    pins: PINS,
54    _tx: PhantomData<TX>,
55    _rx: PhantomData<RX>,
56}
57
58// such a Serial can be split() into (Tx, Rx)
59
60// TODO: Consider removing the USART parameter from Tx and Rx
61// TODO: Remove code duplication between Tx and Rx
62
63/// Serial transmitter
64pub struct Tx<USART: Usart> {
65    addr: usize,
66    _usart: PhantomData<USART>,
67}
68
69/// Serial receiver
70pub struct Rx<USART: Usart> {
71    addr: usize,
72    _usart: PhantomData<USART>,
73}
74
75impl<USART: Usart> Deref for Tx<USART> {
76    type Target = raw::usart0::RegisterBlock;
77    fn deref(&self) -> &Self::Target {
78        let ptr = self.addr as *const _;
79        unsafe { &*ptr }
80    }
81}
82
83impl<USART: Usart> Deref for Rx<USART> {
84    type Target = raw::usart0::RegisterBlock;
85    fn deref(&self) -> &Self::Target {
86        let ptr = self.addr as *const _;
87        unsafe { &*ptr }
88    }
89}
90
91impl<TX, RX, USART, PINS> Serial<TX, RX, USART, PINS>
92where
93    TX: PinId,
94    RX: PinId,
95    USART: Usart,
96    PINS: UsartPins<TX, RX, USART>,
97{
98    const CLOCK_SPEED: u32 = 12_000_000;
99
100    pub fn new(usart: USART, pins: PINS, config: config::Config) -> Self {
101        use self::config::*;
102
103        let speed: Hertz = config.speed;
104        let speed: u32 = speed.0;
105
106        usart
107            .fifocfg
108            .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
109
110        usart.fifotrig.modify(|_, w| unsafe {
111            w.txlvl()
112                .bits(0)
113                .txlvlena()
114                .enabled()
115                .rxlvl()
116                .bits(1)
117                .rxlvlena()
118                .enabled()
119        });
120
121        usart.cfg.write(|w| unsafe {
122            w.paritysel()
123                .bits(match config.parity {
124                    Parity::ParityNone => 0,
125                    Parity::ParityEven => 2,
126                    Parity::ParityOdd => 3,
127                })
128                .stoplen()
129                .bit(match config.stopbits {
130                    StopBits::STOP1 => false,
131                    StopBits::STOP2 => true,
132                })
133                .datalen()
134                .bits(match config.wordlength {
135                    WordLength::DataBits7 => 0,
136                    WordLength::DataBits8 => 1,
137                    WordLength::DataBits9 => 2,
138                })
139                // these are just some defaults (of zero)
140                // loopback mode
141                .loop_()
142                .normal()
143                // asynch mode
144                .syncen()
145                .asynchronous_mode()
146                // polarity
147                .clkpol()
148                .falling_edge()
149                // enable it
150                .enable()
151                .enabled()
152        });
153
154        // baudrate logic from `fsl_usart.c` in SDK
155        let mut best_diff = !0;
156        let mut best_osr = 15;
157        let mut best_brg = !0;
158
159        // SDK says: "Smaller values of OSR can make the sampling position within a data bit less
160        // accurate and may potentially cause more noise errors or incorrect data."
161        for osr in (9..=16).rev() {
162            let brg = Self::CLOCK_SPEED / (osr * speed);
163            if brg >= 0xffff {
164                continue;
165            }
166            let realized_speed = Self::CLOCK_SPEED / (osr * brg);
167            let diff = if speed > realized_speed {
168                speed - realized_speed
169            } else {
170                realized_speed - speed
171            };
172            if diff < best_diff {
173                best_diff = diff;
174                best_osr = osr;
175                best_brg = brg;
176            }
177        }
178
179        // TODO: return Result instead of panicking
180        if best_brg >= 0xffff {
181            panic!("baudrate not supported");
182        }
183
184        usart
185            .brg
186            .write(|w| unsafe { w.brgval().bits(best_brg as u16 - 1) });
187        usart
188            .osr
189            .write(|w| unsafe { w.osrval().bits(best_osr as u8 - 1) });
190
191        Self {
192            usart,
193            pins,
194            _tx: PhantomData,
195            _rx: PhantomData,
196        }
197    }
198
199    fn addr(&self) -> usize {
200        &(*self.usart) as *const _ as usize
201    }
202
203    pub fn split(self) -> (Tx<USART>, Rx<USART>) {
204        // so umm... Tx/Rx "promise" to not step on each others' toes
205        //
206        // Tx:
207        // - reads stat, fifostat
208        // - writes fifowr
209        //
210        // Rx:
211        // - reads fifostat and fiford
212        // - modifies fifocfg + fifostat on buffer overflow
213
214        (
215            Tx {
216                addr: self.addr(),
217                _usart: PhantomData,
218            },
219            Rx {
220                addr: self.addr(),
221                _usart: PhantomData,
222            },
223        )
224    }
225
226    pub fn release(self) -> (USART, PINS) {
227        (self.usart, self.pins)
228    }
229}
230
231impl<TX, RX, USART, PINS> serial::Read<u8> for Serial<TX, RX, USART, PINS>
232where
233    TX: PinId,
234    RX: PinId,
235    USART: Usart,
236    PINS: UsartPins<TX, RX, USART>,
237{
238    type Error = Error;
239
240    fn read(&mut self) -> nb::Result<u8, Error> {
241        let mut rx: Rx<USART> = Rx {
242            addr: self.addr(),
243            _usart: PhantomData,
244        };
245        rx.read()
246    }
247}
248
249impl<USART: Usart> serial::Read<u8> for Rx<USART> {
250    type Error = Error;
251
252    fn read(&mut self) -> nb::Result<u8, Error> {
253        let fifostat = self.fifostat.read();
254
255        if fifostat.rxnotempty().bit() {
256            // SDK uses stat, and e.g. framerrint instead of framerr,
257            // but that's not in the SDK
258            let fiford = self.fiford.read();
259
260            if fiford.framerr().bit_is_set() {
261                return Err(nb::Error::Other(Error::Framing));
262            }
263
264            if fiford.parityerr().bit_is_set() {
265                return Err(nb::Error::Other(Error::Parity));
266            }
267
268            if fiford.rxnoise().bit_is_set() {
269                return Err(nb::Error::Other(Error::Noise));
270            }
271
272            if fifostat.rxerr().bit_is_set() {
273                // clear by writing 1
274                self.fifocfg.modify(|_, w| w.emptyrx().set_bit());
275                self.fifostat.modify(|_, w| w.rxerr().set_bit());
276                return Err(nb::Error::Other(Error::Overrun));
277            }
278
279            Ok(fiford.rxdata().bits() as u8)
280        } else {
281            // cortex_m_semihosting::hprintln!("not rxnotempty").ok();
282            Err(nb::Error::WouldBlock)
283        }
284    }
285}
286
287impl<TX, RX, USART, PINS> serial::Write<u8> for Serial<TX, RX, USART, PINS>
288where
289    TX: PinId,
290    RX: PinId,
291    USART: Usart,
292    PINS: UsartPins<TX, RX, USART>,
293{
294    type Error = Error;
295
296    fn flush(&mut self) -> nb::Result<(), Self::Error> {
297        let mut tx: Tx<USART> = Tx {
298            addr: self.addr(),
299            _usart: PhantomData,
300        };
301        tx.flush()
302    }
303
304    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
305        let mut tx: Tx<USART> = Tx {
306            addr: self.addr(),
307            _usart: PhantomData,
308        };
309        tx.write(byte)
310    }
311}
312
313impl<USART: Usart> serial::Write<u8> for Tx<USART> {
314    type Error = Error;
315
316    fn flush(&mut self) -> nb::Result<(), Self::Error> {
317        if self.stat.read().txidle().bit() {
318            Ok(())
319        } else {
320            Err(nb::Error::WouldBlock)
321        }
322    }
323
324    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
325        if self.fifostat.read().txnotfull().bit() {
326            // TODO: figure out if we need to perform an 8-bit write
327            // This would not be possible via svd2rust API, and need some acrobatics
328            self.fifowr.write(|w| unsafe { w.bits(byte as u32) });
329
330            Ok(())
331        } else {
332            Err(nb::Error::WouldBlock)
333        }
334    }
335}
336
337impl<USART: Usart> fmt::Write for Tx<USART>
338where
339    Tx<USART>: serial::Write<u8>,
340{
341    fn write_str(&mut self, s: &str) -> fmt::Result {
342        use crate::traits::wg::serial::Write;
343        let _ = s
344            .as_bytes()
345            .iter()
346            .map(|c| nb::block!(self.write(*c)))
347            .last();
348        Ok(())
349    }
350}