imxrt_hal/common/lpuart.rs
1//! Low-power universal asynchronous receiver / transmitter.
2//!
3//! Use the LPUART peripheral to perform reads and writes with a serial
4//! device. Features include
5//!
6//! - configurable baud rates (depends on input clock frequency)
7//! - parity bits: none, even, odd
8//! - inverted TX and RX lines
9//! - TX and RX FIFOs with configurable watermarks
10//! - DMA transfers and receives
11//! - Non-blocking and blocking implementations of `embedded-hal` serial
12//! traits.
13//!
14//! # Example
15//!
16//! Demonstrates how to create and configure an LPUART peripheral. To see an example
17//! of LPUART clock configuration, see the [`ccm::uart_clk`](crate::ccm::uart_clk) documentation.
18//! For more information on the DMA API, see the [`dma`](crate::dma) examples.
19//!
20//! ```no_run
21//! use imxrt_hal as hal;
22//! use hal::lpuart::{Baud, Direction, Lpuart, Parity, Pins, Status, Watermark};
23//! use imxrt_ral as ral;
24//! # use imxrt_iomuxc::imxrt1060 as iomuxc;
25//!
26//! # async fn opt() -> Option<()> {
27//! let (gpio_ad_b1_02, gpio_ad_b1_03) = // Handle to LPUART2 TX and RX pins...
28//! # unsafe { (iomuxc::gpio_ad_b1::GPIO_AD_B1_02::new(), iomuxc::gpio_ad_b1::GPIO_AD_B1_03::new()) };
29//! # const UART_CLKC_HZ: u32 = 1;
30//!
31//! let registers = unsafe { ral::lpuart::LPUART2::instance() };
32//! let pins = Pins { tx: gpio_ad_b1_02, rx: gpio_ad_b1_03 };
33//! let mut lpuart2 = Lpuart::with_pins(registers, pins);
34//!
35//! const BAUD: Baud = Baud::compute(UART_CLKC_HZ, 115200);
36//! lpuart2.disable(|lpuart2| {
37//! lpuart2.set_baud(&BAUD);
38//! lpuart2.set_parity(Parity::ODD);
39//! lpuart2.enable_fifo(Watermark::tx(4));
40//! lpuart2.disable_fifo(Direction::Rx);
41//! lpuart2.set_inversion(Direction::Rx, true);
42//! });
43//!
44//! // Fill the transmit FIFO with 0xAA...
45//! while lpuart2.status().contains(Status::TRANSMIT_EMPTY) {
46//! lpuart2.write_byte(0xAA);
47//! }
48//!
49//! // Schedule a DMA receive...
50//! # let mut dma_channel = unsafe { hal::dma::DMA.channel(13) };
51//! let mut buffer = [0u8; 64];
52//! lpuart2.dma_read(&mut dma_channel, &mut buffer)
53//! .await.ok()?;
54//! # Some(()) }
55//! ```
56
57use crate::iomuxc;
58use crate::ral;
59
60/// Any LPUART instance.
61type AnyInstance = crate::AnyInstance<ral::lpuart::RegisterBlock>;
62
63/// LPUART pins.
64pub struct Pins<TX, RX>
65where
66 TX: iomuxc::lpuart::Pin<Direction = iomuxc::lpuart::Tx>,
67 RX: iomuxc::lpuart::Pin<Module = TX::Module, Direction = iomuxc::lpuart::Rx>,
68{
69 /// Transfer pin.
70 pub tx: TX,
71 /// Receive pin.
72 pub rx: RX,
73}
74
75/// LPUART peripheral.
76///
77/// `Lpuart` lets you configure the LPUART peripheral, and perform I/O.
78/// See the [module-level documentation](crate::lpuart) for an example.
79///
80/// `Lpuart` implements serial traits from `embedded-hal`. It models
81/// DMA transfers as futures. The type exposes a lower-level API for
82/// coordinating DMA transfers. However, you may find it easier to use
83/// the [`dma`](crate::dma) interface.
84pub struct Lpuart {
85 pub(crate) lpuart: AnyInstance,
86}
87
88/// Serial direction.
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum Direction {
92 /// Transfer direction (leaving the peripheral).
93 Tx,
94 /// Receiver direction (entering the peripheral).
95 Rx,
96}
97
98impl Lpuart {
99 /// Create a new LPUART peripheral from its peripheral registers
100 /// and TX / RX pins.
101 ///
102 /// When this call returns, the peripheral is reset, the pins are
103 /// configured for their LPUART functions, and the TX and RX
104 /// halves are enabled.
105 ///
106 /// The pins are consumed to ensure they're properly configured, but they
107 /// are not stored in the driver.
108 pub fn with_pins<TX, RX, const N: u8>(
109 lpuart: ral::lpuart::Instance<N>,
110 mut pins: Pins<TX, RX>,
111 ) -> Self
112 where
113 TX: iomuxc::lpuart::Pin<Module = iomuxc::consts::Const<N>, Direction = iomuxc::lpuart::Tx>,
114 RX: iomuxc::lpuart::Pin<Module = iomuxc::consts::Const<N>, Direction = iomuxc::lpuart::Rx>,
115 {
116 iomuxc::lpuart::prepare(&mut pins.tx);
117 iomuxc::lpuart::prepare(&mut pins.rx);
118 Self::init(lpuart)
119 }
120
121 /// Create a new LPUART peripheral from its peripheral registers
122 /// without any pins.
123 ///
124 /// This is similar to [`with_pins()`](Self::with_pins), but it does not configure
125 /// pins to function as inputs and outputs. You're responsible
126 /// for configuring TX and RX pins and for making sure the pin state
127 /// doesn't change.
128 pub fn without_pins<const N: u8>(lpuart: ral::lpuart::Instance<N>) -> Self {
129 Self::init(lpuart)
130 }
131
132 fn init<const N: u8>(lpuart: ral::lpuart::Instance<N>) -> Self {
133 let lpuart: AnyInstance = crate::into_any(lpuart);
134 ral::write_reg!(ral::lpuart, lpuart, GLOBAL, RST: 1);
135 ral::write_reg!(ral::lpuart, lpuart, GLOBAL, RST: 0);
136 ral::modify_reg!(ral::lpuart, lpuart, CTRL, TE: TE_1, RE: RE_1);
137 Self { lpuart }
138 }
139
140 /// Indicates if the transmit / receive functions are
141 /// (`true`) or are not (`false`) enabled.
142 pub fn is_enabled(&self, direction: Direction) -> bool {
143 match direction {
144 Direction::Rx => ral::read_reg!(ral::lpuart, self.lpuart, CTRL, RE == RE_1),
145 Direction::Tx => ral::read_reg!(ral::lpuart, self.lpuart, CTRL, TE == TE_1),
146 }
147 }
148
149 /// Enable (`true`) or disable (`false`) the transmit / receive
150 /// functions.
151 pub fn set_enable(&mut self, direction: Direction, enable: bool) {
152 match direction {
153 Direction::Rx => ral::modify_reg!(ral::lpuart, self.lpuart, CTRL, RE: enable as u32),
154 Direction::Tx => ral::modify_reg!(ral::lpuart, self.lpuart, CTRL, TE: enable as u32),
155 }
156 }
157
158 /// Resets all internal logic and registers.
159 ///
160 /// Note that this may not reset all peripheral state, like the state
161 /// in the peripheral's global register.
162 pub fn reset(&mut self) {
163 ral::write_reg!(ral::lpuart, self.lpuart, GLOBAL, RST: 1);
164 ral::write_reg!(ral::lpuart, self.lpuart, GLOBAL, RST: 0);
165 }
166
167 /// Temporarily disable the LPUART peripheral.
168 ///
169 /// The handle to a [`Disabled`](crate::lpuart::Disabled) driver lets you modify
170 /// LPUART settings that require a fully disabled peripheral. This will flush
171 /// TX and RX buffers.
172 pub fn disable<R>(&mut self, func: impl FnOnce(&mut Disabled) -> R) -> R {
173 let mut disabled = Disabled::new(&mut self.lpuart);
174 func(&mut disabled)
175 }
176
177 /// Return the baud-specific timing values for this UART peripheral.
178 pub fn baud(&self) -> Baud {
179 let (osr, sbr, bothedge) =
180 ral::read_reg!(ral::lpuart, self.lpuart, BAUD, OSR, SBR, BOTHEDGE);
181 Baud {
182 osr: osr + 1,
183 sbr,
184 bothedge: bothedge != 0,
185 }
186 }
187
188 /// Return the parity seting for the UART peripheral.
189 ///
190 /// Result is `None` if there is no parity setting.
191 pub fn parity(&self) -> Option<Parity> {
192 let (pe, pt) = ral::read_reg!(ral::lpuart, self.lpuart, CTRL, PE, PT);
193 const PARITY_ODD: u32 = Parity::Odd as u32;
194 const PARITY_EVEN: u32 = Parity::Even as u32;
195 match pt {
196 PARITY_ODD if pe != 0 => Parity::ODD,
197 PARITY_EVEN if pe != 0 => Parity::EVEN,
198 _ => Parity::NONE,
199 }
200 }
201
202 /// Indicates if the bits are inverted.
203 #[inline]
204 pub fn is_inverted(&self, direction: Direction) -> bool {
205 match direction {
206 Direction::Rx => ral::read_reg!(ral::lpuart, self.lpuart, STAT, RXINV == 1),
207 Direction::Tx => ral::read_reg!(ral::lpuart, self.lpuart, CTRL, TXINV == 1),
208 }
209 }
210
211 /// Indicates if the FIFO is enabled.
212 #[inline]
213 pub fn is_fifo_enabled(&self, direction: Direction) -> bool {
214 match direction {
215 Direction::Rx => ral::read_reg!(ral::lpuart, self.lpuart, FIFO, RXFE == 1),
216 Direction::Tx => ral::read_reg!(ral::lpuart, self.lpuart, FIFO, TXFE == 1),
217 }
218 }
219
220 /// Returns the FIFO watermark value.
221 #[inline]
222 pub fn fifo_watermark(&self, direction: Direction) -> u32 {
223 match direction {
224 Direction::Rx => ral::read_reg!(ral::lpuart, self.lpuart, WATER, RXWATER),
225 Direction::Tx => ral::read_reg!(ral::lpuart, self.lpuart, WATER, TXWATER),
226 }
227 }
228
229 /// Read the data register.
230 pub fn read_data(&self) -> ReadData {
231 ReadData(ral::read_reg!(ral::lpuart, self.lpuart, DATA))
232 }
233
234 /// Write a byte.
235 ///
236 /// This does not perform any checks for space in the transmit
237 /// buffer. To check transmit buffer space, use `status`, and
238 /// check for the transmit data register empty.
239 pub fn write_byte(&self, byte: u8) {
240 ral::write_reg!(ral::lpuart, self.lpuart, DATA, byte as u32);
241 }
242
243 /// Check the peripheral status register.
244 pub fn status(&self) -> Status {
245 let stat = ral::read_reg!(ral::lpuart, self.lpuart, STAT);
246 let fifo = ral::read_reg!(ral::lpuart, self.lpuart, FIFO);
247 Status::from_registers(stat, fifo)
248 }
249
250 /// Clear the status flags.
251 ///
252 /// Bits that are read-only will be cleared by the implementation, so it's
253 /// safe to call with `Status::all()`.
254 #[inline]
255 pub fn clear_status(&mut self, status: Status) {
256 let stat_flags = status & Status::W1C & Status::stat_mask();
257 let fifo_flags = status & Status::W1C & Status::fifo_mask();
258 ral::modify_reg!(ral::lpuart, self.lpuart, STAT, |stat| {
259 let stat = stat & !Status::stat_mask().stat_bits();
260 stat | stat_flags.stat_bits()
261 });
262 ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, |fifo| {
263 let fifo = fifo & !Status::fifo_mask().fifo_bits();
264 fifo | fifo_flags.fifo_bits()
265 });
266 }
267
268 /// Flush data from the FIFO.
269 ///
270 /// This does not flush anything that's already in the transmit or receive register.
271 #[inline]
272 pub fn flush_fifo(&mut self, direction: Direction) {
273 flush_fifo(&self.lpuart, direction);
274 }
275
276 /// Return the interrupt flags.
277 ///
278 /// The interrupt flags indicate the reasons that this peripheral may generate an
279 /// interrupt.
280 pub fn interrupts(&self) -> Interrupts {
281 let ctrl = ral::read_reg!(ral::lpuart, self.lpuart, CTRL);
282 let fifo = ral::read_reg!(ral::lpuart, self.lpuart, FIFO);
283 Interrupts::from_bits_truncate(ctrl | fifo)
284 }
285
286 /// Let the peripheral act as a DMA destination.
287 ///
288 /// After this call, the peripheral will signal to the DMA engine whenever
289 /// it has free space in its transfer buffer.
290 pub fn enable_dma_transmit(&mut self) {
291 ral::modify_reg!(ral::lpuart, self.lpuart, BAUD, TDMAE: 1);
292 }
293
294 /// Stop the peripheral from acting as a DMA destination.
295 ///
296 /// See the DMA chapter in the reference manual to understand when this
297 /// should be called in the DMA transfer lifecycle.
298 pub fn disable_dma_transmit(&mut self) {
299 while ral::read_reg!(ral::lpuart, self.lpuart, BAUD, TDMAE == 1) {
300 ral::modify_reg!(ral::lpuart, self.lpuart, BAUD, TDMAE: 0);
301 }
302 }
303
304 /// Produces a pointer to the data register.
305 ///
306 /// You should use this pointer when coordinating a DMA transfer.
307 /// You're not expected to read from this pointer in software.
308 pub fn data(&self) -> *const ral::RWRegister<u32> {
309 core::ptr::addr_of!(self.lpuart.DATA)
310 }
311
312 /// Let the peripheral act as a DMA source.
313 ///
314 /// After this call, the peripheral will signal to the DMA engine whenever
315 /// it has data available to read.
316 pub fn enable_dma_receive(&mut self) {
317 self.clear_status(Status::W1C);
318 ral::modify_reg!(ral::lpuart, self.lpuart, BAUD, RDMAE: 1);
319 }
320
321 /// Stop the peripheral from acting as a DMA source.
322 ///
323 /// See the DMA chapter in the reference manual to understand when this
324 /// should be called in the DMA transfer lifecycle.
325 pub fn disable_dma_receive(&mut self) {
326 while ral::read_reg!(ral::lpuart, self.lpuart, BAUD, RDMAE == 1) {
327 ral::modify_reg!(ral::lpuart, self.lpuart, BAUD, RDMAE: 0);
328 }
329 }
330
331 /// Attempts to write a single byte to the bus.
332 ///
333 /// Returns `false` if the fifo was already full.
334 pub fn try_write(&mut self, byte: u8) -> bool {
335 ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, TXOF: TXOF_1);
336 self.write_byte(byte);
337 ral::read_reg!(ral::lpuart, self.lpuart, FIFO, TXOF == TXOF_0)
338 }
339
340 /// Attempts to read a single byte from the bus.
341 ///
342 /// Returns:
343 /// - `Ok(Some(u8))` if data was read
344 /// - `Ok(None)` if the fifo was empty
345 /// - `Err(..)` if a read error happened
346 pub fn try_read(&mut self) -> Result<Option<u8>, ReadFlags> {
347 let data = self.read_data();
348 if data.flags().contains(ReadFlags::RXEMPT) {
349 Ok(None)
350 } else if data
351 .flags()
352 .intersects(ReadFlags::PARITY_ERROR | ReadFlags::FRAME_ERROR | ReadFlags::NOISY)
353 {
354 Err(data.flags())
355 } else {
356 Ok(Some(data.into()))
357 }
358 }
359}
360
361fn flush_fifo(lpuart: &AnyInstance, direction: Direction) {
362 match direction {
363 Direction::Rx => ral::modify_reg!(ral::lpuart, lpuart, FIFO, RXFLUSH: RXFLUSH_1),
364 Direction::Tx => ral::modify_reg!(ral::lpuart, lpuart, FIFO, TXFLUSH: TXFLUSH_1),
365 }
366}
367
368/// A temporarily-disabled LPUART peripheral.
369///
370/// The disabled peripheral lets you changed
371/// settings that require a disabled peripheral.
372pub struct Disabled<'a> {
373 lpuart: &'a mut AnyInstance,
374 te: bool,
375 re: bool,
376}
377
378impl Drop for Disabled<'_> {
379 fn drop(&mut self) {
380 ral::modify_reg!(ral::lpuart, self.lpuart, CTRL, TE: self.te as u32, RE: self.re as u32);
381 }
382}
383
384impl<'a> Disabled<'a> {
385 fn new(lpuart: &'a mut AnyInstance) -> Self {
386 let (te, re) = ral::read_reg!(ral::lpuart, lpuart, CTRL, TE, RE);
387 ral::modify_reg!(ral::lpuart, lpuart, CTRL, TE: TE_0, RE: RE_0);
388 for direction in [Direction::Rx, Direction::Tx] {
389 flush_fifo(lpuart, direction);
390 }
391 Self {
392 lpuart,
393 te: te != 0,
394 re: re != 0,
395 }
396 }
397
398 /// Set baud-specific timing values for this UART peripheral.
399 ///
400 /// The timing values are used to set a baud rate. To compute
401 /// a baud rate, see [`Baud::compute`](crate::lpuart::Baud::compute). Or,
402 /// you may compute your own timing values.
403 pub fn set_baud(&mut self, baud: &Baud) {
404 ral::modify_reg!(ral::lpuart, self.lpuart,
405 BAUD,
406 OSR: baud.osr.clamp(4, 32) - 1,
407 SBR: baud.sbr.min((1 << 13) - 1),
408 BOTHEDGE: baud.bothedge as u32)
409 }
410
411 /// Specify parity bit settings. If there is no parity, use `None`.
412 pub fn set_parity(&mut self, parity: Option<Parity>) {
413 ral::modify_reg!(
414 ral::lpuart,
415 self.lpuart,
416 CTRL,
417 PE: parity.is_some() as u32,
418 M: parity.is_some() as u32,
419 PT: parity.map(|p| p as u32).unwrap_or(0u32)
420 );
421 }
422
423 /// Reverse the polarity of data, affecting all data bits, start
424 /// and stop bits, and polarity bits.
425 ///
426 /// The default inversion state is `false`.
427 #[inline]
428 pub fn set_inversion(&mut self, direction: Direction, inverted: bool) {
429 match direction {
430 Direction::Rx => {
431 ral::modify_reg!(ral::lpuart, self.lpuart, STAT, RXINV: inverted as u32)
432 }
433 Direction::Tx => {
434 ral::modify_reg!(ral::lpuart, self.lpuart, CTRL, TXINV: inverted as u32)
435 }
436 }
437 }
438
439 /// Disable the FIFO for the given direction.
440 #[inline]
441 pub fn disable_fifo(&mut self, direction: Direction) {
442 match direction {
443 Direction::Rx => ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, RXFE: RXFE_0),
444 Direction::Tx => ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, TXFE: TXFE_0),
445 }
446 }
447
448 /// Enable the FIFO, and set the FIFO watermark.
449 ///
450 /// `watermark` describes the serial direction, and the point at which the hardware signals a full
451 /// or empty FIFO. Use [`Watermark::tx`](crate::lpuart::Watermark::tx)
452 /// to enable the transfer FIFO, and [`Watermark::rx`](crate::lpuart::Watermark::rx) to enable the
453 /// receive FIFO.
454 ///
455 /// The actual watermark value is limited by the hardware. `enable_fifo` returns the
456 /// actual watermark value.
457 #[inline]
458 pub fn enable_fifo(&mut self, watermark: Watermark) -> u32 {
459 let size = match watermark.direction {
460 Direction::Rx => 1 << ral::read_reg!(ral::lpuart, self.lpuart, PARAM, RXFIFO),
461 Direction::Tx => 1 << ral::read_reg!(ral::lpuart, self.lpuart, PARAM, TXFIFO),
462 };
463 let size = watermark.size.min(size - 1);
464 match watermark.direction {
465 Direction::Rx => {
466 ral::modify_reg!(ral::lpuart, self.lpuart, WATER, RXWATER: size);
467 ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, RXFE: RXFE_1);
468 }
469 Direction::Tx => {
470 ral::modify_reg!(ral::lpuart, self.lpuart, WATER, TXWATER: size);
471 ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, TXFE: TXFE_1);
472 }
473 };
474 size
475 }
476
477 /// Set the interrupt flags for this LPUART peripheral.
478 ///
479 /// Use `set_interrupts` to enable or disable interrupt generation for
480 /// this peripheral.
481 pub fn set_interrupts(&mut self, interrupts: Interrupts) {
482 let ctrl_flags = interrupts & Interrupts::ctrl_mask();
483 let fifo_flags = interrupts & Interrupts::fifo_mask();
484 ral::modify_reg!(ral::lpuart, self.lpuart, CTRL, |ctrl| {
485 let ctrl = ctrl & !Interrupts::ctrl_mask().bits();
486 ctrl | ctrl_flags.bits()
487 });
488 ral::modify_reg!(ral::lpuart, self.lpuart, FIFO, |fifo| {
489 let fifo = fifo & !Interrupts::fifo_mask().bits();
490 fifo | fifo_flags.bits()
491 });
492 }
493}
494
495/// Values specific to the baud rate.
496///
497/// To compute the values for a given baud rate,
498/// use [`compute`](Baud::compute). To understand
499/// the actual baud rate, use [`value`](Baud::value).
500///
501/// Advanced users may choose to set the OSR, SBR, and
502/// BOTHEDGE values directly.
503///
504/// ```no_run
505/// use imxrt_hal::lpuart::Baud;
506///
507/// // Assume UART clock is driven from the crystal
508/// // oscillator...
509/// const UART_CLOCK_HZ: u32 = 24_000_000;
510/// const BAUD: Baud = Baud::compute(UART_CLOCK_HZ, 115200);
511/// ```
512#[cfg_attr(feature = "defmt", derive(defmt::Format))]
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
514pub struct Baud {
515 /// Oversampling rate.
516 ///
517 /// This should be set between 4 and 32.
518 /// The driver clamps the `osr` value within
519 /// this range.
520 pub osr: u32,
521 /// Baud rate modulo divisor.
522 ///
523 /// The driver commits this value directly.
524 /// A value of zero is allowed, but will disable
525 /// baud rate generation in hardware. The max
526 /// value is `(2^13) - 1`. The implementation
527 /// limits the max value.
528 pub sbr: u32,
529 /// Both edge sampling.
530 ///
531 /// Should be set when the oversampling
532 /// rate is between 4 and 7. Optional
533 /// for higher sampling rates. The driver
534 /// will commit this value directly.
535 pub bothedge: bool,
536}
537
538impl Baud {
539 /// Returns the baud value in bits per second.
540 ///
541 /// `source_clock_hz` is the UART clock frequency (Hz).
542 ///
543 /// # Panics
544 ///
545 /// Panics if `sbr` or `osr` is zero.
546 pub const fn value(self, source_clock_hz: u32) -> u32 {
547 source_clock_hz / (self.sbr * self.osr)
548 }
549
550 /// Computes a timings struct that represents a baud rate.
551 ///
552 /// `source_clock_hz` is the UART clock frequency (Hz). `baud`
553 /// is the intended baud rate.
554 pub const fn compute(source_clock_hz: u32, baud: u32) -> Baud {
555 const fn max(left: u32, right: u32) -> u32 {
556 if left > right { left } else { right }
557 }
558 const fn min(left: u32, right: u32) -> u32 {
559 if left < right { left } else { right }
560 }
561
562 let mut err = u32::MAX;
563 let mut best_osr = 0;
564 let mut best_sbr = 0;
565
566 let mut osr = if baud > 3_000_000 { 4 } else { 8 };
567 while osr <= 32 {
568 let mut sbr = 1;
569 while sbr < 8192 {
570 let b = source_clock_hz / (sbr * osr);
571 let e = max(baud, b) - min(baud, b);
572 if e < err {
573 err = e;
574 best_osr = osr;
575 best_sbr = sbr;
576 }
577 sbr += 1;
578 }
579 osr += 1;
580 }
581 Baud {
582 osr: best_osr,
583 sbr: best_sbr,
584 bothedge: 4 <= best_osr && best_osr <= 7,
585 }
586 }
587}
588
589/// Parity bit selection.
590///
591/// See [`Disabled::set_parity`](crate::lpuart::Disabled::set_parity) and
592/// [`Lpuart::parity`](crate::lpuart::Lpuart::parity) for more information.
593/// Consider using the associated constants to quickly specify
594/// parity bits.
595#[cfg_attr(feature = "defmt", derive(defmt::Format))]
596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
597#[repr(u32)]
598pub enum Parity {
599 /// Even parity.
600 Even = 0,
601 /// Odd parity.
602 Odd = 1,
603}
604
605impl Parity {
606 /// No parity.
607 pub const NONE: Option<Parity> = None;
608 /// Even parity.
609 pub const EVEN: Option<Parity> = Some(Parity::Even);
610 /// Odd parity.
611 pub const ODD: Option<Parity> = Some(Parity::Odd);
612}
613
614bitflags::bitflags! {
615 /// Errors that may occur when reading data.
616 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
617 pub struct ReadFlags : u32 {
618 /// Data was received with noise.
619 const NOISY = 1 << 15;
620 /// Parity error when receiving data.
621 const PARITY_ERROR = 1 << 14;
622 /// Framing error when receiving data.
623 const FRAME_ERROR = 1 << 13;
624 /// Receive buffer is empty.
625 ///
626 /// Asserts when there is no data in the receive buffer.
627 const RXEMPT = 1 << 12;
628 /// Idle Line.
629 ///
630 /// Indicates the receiver line was idle before receiving the character.
631 /// Overrun occured, and we lost data in the shift register.
632 const IDLINE = 1 << 11;
633 }
634}
635
636bitflags::bitflags! {
637 /// Interrupt settings.
638 ///
639 /// A set bit indicates that the interrupt is enabled.
640 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
641 pub struct Interrupts : u32 {
642 /// Overrun interrupt enable.
643 const OVERRUN = 1 << 27;
644 /// Noise error interrupt enable.
645 const NOISE_ERROR = 1 << 26;
646 /// Framing error interrupt enable.
647 const FRAMING_ERROR = 1 << 25;
648 /// Parity error interrupt enable.
649 const PARITY_ERROR = 1 << 24;
650 /// Transmit empty interrupt enable.
651 ///
652 /// Triggers when the `TRANSMIT_EMPTY` _status_ bit is high.
653 const TRANSMIT_EMPTY = 1 << 23;
654 /// Transmit complete interrupt enable.
655 ///
656 /// Triggers an interrupt when the `TRANSMIT_COMPLETE` _status_ bit is high.
657 const TRANSMIT_COMPLETE = 1 << 22;
658 /// Receiver interrupt enable.
659 ///
660 /// Triggers when the `RECEIVE_FULL` _status_ bit is high.
661 const RECEIVE_FULL = 1 << 21;
662
663 // All of the above flags pertain to the CTRL
664 // register. These flags pertain to the FIFO
665 // interrupts. They can be written directly.
666
667 /// Transmit FIFO Overflow Interrupt Enable.
668 ///
669 /// If set, a transmit FIFO overrun event generates an
670 /// interrupt.
671 const TRANSMIT_OVERFLOW = 1 << 9;
672 /// Receive FIFO Underflow Interrupt Enable.
673 ///
674 /// If set, a receive FIFO underflow event generates an
675 /// interrupt.
676 const RECEIVE_UNDERFLOW = 1 << 8;
677 }
678}
679
680impl Interrupts {
681 /// Mask for only the FIFO bits.
682 const fn fifo_mask() -> Self {
683 Self::from_bits_truncate(
684 Interrupts::TRANSMIT_OVERFLOW.bits() | Interrupts::RECEIVE_UNDERFLOW.bits(),
685 )
686 }
687 /// Mask for only the CTRL bits.
688 const fn ctrl_mask() -> Self {
689 // Safety: bits are valid for this bitflags instance.
690 Self::from_bits_truncate(Self::all().bits() & !Self::fifo_mask().bits())
691 }
692}
693
694/// The result of reading from the receiver.
695///
696/// The data contains flags, which may indicate errors
697/// in the received data. If the flags indicate value data,
698/// use `u8::from` to convert the data into its raw byte.
699#[cfg_attr(feature = "defmt", derive(defmt::Format))]
700#[derive(Clone, Copy, Debug, PartialEq, Eq)]
701#[repr(transparent)]
702pub struct ReadData(u32);
703
704impl ReadData {
705 /// Access the read flags, which indicate results of the
706 /// read operation.
707 #[inline]
708 pub fn flags(self) -> ReadFlags {
709 ReadFlags::from_bits_truncate(self.0)
710 }
711
712 /// Access the raw value.
713 #[inline]
714 pub fn raw(self) -> u32 {
715 self.0
716 }
717}
718
719impl From<ReadData> for u8 {
720 #[inline]
721 fn from(read_data: ReadData) -> u8 {
722 read_data.0 as u8
723 }
724}
725
726bitflags::bitflags! {
727 /// Status flags.
728 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
729 pub struct Status : u32 {
730 /// Receiver active flag.
731 ///
732 /// Set when the receiver detects a start bit. Cleared when
733 /// the line is idle.
734 const RECEIVE_ACTIVE = 1 << 24;
735 /// Transmit data register empty.
736 ///
737 /// This bit is set when the transmit FIFO can accept data.
738 /// - if the FIFO is enabled, this is set when the FIFO hits the watermark.
739 /// - if the FIFO is disabled, this is set when there's nothing in
740 /// the transmit data register.
741 const TRANSMIT_EMPTY = 1 << 23;
742 /// Transmit complete.
743 ///
744 /// TC is cleared when there's a transmission in progress, or when a preamble /
745 /// break character is loaded. It's set when the transmit buffer is empty.
746 ///
747 /// To clear TC, perform a write.
748 const TRANSMIT_COMPLETE = 1 << 22;
749 /// Receiver data register full.
750 ///
751 /// This bit is set when the receive FIFO is full.
752 /// - if the FIFO is enabled, this is set when the FIFO hits the watermark.
753 /// - if the FIFO is disabled, this is set when there's something in the
754 /// receiver register.
755 const RECEIVE_FULL = 1 << 21;
756 /// Idle line flag.
757 ///
758 /// IDLE is set when the LPUART receive line becomes idle for a full character
759 /// time after a period of activity.
760 const IDLE = 1 << 20;
761 /// Receiver overrun.
762 ///
763 /// Set when software fails to prevent the receive data register
764 /// from overflowing with data. The OR bit is set immediately after the
765 /// stop bit has been completely received for the dataword that overflows
766 /// the buffer and all the other error flags (FE, NF, and PF) are prevented
767 /// from setting.
768 const OVERRUN = 1 << 19;
769 /// Noise flag.
770 ///
771 /// This is also available in the read flags. However, setting it here
772 /// allows you to clear the noise flag in the status register.
773 const NOISY = 1 << 18;
774 /// Framing error.
775 ///
776 /// This is also available in the read flags. However, setting it here
777 /// allows you to clear the noise flag in the status register.
778 const FRAME_ERROR = 1 << 17;
779 /// Parity error.
780 ///
781 /// This is also available in the read flags. However, setting it here
782 /// allows you to clear the noise flag in the status register.
783 const PARITY_ERROR = 1 << 16;
784
785 // All flags up to and including bit 13 are marked 'reserved'
786 // in the status register. We're using these for other 'status'
787 // functions.
788
789 // These two flags relate to the FIFOs. They can only be written
790 // to the FIFO register after a left shift of FIFO_SHIFT.
791
792 /// Transmitter Buffer Overflow Flag
793 ///
794 /// Indicates that more data has been written to the transmit buffer than it can hold.
795 const TRANSMIT_OVERFLOW = 1 << 13;
796 /// Receiver Buffer Underflow Flag
797 ///
798 /// Indicates that more data has been read from the receive buffer than was present.
799 const RECEIVE_UNDERFLOW = 1 << 12;
800 }
801}
802
803impl Status {
804 /// The number of left shifts required to move the FIFO
805 /// status bits into position for the FIFO register.
806 const FIFO_SHIFT: u32 = 4;
807
808 /// The set of status bits that are W1C.
809 ///
810 /// Use this to differentiate read-only bits from bits that are
811 /// W1C.
812 pub const W1C: Status =
813 Self::from_bits_truncate(Self::all().bits() & !Self::read_only_mask().bits());
814
815 /// Status bits that are read-only.
816 ///
817 /// Includes those bits in the FIFO register.
818 const fn read_only_mask() -> Self {
819 Self::from_bits_truncate(
820 Self::RECEIVE_ACTIVE.bits()
821 | Self::TRANSMIT_EMPTY.bits()
822 | Self::TRANSMIT_COMPLETE.bits()
823 | Self::RECEIVE_FULL.bits(),
824 )
825 }
826
827 /// Return the bitflags that represent the FIFO bits.
828 const fn fifo_mask() -> Self {
829 Self::from_bits_truncate(Self::TRANSMIT_OVERFLOW.bits() | Self::RECEIVE_UNDERFLOW.bits())
830 }
831 /// Return the bitflags that represent the STAT bits.
832 const fn stat_mask() -> Self {
833 Self::from_bits_truncate(Self::all().bits() & !Self::fifo_mask().bits())
834 }
835 /// Returns the FIFO bits that may be written to the FIFO register.
836 const fn fifo_bits(self) -> u32 {
837 (self.bits() & Self::fifo_mask().bits()) << Self::FIFO_SHIFT
838 }
839 /// Returns the STAT bits that may be writeen to the STAT register.
840 const fn stat_bits(self) -> u32 {
841 self.bits() & Self::stat_mask().bits()
842 }
843 /// Compose status bitflags from raw STAT and FIFO register values.
844 ///
845 /// FIFO should only include `TXOF` and / or `RXUF` bits.
846 const fn from_registers(stat: u32, fifo: u32) -> Self {
847 Self::from_bits_truncate(stat | (fifo >> Self::FIFO_SHIFT))
848 }
849}
850
851/// Watermark levels for TX and RX FIFOs.
852///
853/// See [`Lpuart::enable_fifo`](crate::lpuart::Disabled::enable_fifo) for more
854/// information.
855#[cfg_attr(feature = "defmt", derive(defmt::Format))]
856#[derive(Debug, Clone, Copy)]
857pub struct Watermark {
858 direction: Direction,
859 size: u32,
860}
861
862impl Watermark {
863 /// Specify the transmit FIFO watermark.
864 ///
865 /// Note that the actual watermark value will be limited by the hardware.
866 #[inline]
867 pub const fn tx(size: u32) -> Self {
868 Watermark {
869 direction: Direction::Tx,
870 size,
871 }
872 }
873 /// Specify the receive FIFO watermark.
874 ///
875 /// Note that the actual watermark value with be limited by the hardware.
876 #[inline]
877 pub const fn rx(size: core::num::NonZeroU32) -> Self {
878 Watermark {
879 direction: Direction::Rx,
880 size: size.get(),
881 }
882 }
883}
884
885impl eh02::serial::Write<u8> for Lpuart {
886 type Error = core::convert::Infallible;
887
888 fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
889 self.flush()?;
890 self.write_byte(word);
891 Ok(())
892 }
893
894 fn flush(&mut self) -> nb::Result<(), Self::Error> {
895 if !self.status().contains(Status::TRANSMIT_EMPTY) {
896 Err(nb::Error::WouldBlock)
897 } else {
898 Ok(())
899 }
900 }
901}
902
903impl eh02::serial::Read<u8> for Lpuart {
904 type Error = ReadFlags;
905
906 fn read(&mut self) -> nb::Result<u8, Self::Error> {
907 let data = self.read_data();
908 self.clear_status(Status::W1C);
909 if data.flags().contains(ReadFlags::RXEMPT) {
910 Err(nb::Error::WouldBlock)
911 } else if data
912 .flags()
913 .intersects(ReadFlags::PARITY_ERROR | ReadFlags::FRAME_ERROR | ReadFlags::NOISY)
914 {
915 Err(nb::Error::Other(data.flags()))
916 } else {
917 Ok(data.into())
918 }
919 }
920}
921
922impl eh02::blocking::serial::Write<u8> for Lpuart {
923 type Error = core::convert::Infallible;
924
925 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
926 for word in buffer {
927 nb::block!(eh02::serial::Write::write(self, *word))?;
928 }
929
930 Ok(())
931 }
932
933 fn bflush(&mut self) -> Result<(), Self::Error> {
934 nb::block!(eh02::serial::Write::flush(self))?;
935 Ok(())
936 }
937}
938
939impl core::fmt::Display for ReadFlags {
940 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
941 write!(f, "Read data error: {self:?}")
942 }
943}
944
945impl core::error::Error for ReadFlags {}
946
947impl embedded_io::Error for ReadFlags {
948 fn kind(&self) -> embedded_io::ErrorKind {
949 embedded_io::ErrorKind::Other
950 }
951}
952
953impl embedded_io::ErrorType for Lpuart {
954 type Error = ReadFlags;
955}
956
957impl embedded_io::WriteReady for Lpuart {
958 fn write_ready(&mut self) -> Result<bool, Self::Error> {
959 Ok(self.status().contains(Status::TRANSMIT_EMPTY))
960 }
961}
962
963impl embedded_io::ReadReady for Lpuart {
964 fn read_ready(&mut self) -> Result<bool, Self::Error> {
965 Ok(self.status().contains(Status::RECEIVE_FULL))
966 }
967}
968
969impl embedded_io::Write for Lpuart {
970 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
971 let mut num_written = 0;
972 for word in buf {
973 if num_written == 0 {
974 // For the first word, continue trying until we send.
975 // This function is supposed to block until at least one word is
976 // sent.
977 while !self.try_write(*word) {}
978 } else {
979 // If we already sent at least one word, return once
980 // the buffer is full
981 if !self.try_write(*word) {
982 break;
983 }
984 }
985 num_written += 1;
986 }
987
988 Ok(num_written)
989 }
990
991 fn flush(&mut self) -> Result<(), Self::Error> {
992 while !self.status().contains(Status::TRANSMIT_COMPLETE) {}
993
994 Ok(())
995 }
996}
997
998impl embedded_io::Read for Lpuart {
999 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1000 let mut num_read = 0;
1001 for word in buf {
1002 let data = if num_read == 0 {
1003 // For the first word, continue querying until we receive something.
1004 // This function is supposed to block until at least one word is
1005 // received.
1006 loop {
1007 if let Some(data) = self.try_read()? {
1008 break data;
1009 }
1010 }
1011 } else {
1012 // If we already read at least one word, return once
1013 // the buffer is empty
1014 if let Some(data) = self.try_read()? {
1015 data
1016 } else {
1017 break;
1018 }
1019 };
1020
1021 *word = data;
1022 num_read += 1;
1023 }
1024
1025 Ok(num_read)
1026 }
1027}
1028
1029#[cfg(test)]
1030mod tests {
1031 use super::{Baud, ReadData, ReadFlags, Status};
1032
1033 #[test]
1034 fn approximate_baud() {
1035 // Assume the 24MHz XTAL clock.
1036 const UART_CLOCK_HZ: u32 = 24_000_000;
1037 // The best baud rate we can get is
1038 const EXPECTED_BAUD: u32 = 115384;
1039 // for a target baud of
1040 const TARGET_BAUD: u32 = 115200;
1041
1042 const BAUD: Baud = Baud::compute(UART_CLOCK_HZ, TARGET_BAUD);
1043
1044 assert_eq!(BAUD.value(UART_CLOCK_HZ), EXPECTED_BAUD);
1045
1046 // These values could switch, depending on the implementation...
1047 assert!(BAUD.sbr == 8 || BAUD.sbr == 26, "SBR: {}", BAUD.sbr);
1048 if BAUD.sbr == 8 {
1049 assert_eq!(BAUD.osr, 26);
1050 } else {
1051 assert_eq!(BAUD.osr, 8);
1052 }
1053 assert!(!BAUD.bothedge);
1054 }
1055
1056 #[test]
1057 fn non_default_sbr_baud() {
1058 // Assume the 24MHz XTAL clock.
1059 const UART_CLOCK_HZ: u32 = 24_000_000;
1060 // The best baud rate we can get is
1061 const EXPECTED_BAUD: u32 = 9600;
1062 // for a target baud of
1063 const TARGET_BAUD: u32 = 9600;
1064
1065 const BAUD: Baud = Baud::compute(UART_CLOCK_HZ, TARGET_BAUD);
1066
1067 assert_eq!(BAUD.value(UART_CLOCK_HZ), EXPECTED_BAUD);
1068
1069 assert_eq!(BAUD.osr, 10, "OSR: {}", BAUD.osr);
1070 assert_eq!(BAUD.sbr, 250, "SBR: {}", BAUD.sbr);
1071 assert!(!BAUD.bothedge);
1072 }
1073
1074 #[test]
1075 fn max_baud() {
1076 // Assume the 24MHz XTAL clock.
1077 const UART_CLOCK_HZ: u32 = 24_000_000;
1078 // The best baud rate we can get is
1079 const EXPECTED_BAUD: u32 = 6_000_000;
1080 // for a target baud of
1081 const TARGET_BAUD: u32 = 6_000_000;
1082
1083 const BAUD: Baud = Baud::compute(UART_CLOCK_HZ, TARGET_BAUD);
1084
1085 assert_eq!(BAUD.value(UART_CLOCK_HZ), EXPECTED_BAUD);
1086
1087 assert_eq!(BAUD.osr, 4, "OSR: {}", BAUD.osr);
1088 assert_eq!(BAUD.sbr, 1, "SBR: {}", BAUD.sbr);
1089 assert!(BAUD.bothedge);
1090 }
1091
1092 #[test]
1093 fn read_data_flags() {
1094 let read_data = ReadData(1 << 15 | 1 << 13);
1095 let flags = read_data.flags();
1096
1097 assert!(flags.contains(ReadFlags::NOISY));
1098 assert!(!flags.contains(ReadFlags::PARITY_ERROR));
1099 assert!(flags.contains(ReadFlags::FRAME_ERROR));
1100 assert!(!flags.contains(ReadFlags::RXEMPT));
1101 assert!(!flags.contains(ReadFlags::IDLINE));
1102
1103 assert!(flags.intersects(ReadFlags::NOISY | ReadFlags::PARITY_ERROR));
1104 assert!(!flags.intersects(ReadFlags::RXEMPT | ReadFlags::PARITY_ERROR));
1105 }
1106
1107 #[test]
1108 fn status_flags() {
1109 assert_eq!(Status::fifo_mask().bits(), (1 << 13) | (1 << 12));
1110 assert_eq!(Status::fifo_mask().fifo_bits(), (1 << 17) | (1 << 16));
1111 assert_eq!(Status::stat_mask().bits(), 0x01FF_0000);
1112 assert_eq!(Status::stat_mask().stat_bits(), 0x01FF_0000);
1113 assert_eq!(Status::W1C.bits(), 0x001F_3000);
1114
1115 assert!(
1116 Status::from_registers(0, (1 << 17) | (1 << 16))
1117 .contains(Status::TRANSMIT_OVERFLOW | Status::RECEIVE_UNDERFLOW)
1118 );
1119 assert!(Status::from_registers(u32::MAX, 0).contains(Status::stat_mask()));
1120
1121 assert!(Status::all().contains(Status::TRANSMIT_EMPTY));
1122 }
1123}