lpc55s6x_hal/drivers/
serial.rs

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