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