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}