stm32_hal2/
lpuart.rs

1//! C+P from the `usart` module. todo: Reduce DRY.
2//!
3//! This module allows for serial communication using the STM32 LPUART peripheral
4//! It provides APIs to configure, read, and write from
5//! U[S]ART, with blocking, nonblocking, and DMA functionality.
6
7// todo: Synchronous mode.
8// todo: Auto baud
9
10// todo: Missing some features (like additional interrupts) on the USARTv3 peripheral . (L5, G etc)
11
12use core::ops::Deref;
13
14use cfg_if::cfg_if;
15
16#[cfg(not(any(feature = "l552", feature = "h5")))]
17use crate::dma::{self, ChannelCfg, DmaChannel};
18#[cfg(feature = "g0")]
19use crate::pac::DMA as DMA1;
20#[cfg(not(any(feature = "g0", feature = "h5")))]
21use crate::pac::DMA1;
22use crate::{
23    clocks::Clocks,
24    error::{Error, Result},
25    pac::{self, RCC},
26    usart::{Parity, UsartConfig, UsartError, UsartInterrupt},
27    util::{BaudPeriph, RccPeriph, bounded_loop, cr1, isr},
28};
29
30/// Represents the USART peripheral, for serial communications.
31pub struct LpUart<R> {
32    pub regs: R,
33    baud: u32,
34    config: UsartConfig,
35}
36
37impl<R> LpUart<R>
38where
39    R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph + BaudPeriph,
40{
41    /// Initialize a U[s]ART peripheral, including configuration register writes, and enabling and
42    /// resetting its RCC peripheral clock. `baud` is the baud rate, in bytes-per-second.
43    pub fn new(regs: R, baud: u32, config: UsartConfig, clock_cfg: &Clocks) -> Result<Self> {
44        let rcc = unsafe { &(*RCC::ptr()) };
45        R::en_reset(rcc);
46
47        let mut lpuart = Self { regs, baud, config };
48
49        // This should already be disabled on power up, but disable here just in case;
50        // some bits can't be set with USART enabled.
51
52        lpuart.disable()?;
53
54        // Set up transmission. See L44 RM, section 38.5.2: "Character Transmission Procedures".
55        // 1. Program the M bits in USART_CR1 to define the word length.
56
57        let word_len_bits = lpuart.config.word_len.bits();
58        cr1!(lpuart.regs).modify(|_, w| {
59            w.pce().bit(lpuart.config.parity != Parity::Disabled);
60            cfg_if! {
61                if #[cfg(not(any(feature = "f", feature = "wl")))] {
62                    w.m1().bit(word_len_bits.0 != 0);
63                    w.m0().bit(word_len_bits.1 != 0);
64                    return w.ps().bit(lpuart.config.parity == Parity::EnabledOdd);
65                } else {
66                    return w.ps().bit(lpuart.config.parity == Parity::EnabledOdd);
67                }
68            }
69        });
70
71        // todo: Workaround due to a PAC bug, where M0 is missing.
72        #[cfg(any(feature = "f"))]
73        lpuart.regs.cr1().write(|w| unsafe {
74            w.bits(
75                lpuart.regs.cr1().read().bits()
76                    | ((word_len_bits.0 as u32) << 28)
77                    | ((word_len_bits.1 as u32) << 12),
78            )
79        });
80
81        #[cfg(not(feature = "f4"))]
82        lpuart
83            .regs
84            .cr3()
85            .modify(|_, w| w.ovrdis().bit(lpuart.config.overrun_disabled));
86
87        // Must be done before enabling.
88        #[cfg(any(feature = "g4", feature = "h7"))]
89        lpuart
90            .regs
91            .cr1()
92            .modify(|_, w| w.fifoen().bit(lpuart.config.fifo_enabled));
93
94        // 2. Select the desired baud rate using the USART_BRR register.
95        lpuart.set_baud(baud, clock_cfg).ok();
96        // 3. Program the number of stop bits in USART_CR2.
97        lpuart
98            .regs
99            .cr2()
100            .modify(|_, w| unsafe { w.stop().bits(lpuart.config.stop_bits as u8) });
101        // 4. Enable the USART by writing the UE bit in USART_CR1 register to 1.
102        lpuart.enable()?;
103
104        // 5. Select DMA enable (DMAT[R]] in USART_CR3 if multibuffer communication is to take
105        // place. Configure the DMA register as explained in multibuffer communication.
106        // (Handled in `read_dma()` and `write_dma()`)
107        // 6. Set the TE bit in USART_CR1 to send an idle frame as first transmission.
108        // 6. Set the RE bit USART_CR1. This enables the receiver which begins searching for a
109        // start bit.
110
111        cr1!(lpuart.regs).modify(|_, w| {
112            w.te().bit(true);
113            w.re().bit(true)
114        });
115
116        Ok(lpuart)
117    }
118}
119
120impl<R> LpUart<R>
121where
122    R: Deref<Target = pac::lpuart1::RegisterBlock> + BaudPeriph,
123{
124    /// Set the BAUD rate. Called during init, and can be called later to change BAUD
125    /// during program execution.
126    pub fn set_baud(&mut self, baud: u32, clock_cfg: &Clocks) -> Result<()> {
127        let originally_enabled = cr1!(self.regs).read().ue().bit_is_set();
128
129        if originally_enabled {
130            cr1!(self.regs).modify(|_, w| w.ue().clear_bit());
131            bounded_loop!(
132                cr1!(self.regs).read().ue().bit_is_set(),
133                Error::RegisterUnchanged
134            );
135        }
136
137        // To set BAUD rate, see G4 RM, section 38.4.7: LPUART baud rate generation.
138        // The computation is different here from normal UART.
139        // todo: Take into account the selectable USART clock in both
140        // todo util::baud implementation, and `clocks` module.
141        let fclk = R::baud(clock_cfg);
142
143        // This is a 20-bit register, so the value can easily overflow, e.g. with 9.6kHz baud.
144        // So, we set the prescaler. 10 keeps it under 20 bits at 9.6kHz baud, and 170Mhz fclock.
145        let prescaler = 10;
146        let prescaler_value = 0b101;
147        self.regs
148            .presc()
149            .write(|w| unsafe { w.bits(prescaler_value) });
150
151        // Be careful about overflowing here; this order of operations can prevent overflowing 32-bit integers.
152        // mid-operations. This is a subtly different overflow type than why we use the prescaler.
153        let usart_div = (fclk / baud) * 256 / prescaler;
154
155        self.regs
156            .brr()
157            .write(|w| unsafe { w.bits(usart_div as u32) });
158
159        self.baud = baud;
160
161        if originally_enabled {
162            cr1!(self.regs).modify(|_, w| w.ue().bit(true));
163        }
164
165        Ok(())
166    }
167}
168
169impl<R> LpUart<R>
170where
171    R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph,
172{
173    /// Enable this U[s]ART peripheral.
174    pub fn enable(&mut self) -> Result<()> {
175        cr1!(self.regs).modify(|_, w| w.ue().set_bit());
176        bounded_loop!(
177            cr1!(self.regs).read().ue().bit_is_clear(),
178            Error::RegisterUnchanged
179        );
180        Ok(())
181    }
182
183    /// Disable this U[s]ART peripheral.
184    pub fn disable(&mut self) -> Result<()> {
185        cr1!(self.regs).modify(|_, w| w.ue().clear_bit());
186        bounded_loop!(
187            cr1!(self.regs).read().ue().bit_is_set(),
188            Error::RegisterUnchanged
189        );
190        Ok(())
191    }
192
193    /// Transmit data, as a sequence of u8. See L44 RM, section 38.5.2: "Character transmission procedure"
194    pub fn write(&mut self, data: &[u8]) -> Result<()> {
195        // todo: how does this work with a 9 bit words? Presumably you'd need to make `data`
196        // todo take `&u16`.
197
198        // 7. Write the data to send in the USART_TDR register (this clears the TXE bit). Repeat this
199        // for each data to be transmitted in case of single buffer.
200
201        for word in data {
202            #[cfg(feature = "h5")]
203            bounded_loop!(
204                isr!(self.regs).read().txfe().bit_is_clear(),
205                Error::RegisterUnchanged
206            );
207
208            #[cfg(not(feature = "h5"))]
209            // Note: Per these PACs, TXFNF and TXE are on the same field, so this is actually
210            // checking txfnf if the fifo is enabled.
211            bounded_loop!(
212                isr!(self.regs).read().txe().bit_is_clear(),
213                Error::RegisterUnchanged
214            );
215
216            #[cfg(not(feature = "f4"))]
217            self.regs
218                .tdr()
219                .modify(|_, w| unsafe { w.tdr().bits(*word as u16) });
220
221            #[cfg(feature = "f4")]
222            self.regs
223                .dr()
224                .modify(|_, w| unsafe { w.dr().bits(*word as u16) });
225        }
226
227        // 8. After writing the last data into the USART_TDR register, wait until TC=1. This indicates
228        // that the transmission of the last frame is complete. This is required for instance when
229        // the USART is disabled or enters the Halt mode to avoid corrupting the last
230        // transmission
231        bounded_loop!(
232            isr!(self.regs).read().tc().bit_is_clear(),
233            Error::RegisterUnchanged
234        );
235
236        Ok(())
237    }
238
239    /// Write a single word, without waiting until ready for the next. Compared to the `write()` function, this
240    /// does not block.
241    pub fn write_one(&mut self, word: u8) {
242        // todo: how does this work with a 9 bit words? Presumably you'd need to make `data`
243        // todo take `&u16`.
244        cfg_if! {
245            if #[cfg(not(feature = "f4"))] {
246            self.regs
247                .tdr()
248                .modify(|_, w| unsafe { w.tdr().bits(word as u16) });
249            } else {
250                self.regs
251                    .dr()
252                    .modify(|_, w| unsafe { w.dr().bits(word as u16) });
253            }
254        }
255    }
256
257    /// Receive data into a u8 buffer. See L44 RM, section 38.5.3: "Character reception procedure"
258    pub fn read(&mut self, buf: &mut [u8]) -> Result<()> {
259        for i in 0..buf.len() {
260            // Wait for the next bit
261            #[cfg(feature = "h5")]
262            bounded_loop!(
263                isr!(self.regs).read().rxfne().bit_is_clear(),
264                Error::RegisterUnchanged
265            );
266
267            #[cfg(not(feature = "h5"))]
268            bounded_loop!(
269                isr!(self.regs).read().rxne().bit_is_clear(),
270                Error::RegisterUnchanged
271            );
272
273            #[cfg(not(feature = "f4"))]
274            {
275                buf[i] = self.regs.rdr().read().rdr().bits() as u8;
276            }
277            #[cfg(feature = "f4")]
278            {
279                buf[i] = self.regs.dr().read().dr().bits() as u8;
280            }
281        }
282
283        // When a character is received:
284        // • The RXNE bit is set to indicate that the content of the shift register is transferred to the
285        // RDR. In other words, data has been received and can be read (as well as its
286        // associated error flags).
287        // • An interrupt is generated if the RXNEIE bit is set.
288        // • The error flags can be set if a frame error, noise or an overrun error has been detected
289        // during reception. PE flag can also be set with RXNE.
290        // • In multibuffer, RXNE is set after every byte received and is cleared by the DMA read of
291        // the Receive data Register.
292        // • In single buffer mode, clearing the RXNE bit is performed by a software read to the
293        // USART_RDR register. The RXNE flag can also be cleared by writing 1 to the RXFRQ
294        // in the USART_RQR register. The RXNE bit must be cleared before the end of the
295        // reception of the next character to avoid an overrun error
296
297        Ok(())
298    }
299
300    /// Read a single word, without waiting until ready for the next. Compared to the `read()` function, this
301    /// does not block.
302    pub fn read_one(&mut self) -> u8 {
303        cfg_if! {
304            if #[cfg(not(feature = "f4"))] {
305                self.regs.rdr().read().rdr().bits() as u8
306            } else {
307                self.regs.dr().read().dr().bits() as u8
308            }
309        }
310    }
311
312    #[cfg(not(any(feature = "f4", feature = "l552", feature = "h5")))]
313    /// Transmit data using DMA. (L44 RM, section 38.5.15)
314    /// Note that the `channel` argument is unused on F3 and L4, since it is hard-coded,
315    /// and can't be configured using the DMAMUX peripheral. (`dma::mux()` fn).
316    pub unsafe fn write_dma(
317        &mut self,
318        buf: &[u8],
319        channel: DmaChannel,
320        channel_cfg: ChannelCfg,
321        dma_periph: dma::DmaPeriph,
322    ) -> Result<()> {
323        let (ptr, len) = (buf.as_ptr(), buf.len());
324
325        // To map a DMA channel for USART transmission, use
326        // the following procedure (x denotes the channel number):
327
328        #[cfg(any(feature = "f3", feature = "l4"))]
329        let channel = R::write_chan();
330        #[cfg(feature = "l4")]
331        let mut dma_regs = unsafe { &(*DMA1::ptr()) }; // todo: Hardcoded DMA1
332        #[cfg(feature = "l4")]
333        R::write_sel(&mut dma_regs);
334
335        let num_data = len as u32;
336
337        // "DMA mode can be enabled for transmission by setting DMAT bit in the USART_CR3
338        // register. Data is loaded from a SRAM area configured using the DMA peripheral (refer to
339        // Section 11: Direct memory access controller (DMA) on page 295) to the USART_TDR
340        // register whenever the TXE bit is set."
341        self.regs.cr3().modify(|_, w| w.dmat().bit(true));
342
343        // 6. Clear the TC flag in the USART_ISR register by setting the TCCF bit in the
344        // USART_ICR register.
345        self.regs.icr().write(|w| w.tccf().bit(true));
346
347        match dma_periph {
348            dma::DmaPeriph::Dma1 => {
349                let mut regs = unsafe { &(*DMA1::ptr()) };
350                dma::cfg_channel(
351                    &mut regs,
352                    channel,
353                    // 1. Write the USART_TDR register address in the DMA control register to configure it as
354                    // the destination of the transfer. The data is moved to this address from memory after
355                    // each TXE event.
356                    self.regs.tdr().as_ptr() as u32,
357                    // 2. Write the memory address in the DMA control register to configure it as the source of
358                    // the transfer. The data is loaded into the USART_TDR register from this memory area
359                    // after each TXE event.
360                    ptr as u32,
361                    // 3. Configure the total number of bytes to be transferred to the DMA control register.
362                    num_data,
363                    dma::Direction::ReadFromMem,
364                    // 4. Configure the channel priority in the DMA control register
365                    // (Handled by `ChannelCfg::default())`
366                    dma::DataSize::S8,
367                    dma::DataSize::S8,
368                    channel_cfg,
369                )?;
370            }
371            #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
372            dma::DmaPeriph::Dma2 => {
373                let mut regs = unsafe { &(*pac::DMA2::ptr()) };
374                dma::cfg_channel(
375                    &mut regs,
376                    channel,
377                    self.regs.tdr().as_ptr() as u32,
378                    ptr as u32,
379                    num_data,
380                    dma::Direction::ReadFromMem,
381                    dma::DataSize::S8,
382                    dma::DataSize::S8,
383                    channel_cfg,
384                )?;
385            }
386        }
387
388        // 5. Configure DMA interrupt generation after half/ full transfer as required by the
389        // application.
390        // (Handled in `cfg_channel`)
391
392        // 7. Activate the channel in the DMA register.
393        // When the number of data transfers programmed in the DMA Controller is reached, the DMA
394        // controller generates an interrupt on the DMA channel interrupt vector.
395        // (Handled in `cfg_channel`)
396
397        // In transmission mode, once the DMA has written all the data to be transmitted (the TCIF flag
398        // is set in the DMA_ISR register), the TC flag can be monitored to make sure that the USART
399        // communication is complete. This is required to avoid corrupting the last transmission before
400        // disabling the USART or entering Stop mode. Software must wait until TC=1. The TC flag
401        // remains cleared during all data transfers and it is set by hardware at the end of transmission
402        // of the last frame.
403        Ok(())
404    }
405
406    #[cfg(not(any(feature = "f4", feature = "l552", feature = "h5")))]
407    /// Receive data using DMA. (L44 RM, section 38.5.15; G4 RM section 37.5.19.
408    /// Note that the `channel` argument is unused on F3 and L4, since it is hard-coded,
409    /// and can't be configured using the DMAMUX peripheral. (`dma::mux()` fn).
410    pub unsafe fn read_dma(
411        &mut self,
412        buf: &mut [u8],
413        channel: DmaChannel,
414        channel_cfg: ChannelCfg,
415        dma_periph: dma::DmaPeriph,
416    ) -> Result<()> {
417        let (ptr, len) = (buf.as_mut_ptr(), buf.len());
418
419        #[cfg(any(feature = "f3", feature = "l4"))]
420        let channel = R::read_chan();
421        #[cfg(feature = "l4")]
422        let mut dma_regs = unsafe { &(*DMA1::ptr()) }; // todo: Hardcoded DMA1
423        #[cfg(feature = "l4")]
424        R::write_sel(&mut dma_regs);
425
426        let num_data = len as u32;
427
428        // DMA mode can be enabled for reception by setting the DMAR bit in USART_CR3 register.
429        self.regs.cr3().modify(|_, w| w.dmar().bit(true));
430
431        match dma_periph {
432            dma::DmaPeriph::Dma1 => {
433                let mut regs = unsafe { &(*DMA1::ptr()) };
434                dma::cfg_channel(
435                    &mut regs,
436                    channel,
437                    // 1. Write the USART_RDR register address in the DMA control register to configure it as
438                    // the source of the transfer. The data is moved from this address to the memory after
439                    // each RXNE event.
440                    self.regs.rdr().as_ptr() as u32,
441                    // 2. Write the memory address in the DMA control register to configure it as the destination
442                    // of the transfer. The data is loaded from USART_RDR to this memory area after each
443                    // RXNE event.
444                    ptr as u32,
445                    // 3. Configure the total number of bytes to be transferred to the DMA control register.
446                    num_data,
447                    dma::Direction::ReadFromPeriph,
448                    dma::DataSize::S8,
449                    dma::DataSize::S8,
450                    channel_cfg,
451                )?;
452            }
453            #[cfg(not(any(feature = "f3x4", feature = "g0", feature = "wb")))]
454            dma::DmaPeriph::Dma2 => {
455                let mut regs = unsafe { &(*pac::DMA2::ptr()) };
456                dma::cfg_channel(
457                    &mut regs,
458                    channel,
459                    self.regs.rdr().as_ptr() as u32,
460                    ptr as u32,
461                    num_data,
462                    dma::Direction::ReadFromPeriph,
463                    dma::DataSize::S8,
464                    dma::DataSize::S8,
465                    channel_cfg,
466                )?;
467            }
468        }
469
470        // 4. Configure the channel priority in the DMA control register
471        // (Handled in cfg)
472
473        // 5. Configure interrupt generation after half/ full transfer as required by the application.
474        // (Handled by user code))
475
476        // 6. Activate the channel in the DMA control register. (Handled by `cfg_channel` above).
477        // When the number of data transfers programmed in the DMA Controller is reached, the DMA
478        // controller generates an interrupt on the DMA channel interrupt vector.
479        // (Handled in above fn call)
480
481        // When the number of data transfers programmed in the DMA Controller is reached, the DMA
482        // controller generates an interrupt on the DMA channel interrupt vector.
483        Ok(())
484    }
485    //
486    // /// Flush the transmit buffer.
487    // pub fn flush(&self) {
488    //     #[cfg(not(feature = "f4"))]
489    //     while isr!(self.regs).read().tc().bit_is_clear() {}
490    //     #[cfg(feature = "f4")]
491    //     while self.regs.sr().read().tc().bit_is_clear() {}
492    // }
493
494    #[cfg(not(feature = "f4"))]
495    /// Enable a specific type of interrupt. See G4 RM, Table 349: USART interrupt requests.
496    /// If `Some`, the inner value of `CharDetect` sets the address of the char to match.
497    /// If `None`, the interrupt is enabled without changing the char to match.
498    pub fn enable_interrupt(&mut self, interrupt: UsartInterrupt) -> Result<()> {
499        match interrupt {
500            UsartInterrupt::CharDetect(char_wrapper) => {
501                if let Some(char) = char_wrapper {
502                    // Disable the UART to allow writing the `add` and `addm7` bits
503                    cr1!(self.regs).modify(|_, w| w.ue().clear_bit());
504                    bounded_loop!(
505                        cr1!(self.regs).read().ue().bit_is_set(),
506                        Error::RegisterUnchanged
507                    );
508
509                    // Enable character-detecting UART interrupt
510                    cr1!(self.regs).modify(|_, w| w.cmie().bit(true));
511
512                    // Allow an 8-bit address to be set in `add`.
513                    self.regs.cr2().modify(|_, w| unsafe {
514                        w.addm7().bit(true);
515                        // Set the character to detect
516                        w.add().bits(char)
517                    });
518
519                    cr1!(self.regs).modify(|_, w| w.ue().bit(true));
520                    bounded_loop!(
521                        cr1!(self.regs).read().ue().bit_is_clear(),
522                        Error::RegisterUnchanged
523                    );
524                }
525
526                cr1!(self.regs).modify(|_, w| w.cmie().bit(true));
527            }
528            UsartInterrupt::Cts => {
529                self.regs.cr3().modify(|_, w| w.ctsie().bit(true));
530            }
531            UsartInterrupt::Idle => {
532                cr1!(self.regs).modify(|_, w| w.idleie().bit(true));
533            }
534            UsartInterrupt::FramingError => {
535                self.regs.cr3().modify(|_, w| w.eie().bit(true));
536            }
537            UsartInterrupt::Overrun => {
538                self.regs.cr3().modify(|_, w| w.eie().bit(true));
539            }
540            UsartInterrupt::ParityError => {
541                cr1!(self.regs).modify(|_, w| w.peie().bit(true));
542            }
543            UsartInterrupt::ReadNotEmpty => {
544                #[cfg(feature = "h5")]
545                cr1!(self.regs).modify(|_, w| w.rxfneie().bit(true));
546                #[cfg(not(feature = "h5"))]
547                cr1!(self.regs).modify(|_, w| w.rxneie().bit(true));
548            }
549            UsartInterrupt::TransmissionComplete => {
550                cr1!(self.regs).modify(|_, w| w.tcie().bit(true));
551            }
552            UsartInterrupt::TransmitEmpty => {
553                #[cfg(feature = "h5")]
554                cr1!(self.regs).modify(|_, w| w.txfeie().bit(true));
555                #[cfg(not(feature = "h5"))]
556                cr1!(self.regs).modify(|_, w| w.txeie().bit(true));
557            }
558            _ => panic!(), // UART interrupts not avail on LPUART
559        }
560        Ok(())
561    }
562
563    #[cfg(not(feature = "f4"))]
564    /// Disable a specific type of interrupt. See G4 RM, Table 349: USART interrupt requests.
565    /// Note that the inner value of `CharDetect` doesn't do anything here.
566    pub fn disable_interrupt(&mut self, interrupt: UsartInterrupt) {
567        match interrupt {
568            UsartInterrupt::CharDetect(_) => {
569                cr1!(self.regs).modify(|_, w| w.cmie().clear_bit());
570            }
571            UsartInterrupt::Cts => {
572                self.regs.cr3().modify(|_, w| w.ctsie().clear_bit());
573            }
574            UsartInterrupt::Idle => {
575                cr1!(self.regs).modify(|_, w| w.idleie().clear_bit());
576            }
577            UsartInterrupt::FramingError => {
578                self.regs.cr3().modify(|_, w| w.eie().clear_bit());
579            }
580            UsartInterrupt::Overrun => {
581                self.regs.cr3().modify(|_, w| w.eie().clear_bit());
582            }
583            UsartInterrupt::ParityError => {
584                cr1!(self.regs).modify(|_, w| w.peie().clear_bit());
585            }
586            UsartInterrupt::ReadNotEmpty => {
587                #[cfg(feature = "h5")]
588                cr1!(self.regs).modify(|_, w| w.rxfneie().clear_bit());
589                #[cfg(not(feature = "h5"))]
590                cr1!(self.regs).modify(|_, w| w.rxneie().clear_bit());
591            }
592            #[cfg(not(any(feature = "f3", feature = "l4")))]
593            UsartInterrupt::TransmissionComplete => {
594                cr1!(self.regs).modify(|_, w| w.tcie().clear_bit());
595            }
596            UsartInterrupt::TransmitEmpty => {
597                #[cfg(feature = "h5")]
598                cr1!(self.regs).modify(|_, w| w.txfeie().clear_bit());
599                #[cfg(not(feature = "h5"))]
600                cr1!(self.regs).modify(|_, w| w.txeie().clear_bit());
601            }
602            _ => panic!(), // UART interrupts not avail on LPUART
603        }
604    }
605
606    #[cfg(not(feature = "f4"))]
607    /// Print the (raw) contents of the status register.
608    pub fn read_status(&self) -> u32 {
609        unsafe { isr!(self.regs).read().bits() }
610    }
611
612    #[cfg(not(feature = "f4"))]
613    /// Clears the interrupt pending flag for a specific type of interrupt. Note that
614    /// it can also clear error flags, like Overrun and framing errors. See G4 RM,
615    /// Table 349: USART interrupt requests.
616    /// Note that the inner value of `CharDetect` doesn't do anything here.
617    pub fn clear_interrupt(&mut self, interrupt: UsartInterrupt) {
618        match interrupt {
619            UsartInterrupt::CharDetect(_) => self.regs.icr().write(|w| w.cmcf().bit(true)),
620            UsartInterrupt::Cts => self.regs.icr().write(|w| w.ctscf().bit(true)),
621            UsartInterrupt::Idle => self.regs.icr().write(|w| w.idlecf().bit(true)),
622            UsartInterrupt::FramingError => self.regs.icr().write(|w| w.fecf().bit(true)),
623            UsartInterrupt::Overrun => self.regs.icr().write(|w| w.orecf().bit(true)),
624            UsartInterrupt::ParityError => self.regs.icr().write(|w| w.pecf().bit(true)),
625            UsartInterrupt::ReadNotEmpty => self.regs.rqr().write(|w| w.rxfrq().bit(true)),
626            UsartInterrupt::TransmissionComplete => self.regs.icr().write(|w| w.tccf().bit(true)),
627            UsartInterrupt::TransmitEmpty => self.regs.rqr().write(|w| w.txfrq().bit(true)),
628            _ => panic!(), // UART interrupts not avail on LPUART
629        };
630    }
631
632    #[cfg(not(feature = "f4"))]
633    /// Checks if a given status flag is set. Returns `true` if the status flag is set. Note that this preforms
634    /// a read each time called. If checking multiple flags, this isn't optimal.
635    pub fn check_status_flag(&mut self, flag: UsartInterrupt) -> bool {
636        let status = isr!(self.regs).read();
637
638        match flag {
639            UsartInterrupt::CharDetect(_) => status.cmf().bit_is_set(),
640            UsartInterrupt::Cts => status.cts().bit_is_set(),
641            UsartInterrupt::Idle => status.idle().bit_is_set(),
642            UsartInterrupt::FramingError => status.fe().bit_is_set(),
643            UsartInterrupt::Overrun => status.ore().bit_is_set(),
644            UsartInterrupt::ParityError => status.pe().bit_is_set(),
645            #[cfg(feature = "h5")]
646            UsartInterrupt::ReadNotEmpty => status.rxfne().bit_is_set(),
647            #[cfg(not(feature = "h5"))]
648            UsartInterrupt::ReadNotEmpty => status.rxne().bit_is_set(),
649            UsartInterrupt::TransmissionComplete => status.tc().bit_is_set(),
650            #[cfg(feature = "h5")]
651            UsartInterrupt::TransmitEmpty => status.txfe().bit_is_set(),
652            #[cfg(not(feature = "h5"))]
653            UsartInterrupt::TransmitEmpty => status.txe().bit_is_set(),
654            _ => panic!(), // UART interrupts not avail on LPUART
655        }
656    }
657
658    fn check_status(&mut self) -> Result<()> {
659        let status = isr!(self.regs).read();
660        let mut result = if status.pe().bit_is_set() {
661            Err(Error::UsartError(UsartError::Parity))
662        } else if status.fe().bit_is_set() {
663            Err(Error::UsartError(UsartError::Framing))
664        } else if status.ore().bit_is_set() {
665            Err(Error::UsartError(UsartError::Overrun))
666        } else {
667            Ok(())
668        };
669
670        #[cfg(not(any(feature = "wl", feature = "h7")))]
671        if status.nf().bit_is_set() {
672            result = Err(Error::UsartError(UsartError::Noise));
673        }
674        #[cfg(feature = "h7")]
675        if status.ne().bit_is_set() {
676            // todo: QC
677            result = Err(Error::UsartError(UsartError::Noise));
678        }
679
680        if result.is_err() {
681            // For F4, clear error flags by reading SR and DR
682            // For others, clear error flags by reading ISR, clearing ICR, then reading RDR
683            cfg_if! {
684                if #[cfg(feature = "f4")] {
685                    let _ = self.regs.dr().read();
686                } else {
687                    self.regs.icr().write(|w| {
688                        w.pecf().bit(true);
689                        w.fecf().bit(true);
690                        w.ncf().bit(true);
691                        w.orecf().bit(true)
692                    });
693                    let _ = self.regs.rdr().read();
694                }
695            }
696        }
697        result
698    }
699}
700
701#[cfg(feature = "embedded_hal")]
702mod embedded_io_impl {
703    use embedded_io::{ErrorType, Read, ReadReady, Write, WriteReady};
704
705    use super::*;
706
707    impl<R> ErrorType for LpUart<R> {
708        type Error = crate::error::Error;
709    }
710
711    impl<R> Read for LpUart<R>
712    where
713        R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph + BaudPeriph,
714        LpUart<R>: ReadReady,
715    {
716        fn read(&mut self, mut buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
717            // Block until at least one byte can be read:
718            while !self.read_ready()? {
719                cortex_m::asm::nop();
720            }
721
722            let buf_len = buf.len();
723            while !buf.is_empty() && self.read_ready()? {
724                let (first, remaining) = buf.split_first_mut().unwrap();
725                *first = self.read_one();
726                buf = remaining;
727            }
728            Ok(buf_len - buf.len())
729        }
730    }
731
732    impl<R> ReadReady for LpUart<R>
733    where
734        R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph + BaudPeriph,
735    {
736        fn read_ready(&mut self) -> core::result::Result<bool, Self::Error> {
737            self.check_status()?;
738            cfg_if! {
739                if #[cfg(feature = "h5")] {
740                    let ready = isr!(self.regs).read().rxfne().bit_is_set();
741                } else {
742                    let ready = isr!(self.regs).read().rxne().bit_is_set();
743                }
744            };
745            Ok(ready)
746        }
747    }
748
749    impl<R> Write for LpUart<R>
750    where
751        R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph + BaudPeriph,
752    {
753        fn write(&mut self, mut buf: &[u8]) -> core::result::Result<usize, Self::Error> {
754            // Block until at least one byte can be written:
755            while !self.write_ready()? {
756                cortex_m::asm::nop();
757            }
758            let buf_len = buf.len();
759
760            while !buf.is_empty() && self.write_ready()? {
761                let (byte, remaining) = buf.split_first().unwrap();
762                self.write_one(*byte);
763                buf = remaining;
764            }
765            Ok(buf_len - buf.len())
766        }
767
768        fn flush(&mut self) -> core::result::Result<(), Self::Error> {
769            // fixme
770            while isr!(self.regs).read().tc().bit_is_clear() {
771                cortex_m::asm::nop();
772            }
773            Ok(())
774        }
775    }
776
777    impl<R> WriteReady for LpUart<R>
778    where
779        R: Deref<Target = pac::lpuart1::RegisterBlock> + RccPeriph + BaudPeriph,
780    {
781        fn write_ready(&mut self) -> core::result::Result<bool, Self::Error> {
782            cfg_if! {
783                if #[cfg(feature = "h5")] {
784                    let ready = isr!(self.regs).read().txfe().bit_is_set();
785                } else {
786                    let ready = isr!(self.regs).read().txe().bit_is_set();
787                }
788            };
789            Ok(ready)
790        }
791    }
792}