lpc8xx_hal/usart/
rx.rs

1use core::marker::PhantomData;
2
3use cortex_m::interrupt;
4use void::Void;
5
6use crate::{
7    dma::{self, transfer::state::Ready},
8    embedded_hal::serial::Read,
9    init_state,
10    pac::dma0::channel::xfercfg::SRCINC_A,
11};
12
13use super::{
14    flags::{Flag, Interrupts},
15    instances::Instance,
16    state::{Enabled, Word},
17};
18
19/// USART receiver
20///
21/// Can be accessed through [`USART`].
22///
23/// # `embedded-hal` traits
24/// - [`embedded_hal::serial::Read`] for non-blocking reads
25///
26///
27/// [`USART`]: struct.USART.html
28/// [`embedded_hal::serial::Read`]: #impl-Read<W>
29pub struct Rx<I, State> {
30    _instance: PhantomData<I>,
31    _state: PhantomData<State>,
32}
33
34impl<I, State> Rx<I, State>
35where
36    I: Instance,
37{
38    pub(super) fn new() -> Self {
39        Self {
40            _instance: PhantomData,
41            _state: PhantomData,
42        }
43    }
44}
45
46impl<I, W, Mode> Rx<I, Enabled<W, Mode>>
47where
48    I: Instance,
49    W: Word,
50{
51    /// Put the receiver into address detection mode
52    ///
53    /// After this method is called, all received data that does not have the
54    /// most significant bit set will be ignored. Data that does have the most
55    /// significant bit set will be matched against the provided address.
56    ///
57    /// While the receiver is operating that way, only matched addresses will be
58    /// received. Once you have received a matched address and inspected it to
59    /// your satisfaction, you must call `stop_address_detection` to start
60    /// receiving regular data again.
61    ///
62    /// You can call this method multiple times, without calling
63    /// `stop_address_detection` in between. The only effect this has, is to
64    /// change the address that is being matched to the one provided by the most
65    /// recent call.
66    pub fn start_address_detection(&mut self, address: u8) {
67        // This is sound, as we have exclusive access to the ADDR register and
68        // access to CTL is protected by a critical section.
69        let usart = unsafe { &*I::REGISTERS };
70
71        // Store address.
72        usart.addr.write(|w| {
73            // Sound, as the field accepts all possible values of `u8`.
74            unsafe { w.address().bits(address) }
75        });
76
77        interrupt::free(|_| {
78            // Enable address detection.
79            usart.ctl.modify(|_, w| w.addrdet().enabled());
80        });
81
82        // Don't need to set CFG.AUTOADDR. This is already done automatically on
83        // initialization.
84    }
85
86    /// Put the receiver out of address detection mode
87    ///
88    /// After you've put the receiver into address detection mode using the
89    /// `start_address_detection` method, you can start receiving data normally
90    /// again by calling this method. Typically you would do this after
91    /// receiving a matched address.
92    ///
93    /// Calling this method while the receiver is not in address detection mode
94    /// has no effect.
95    pub fn stop_address_detection(&mut self) {
96        // This is sound, access to CTL is protected by a critical section.
97        let usart = unsafe { &*I::REGISTERS };
98
99        interrupt::free(|_| {
100            // Disable address detection.
101            usart.ctl.modify(|_, w| w.addrdet().disabled());
102        });
103    }
104
105    /// Query whether the provided flag is set
106    ///
107    /// Flags that need to be reset by software will be reset by this operation.
108    pub fn is_flag_set(&self, flag: Flag) -> bool {
109        flag.is_set::<I>()
110    }
111
112    /// Enable interrupts
113    ///
114    /// Enables all interrupts set to `true` in `interrupts`. Interrupts set to
115    /// `false` are not affected.
116    ///
117    /// # Example
118    ///
119    /// ``` no_run
120    /// use lpc8xx_hal::usart;
121    ///
122    /// # use lpc8xx_hal::Peripherals;
123    /// #
124    /// # let mut p = Peripherals::take().unwrap();
125    /// #
126    /// # let mut syscon = p.SYSCON.split();
127    /// # let mut swm    = p.SWM.split();
128    /// #
129    /// # #[cfg(feature = "82x")]
130    /// # let mut swm_handle = swm.handle;
131    /// # #[cfg(feature = "845")]
132    /// # let mut swm_handle = swm.handle.enable(&mut syscon.handle);
133    /// #
134    /// # #[cfg(feature = "82x")]
135    /// # let clock_config = {
136    /// #     syscon.uartfrg.set_clkdiv(6);
137    /// #     syscon.uartfrg.set_frgmult(22);
138    /// #     syscon.uartfrg.set_frgdiv(0xff);
139    /// #     usart::Clock::new(&syscon.uartfrg, 0, 16)
140    /// # };
141    /// # #[cfg(feature = "845")]
142    /// # let clock_config = usart::Clock::new_with_baudrate(115200);
143    /// #
144    /// # let (u0_rxd, _) = swm.movable_functions.u0_rxd.assign(
145    /// #     p.pins.pio0_0.into_swm_pin(),
146    /// #     &mut swm_handle,
147    /// # );
148    /// # let (u0_txd, _) = swm.movable_functions.u0_txd.assign(
149    /// #     p.pins.pio0_4.into_swm_pin(),
150    /// #     &mut swm_handle,
151    /// # );
152    /// #
153    /// # let mut usart = p.USART0.enable_async(
154    /// #     &clock_config,
155    /// #     &mut syscon.handle,
156    /// #     u0_rxd,
157    /// #     u0_txd,
158    /// #     usart::Settings::default(),
159    /// # );
160    /// #
161    /// // Enable only RXRDY and TXRDY, leave other interrupts untouched.
162    /// usart.enable_interrupts(usart::Interrupts {
163    ///     RXRDY: true,
164    ///     TXRDY: true,
165    ///     .. usart::Interrupts::default()
166    /// });
167    /// ```
168    pub fn enable_interrupts(&mut self, interrupts: Interrupts) {
169        interrupts.enable::<I>();
170    }
171
172    /// Disable interrupts
173    ///
174    /// Disables all interrupts set to `true` in `interrupts`. Interrupts set to
175    /// `false` are not affected.
176    ///
177    /// # Example
178    ///
179    /// ``` no_run
180    /// use lpc8xx_hal::usart;
181    ///
182    /// # use lpc8xx_hal::Peripherals;
183    /// #
184    /// # let mut p = Peripherals::take().unwrap();
185    /// #
186    /// # let mut syscon = p.SYSCON.split();
187    /// # let mut swm    = p.SWM.split();
188    /// #
189    /// # #[cfg(feature = "82x")]
190    /// # let mut swm_handle = swm.handle;
191    /// # #[cfg(feature = "845")]
192    /// # let mut swm_handle = swm.handle.enable(&mut syscon.handle);
193    /// #
194    /// # #[cfg(feature = "82x")]
195    /// # let clock_config = {
196    /// #     syscon.uartfrg.set_clkdiv(6);
197    /// #     syscon.uartfrg.set_frgmult(22);
198    /// #     syscon.uartfrg.set_frgdiv(0xff);
199    /// #     usart::Clock::new(&syscon.uartfrg, 0, 16)
200    /// # };
201    /// # #[cfg(feature = "845")]
202    /// # let clock_config = usart::Clock::new_with_baudrate(115200);
203    /// #
204    /// # let (u0_rxd, _) = swm.movable_functions.u0_rxd.assign(
205    /// #     p.pins.pio0_0.into_swm_pin(),
206    /// #     &mut swm_handle,
207    /// # );
208    /// # let (u0_txd, _) = swm.movable_functions.u0_txd.assign(
209    /// #     p.pins.pio0_4.into_swm_pin(),
210    /// #     &mut swm_handle,
211    /// # );
212    /// #
213    /// # let mut usart = p.USART0.enable_async(
214    /// #     &clock_config,
215    /// #     &mut syscon.handle,
216    /// #     u0_rxd,
217    /// #     u0_txd,
218    /// #     usart::Settings::default(),
219    /// # );
220    /// #
221    /// // Disable only RXRDY and TXRDY, leave other interrupts untouched.
222    /// usart.disable_interrupts(usart::Interrupts {
223    ///     RXRDY: true,
224    ///     TXRDY: true,
225    ///     .. usart::Interrupts::default()
226    /// });
227    /// ```
228    pub fn disable_interrupts(&mut self, interrupts: Interrupts) {
229        interrupts.disable::<I>();
230    }
231}
232
233impl<I, Mode> Rx<I, Enabled<u8, Mode>>
234where
235    I: Instance,
236{
237    /// Reads until the provided buffer is full, using DMA
238    ///
239    /// # Panics
240    ///
241    /// Panics, if the length of `buffer` is 0 or larger than 1024.
242    pub fn read_all(
243        self,
244        buffer: &'static mut [u8],
245        channel: dma::Channel<I::RxChannel, init_state::Enabled>,
246    ) -> dma::Transfer<Ready, I::RxChannel, Self, &'static mut [u8]> {
247        dma::Transfer::new(channel, self, buffer)
248    }
249}
250
251impl<I, W, Mode> Read<W> for Rx<I, Enabled<W, Mode>>
252where
253    I: Instance,
254    W: Word,
255{
256    type Error = Error<W>;
257
258    fn read(&mut self) -> nb::Result<W, Self::Error> {
259        // Sound, as we're only reading from `stat`, and `rxdatstat` is
260        // exclusively accessed by this method.
261        let usart = unsafe { &*I::REGISTERS };
262
263        let stat = usart.stat.read();
264
265        if stat.rxbrk().bit_is_set() {
266            return Err(nb::Error::WouldBlock);
267        }
268
269        if stat.rxrdy().bit_is_set() {
270            // It's important to read this register all at once, as reading
271            // it changes the status flags.
272            let rx_dat_stat = usart.rxdatstat.read();
273
274            let word = Word::from_u16(rx_dat_stat.rxdat().bits());
275
276            if stat.overrunint().bit_is_set() {
277                usart.stat.write(|w| w.overrunint().set_bit());
278                Err(nb::Error::Other(Error::Overrun(word)))
279            } else if rx_dat_stat.framerr().bit_is_set() {
280                usart.stat.write(|w| w.framerrint().set_bit());
281                Err(nb::Error::Other(Error::Framing(word)))
282            } else if rx_dat_stat.parityerr().bit_is_set() {
283                usart.stat.write(|w| w.parityerrint().set_bit());
284                Err(nb::Error::Other(Error::Parity(word)))
285            } else if rx_dat_stat.rxnoise().bit_is_set() {
286                usart.stat.write(|w| w.rxnoiseint().set_bit());
287                Err(nb::Error::Other(Error::Noise(word)))
288            } else {
289                Ok(word)
290            }
291        } else {
292            Err(nb::Error::WouldBlock)
293        }
294    }
295}
296
297impl<I, State> crate::private::Sealed for Rx<I, State> {}
298
299impl<I, Mode> dma::Source for Rx<I, Enabled<u8, Mode>>
300where
301    I: Instance,
302{
303    type Error = Void;
304
305    fn is_valid(&self) -> bool {
306        true
307    }
308
309    fn is_empty(&self) -> bool {
310        false
311    }
312
313    fn increment(&self) -> SRCINC_A {
314        SRCINC_A::NO_INCREMENT
315    }
316
317    fn transfer_count(&self) -> Option<u16> {
318        None
319    }
320
321    fn end_addr(&self) -> *const u8 {
322        // Sound, because we're dereferencing a register address that is always
323        // valid on the target hardware.
324        (unsafe { &(*I::REGISTERS).rxdat }) as *const _ as *mut u8
325    }
326
327    fn finish(&mut self) -> nb::Result<(), Self::Error> {
328        Ok(())
329    }
330}
331
332/// A USART error
333#[derive(Clone, Copy, Debug, Eq, PartialEq)]
334pub enum Error<Word> {
335    /// Character received with a stop bit missing at the expected location
336    Framing(Word),
337
338    /// Corrupted character received
339    Noise(Word),
340
341    /// Character received, while receive buffer was still in use
342    Overrun(Word),
343
344    /// Parity error detected in received character
345    Parity(Word),
346}