stm32wlxx_hal/
uart.rs

1//! Universal synchronous/asynchronous receiver transmitter
2use crate::{
3    dma::{self, DmaCh},
4    gpio::{self},
5    pac, rcc, Ratio,
6};
7use cortex_m::interrupt::CriticalSection;
8use embedded_hal::prelude::*;
9
10typestate!(NoRx, "no RX on a generic UART structure");
11typestate!(NoTx, "no TX on a generic UART structure");
12
13/// UART clock selection.
14#[derive(Debug)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[repr(u8)]
17pub enum Clk {
18    /// PCLK
19    PClk = 0b00,
20    /// System clock
21    Sysclk = 0b01,
22    /// HSI16 clock
23    Hsi16 = 0b10,
24    /// LSE clock
25    Lse = 0b11,
26}
27
28/// UART errors.
29#[derive(Debug)]
30#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31pub enum Error {
32    /// Overrun.
33    Overrun,
34    /// Start bit noise detected.
35    Noise,
36    /// Framing error.
37    Framing,
38    /// Parity error.
39    Parity,
40    /// RX DMA error
41    ///
42    /// This can only occur on UART transfers that use the RX DMA.
43    RxDma,
44    /// TX DMA error
45    ///
46    /// This can only occur on UART transfers that use the TX DMA.
47    TxDma,
48}
49
50/// UART1 driver.
51#[derive(Debug)]
52pub struct Uart1<RX, TX> {
53    uart: pac::USART1,
54    rx: RX,
55    tx: TX,
56}
57
58/// UART2 driver.
59#[derive(Debug)]
60pub struct Uart2<RX, TX> {
61    uart: pac::USART2,
62    rx: RX,
63    tx: TX,
64}
65
66/// Low-power UART driver.
67#[derive(Debug)]
68pub struct LpUart<RX, TX> {
69    uart: pac::LPUART,
70    rx: RX,
71    tx: TX,
72}
73
74impl LpUart<NoRx, NoTx> {
75    /// Create a new LPUART driver from a LPUART peripheral.
76    ///
77    /// This will enable clocks and reset the LPUART peripheral.
78    ///
79    /// # Panics
80    ///
81    /// * Source frequency is not between 3× and 4096× the baud rate
82    /// * The derived baud rate register value is less than `0x300`
83    ///
84    /// # Example
85    ///
86    /// ```no_run
87    /// use stm32wlxx_hal::{
88    ///     pac,
89    ///     uart::{self, LpUart, NoRx, NoTx},
90    /// };
91    ///
92    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
93    ///
94    /// // enable the HSI16 source clock
95    /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
96    /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
97    ///
98    /// let uart: LpUart<NoRx, NoTx> = LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC);
99    /// ```
100    pub fn new(uart: pac::LPUART, baud: u32, clk: Clk, rcc: &mut pac::RCC) -> LpUart<NoRx, NoTx> {
101        unsafe { Self::pulse_reset(rcc) };
102        Self::enable_clock(rcc);
103
104        rcc.ccipr.modify(|_, w| w.lpuart1sel().bits(clk as u8));
105
106        let ret: LpUart<NoRx, NoTx> = LpUart {
107            uart,
108            rx: NoRx::new(),
109            tx: NoTx::new(),
110        };
111
112        let baud: u64 = baud.into();
113        let freq: u64 = ret.clock_hz(rcc).into();
114        assert!(freq >= baud.saturating_mul(3) && freq <= baud.saturating_mul(4096));
115
116        let br: u32 = ((freq * 256) / baud) as u32;
117        assert!(br >= 0x300);
118        ret.uart.brr.write(|w| unsafe { w.brr().bits(br) });
119        ret.uart.cr1.write(|w| w.ue().set_bit().fifoen().set_bit());
120
121        ret
122    }
123}
124
125impl Uart1<NoRx, NoTx> {
126    /// Create a new UART driver from a UART peripheral.
127    ///
128    /// This will enable clocks and reset the UART peripheral.
129    ///
130    /// # Example
131    ///
132    /// ```no_run
133    /// use stm32wlxx_hal::{
134    ///     pac,
135    ///     uart::{self, NoRx, NoTx, Uart1},
136    /// };
137    ///
138    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
139    ///
140    /// // enable the HSI16 source clock
141    /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
142    /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
143    ///
144    /// let uart: Uart1<NoRx, NoTx> = Uart1::new(dp.USART1, 115_200, uart::Clk::Hsi16, &mut dp.RCC);
145    /// ```
146    pub fn new(uart: pac::USART1, baud: u32, clk: Clk, rcc: &mut pac::RCC) -> Uart1<NoRx, NoTx> {
147        unsafe { Self::pulse_reset(rcc) };
148        Self::enable_clock(rcc);
149
150        rcc.ccipr.modify(|_, w| w.usart1sel().bits(clk as u8));
151
152        let ret: Uart1<NoRx, NoTx> = Uart1 {
153            uart,
154            rx: NoRx::new(),
155            tx: NoTx::new(),
156        };
157
158        let freq: u32 = ret.clock_hz(rcc);
159
160        // only for oversampling of 16 (default), change for oversampling of 8
161        let br: u16 = (freq / baud) as u16;
162        ret.uart.brr.write(|w| w.brr().bits(br));
163        ret.uart.cr1.write(|w| w.ue().set_bit().fifoen().set_bit());
164
165        ret
166    }
167}
168
169impl Uart2<NoRx, NoTx> {
170    /// Create a new UART driver from a UART peripheral.
171    ///
172    /// This will enable clocks and reset the UART peripheral.
173    ///
174    /// # Example
175    ///
176    /// ```no_run
177    /// use stm32wlxx_hal::{
178    ///     pac,
179    ///     uart::{self, NoRx, NoTx, Uart2},
180    /// };
181    ///
182    /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
183    ///
184    /// // enable the HSI16 source clock
185    /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
186    /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
187    ///
188    /// let uart: Uart2<NoRx, NoTx> = Uart2::new(dp.USART2, 115_200, uart::Clk::Hsi16, &mut dp.RCC);
189    /// ```
190    pub fn new(uart: pac::USART2, baud: u32, clk: Clk, rcc: &mut pac::RCC) -> Uart2<NoRx, NoTx> {
191        unsafe { Self::pulse_reset(rcc) };
192        Self::enable_clock(rcc);
193
194        rcc.ccipr.modify(|_, w| w.usart2sel().bits(clk as u8));
195
196        let ret: Uart2<NoRx, NoTx> = Uart2 {
197            uart,
198            rx: NoRx::new(),
199            tx: NoTx::new(),
200        };
201
202        let freq: u32 = ret.clock_hz(rcc);
203
204        // only for oversampling of 16 (default), change for oversampling of 8
205        let br: u16 = (freq / baud) as u16;
206        ret.uart.brr.write(|w| w.brr().bits(br));
207        ret.uart.cr1.write(|w| w.ue().set_bit().fifoen().set_bit());
208
209        ret
210    }
211}
212
213const LPUART_BASE: usize = 0x4000_8000;
214const UART1_BASE: usize = 0x4001_3800;
215const UART2_BASE: usize = 0x4000_4400;
216const RDR_OFFSET: usize = 0x24;
217const TDR_OFFSET: usize = 0x28;
218
219macro_rules! impl_consts {
220    ($uart:ident, $rx_req_id:expr, $tx_req_id:expr, $base:expr) => {
221        impl<RX, TX> $uart<RX, TX> {
222            const DMA_RX_ID: u8 = $rx_req_id;
223            const DMA_TX_ID: u8 = $tx_req_id;
224            const RDR: usize = $base + RDR_OFFSET;
225            const TDR: usize = $base + TDR_OFFSET;
226        }
227    };
228}
229
230impl_consts!(LpUart, 21, 22, LPUART_BASE);
231impl_consts!(Uart1, 17, 18, UART1_BASE);
232impl_consts!(Uart2, 19, 20, UART2_BASE);
233
234macro_rules! impl_clock_hz {
235    ($uart:ident, $sel:ident, $presc:ident, $method:ident, $pclk_method:ident) => {
236        impl<RX, TX> $uart<RX, TX> {
237            /// Calculate the clock frequency.
238            ///
239            /// Fractional frequencies will be rounded towards zero.
240            pub fn clock_hz(&self, rcc: &pac::RCC) -> u32 {
241                use pac::{rcc::ccipr::$sel, $presc::presc::PRESCALER_A};
242                let src: Ratio<u32> = match rcc.ccipr.read().$method().variant() {
243                    $sel::Pclk => {
244                        let cfgr: pac::rcc::cfgr::R = rcc.cfgr.read();
245                        rcc::$pclk_method(rcc, &cfgr)
246                    }
247                    $sel::Sysclk => {
248                        let cfgr: pac::rcc::cfgr::R = rcc.cfgr.read();
249                        rcc::sysclk(rcc, &cfgr)
250                    }
251                    $sel::Hsi16 => Ratio::new_raw(16_000_000, 1),
252                    $sel::Lse => Ratio::new_raw(32_768, 1),
253                };
254                let pre: u32 = match self.uart.presc.read().prescaler().variant() {
255                    Some(p) => match p {
256                        PRESCALER_A::Div1 => 1,
257                        PRESCALER_A::Div2 => 2,
258                        PRESCALER_A::Div4 => 4,
259                        PRESCALER_A::Div6 => 6,
260                        PRESCALER_A::Div8 => 8,
261                        PRESCALER_A::Div10 => 10,
262                        PRESCALER_A::Div12 => 12,
263                        PRESCALER_A::Div16 => 16,
264                        PRESCALER_A::Div32 => 32,
265                        PRESCALER_A::Div64 => 64,
266                        PRESCALER_A::Div128 => 128,
267                        PRESCALER_A::Div256 => 256,
268                    },
269                    None => 256,
270                };
271                (src / pre).to_integer()
272            }
273        }
274    };
275}
276
277impl_clock_hz!(LpUart, LPUART1SEL_A, lpuart, lpuart1sel, pclk1);
278impl_clock_hz!(Uart1, USART1SEL_A, usart1, usart1sel, pclk2);
279impl_clock_hz!(Uart2, USART1SEL_A, usart1, usart2sel, pclk1);
280
281macro_rules! impl_pulse_reset {
282    ($uart:ident, $reg:ident, $method:ident) => {
283        impl $uart<NoRx, NoTx> {
284            /// Reset the UART.
285            ///
286            /// # Safety
287            ///
288            /// 1. The UART must not be in-use.
289            /// 2. You are responsible for setting up the UART after a reset.
290            ///
291            /// # Example
292            ///
293            /// See [`steal`](Self::steal)
294            pub unsafe fn pulse_reset(rcc: &mut pac::RCC) {
295                rcc.$reg.modify(|_, w| w.$method().set_bit());
296                rcc.$reg.modify(|_, w| w.$method().clear_bit());
297            }
298        }
299    };
300}
301
302impl_pulse_reset!(LpUart, apb1rstr2, lpuart1rst);
303impl_pulse_reset!(Uart1, apb2rstr, usart1rst);
304impl_pulse_reset!(Uart2, apb1rstr1, usart2rst);
305
306macro_rules! impl_clock_en_dis {
307    ($uart:ident, $reg:ident, $method:ident) => {
308        impl $uart<NoRx, NoTx> {
309            /// Enable the UART clock.
310            ///
311            /// This is done for you in [`new`](Self::new)
312            ///
313            /// # Example
314            ///
315            /// ```no_run
316            /// use stm32wlxx_hal::{pac, uart::LpUart};
317            ///
318            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
319            /// LpUart::enable_clock(&mut dp.RCC);
320            /// ```
321            pub fn enable_clock(rcc: &mut pac::RCC) {
322                rcc.$reg.modify(|_, w| w.$method().enabled())
323            }
324
325            /// Disable the UART clock.
326            ///
327            /// # Safety
328            ///
329            /// 1. You are responsible for ensuring the UART is in a state where
330            ///    the clock can be disabled without entering an error state.
331            /// 2. You cannot use the UART while the clock is disabled.
332            /// 3. You are responsible for re-enabling the clock before resuming
333            ///    use of the UART.
334            /// 4. You are responsible for setting up anything that may have lost
335            ///    state while the clock was disabled.
336            pub unsafe fn disable_clock(rcc: &mut pac::RCC) {
337                rcc.$reg.modify(|_, w| w.$method().disabled())
338            }
339        }
340    };
341}
342
343impl_clock_en_dis!(LpUart, apb1enr2, lpuart1en);
344impl_clock_en_dis!(Uart1, apb2enr, usart1en);
345impl_clock_en_dis!(Uart2, apb1enr1, usart2en);
346
347macro_rules! impl_free_steal {
348    ($uart:ident, $periph:ident) => {
349        impl $uart<NoRx, NoTx> {
350            /// Steal the UART peripheral from whatever is currently using it.
351            ///
352            /// This will **not** initialize the peripheral (unlike [`new`]).
353            ///
354            /// # Safety
355            ///
356            /// 1. Ensure that the code stealing the UART has exclusive access to the
357            ///    peripheral. Singleton checks are bypassed with this method.
358            /// 2. You are responsible for setting up the UART correctly.
359            ///
360            /// # Example
361            ///
362            /// ```no_run
363            /// use stm32wlxx_hal::{
364            ///     pac,
365            ///     uart::{LpUart, NoRx, NoTx},
366            /// };
367            ///
368            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
369            ///
370            /// LpUart::enable_clock(&mut dp.RCC);
371            /// // safety:
372            /// // 1. Nothing else is using the LPUART in this code.
373            /// // 2. This code performs setup for the LPUART.
374            /// unsafe { LpUart::pulse_reset(&mut dp.RCC) };
375            ///
376            /// // safety:
377            /// // 1. Nothing else is using the LPUART in this code.
378            /// // 2. The LPUART has been setup, clocks are enabled and the LPUART has been reset.
379            /// let mut lpuart: LpUart<NoRx, NoTx> = unsafe { LpUart::steal() };
380            /// ```
381            ///
382            /// [`new`]: Self::new
383            pub unsafe fn steal() -> $uart<NoRx, NoTx> {
384                $uart {
385                    uart: pac::Peripherals::steal().$periph,
386                    rx: NoRx::new(),
387                    tx: NoTx::new(),
388                }
389            }
390        }
391
392        impl<RX, TX> $uart<RX, TX> {
393            /// Free the UART peripheral from the driver.
394            ///
395            /// # Example
396            ///
397            /// ```no_run
398            /// use stm32wlxx_hal::{
399            ///     pac,
400            ///     uart::{self, LpUart, NoRx, NoTx},
401            /// };
402            ///
403            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
404            /// let lpuart: pac::LPUART = dp.LPUART;
405            ///
406            /// let lpuart: LpUart<NoRx, NoTx> =
407            ///     LpUart::new(lpuart, 115_200, uart::Clk::Hsi16, &mut dp.RCC);
408            /// // ... use LPUART
409            /// let lpuart: pac::LPUART = lpuart.free();
410            /// ```
411            pub fn free(self) -> pac::$periph {
412                self.uart
413            }
414        }
415    };
416}
417
418impl_free_steal!(LpUart, LPUART);
419impl_free_steal!(Uart1, USART1);
420impl_free_steal!(Uart2, USART2);
421
422macro_rules! impl_tx_en_dis {
423    ($uart:ident, $trt:ident, $method:ident) => {
424        impl<RX> $uart<RX, NoTx> {
425            /// Enable the UART transmitter.
426            ///
427            /// # Example
428            ///
429            /// ```no_run
430            /// use stm32wlxx_hal::{
431            ///     cortex_m,
432            ///     gpio::{pins, PortB},
433            ///     pac,
434            ///     uart::{self, LpUart, NoRx},
435            /// };
436            ///
437            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
438            ///
439            /// // enable the HSI16 source clock
440            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
441            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
442            ///
443            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
444            /// let uart: LpUart<NoRx, pins::B11> = cortex_m::interrupt::free(|cs| {
445            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
446            ///         .enable_tx(gpiob.b11, cs)
447            /// });
448            /// ```
449            pub fn enable_tx<TX: gpio::sealed::$trt>(
450                self,
451                mut tx: TX,
452                cs: &CriticalSection,
453            ) -> $uart<RX, TX> {
454                tx.$method(cs);
455                self.uart.cr1.modify(|_, w| w.te().enabled());
456                $uart {
457                    uart: self.uart,
458                    rx: self.rx,
459                    tx,
460                }
461            }
462        }
463
464        impl<RX> $uart<RX, NoTx> {
465            /// Enable the UART transmitter with a DMA channel.
466            ///
467            /// # Example
468            ///
469            /// ```no_run
470            /// use stm32wlxx_hal::{
471            ///     cortex_m,
472            ///     dma::{AllDma, Dma2Ch7},
473            ///     gpio::{pins, PortB},
474            ///     pac,
475            ///     uart::{self, LpUart, NoRx},
476            /// };
477            ///
478            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
479            ///
480            /// // enable the HSI16 source clock
481            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
482            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
483            ///
484            /// let dma: AllDma = AllDma::split(dp.DMAMUX, dp.DMA1, dp.DMA2, &mut dp.RCC);
485            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
486            /// let uart: LpUart<NoRx, (pins::B11, Dma2Ch7)> = cortex_m::interrupt::free(|cs| {
487            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
488            ///         .enable_tx_dma(gpiob.b11, dma.d2.c7, cs)
489            /// });
490            /// ```
491            pub fn enable_tx_dma<TxPin: gpio::sealed::$trt, TxDma: DmaCh>(
492                self,
493                mut tx: TxPin,
494                mut tx_dma: TxDma,
495                cs: &CriticalSection,
496            ) -> $uart<RX, (TxPin, TxDma)> {
497                tx.$method(cs);
498                self.uart.cr1.modify(|_, w| w.te().enabled());
499                self.uart.cr3.modify(|_, w| w.dmat().enabled());
500
501                tx_dma.set_cr(dma::Cr::DISABLE);
502                tx_dma.clear_all_flags();
503                tx_dma.set_periph_addr(Self::TDR as u32);
504                tx_dma.set_mux_cr_reqid(Self::DMA_TX_ID);
505
506                $uart {
507                    uart: self.uart,
508                    rx: self.rx,
509                    tx: (tx, tx_dma),
510                }
511            }
512        }
513
514        impl<RX, TX> $uart<RX, TX> {
515            /// Disable the UART transmitter.
516            ///
517            /// # Example
518            ///
519            /// ```no_run
520            /// use stm32wlxx_hal::{
521            ///     cortex_m,
522            ///     gpio::{pins, PortB},
523            ///     pac,
524            ///     uart::{self, LpUart, NoRx, NoTx},
525            /// };
526            ///
527            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
528            ///
529            /// // enable the HSI16 source clock
530            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
531            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
532            ///
533            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
534            /// let uart: LpUart<NoRx, pins::B11> = cortex_m::interrupt::free(|cs| {
535            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
536            ///         .enable_tx(gpiob.b11, cs)
537            /// });
538            ///
539            /// let (uart, b11): (LpUart<NoRx, NoTx>, pins::B11) = uart.disable_tx();
540            /// ```
541            pub fn disable_tx(self) -> ($uart<RX, NoTx>, TX) {
542                self.uart.cr1.modify(|_, w| w.te().disabled());
543                self.uart.cr3.modify(|_, w| w.dmat().disabled());
544                (
545                    $uart {
546                        uart: self.uart,
547                        rx: self.rx,
548                        tx: NoTx::new(),
549                    },
550                    self.tx,
551                )
552            }
553        }
554    };
555}
556
557impl_tx_en_dis!(LpUart, LpUart1Tx, set_lpuart1_tx_af);
558impl_tx_en_dis!(Uart1, Uart1Tx, set_uart1_tx_af);
559impl_tx_en_dis!(Uart2, Uart2Tx, set_uart2_tx_af);
560
561macro_rules! impl_rx_en_dis {
562    ($uart:ident, $trt:ident, $method:ident) => {
563        impl<TX> $uart<NoRx, TX> {
564            /// Enable the UART receiver.
565            ///
566            /// # Example
567            ///
568            /// ```no_run
569            /// use stm32wlxx_hal::{
570            ///     cortex_m,
571            ///     gpio::{pins, PortB},
572            ///     pac,
573            ///     uart::{self, LpUart, NoTx},
574            /// };
575            ///
576            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
577            ///
578            /// // enable the HSI16 source clock
579            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
580            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
581            ///
582            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
583            /// let uart: LpUart<pins::B10, NoTx> = cortex_m::interrupt::free(|cs| {
584            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
585            ///         .enable_rx(gpiob.b10, cs)
586            /// });
587            /// ```
588            pub fn enable_rx<RX: gpio::sealed::$trt>(
589                self,
590                mut rx: RX,
591                cs: &CriticalSection,
592            ) -> $uart<RX, TX> {
593                rx.$method(cs);
594                self.uart.cr1.modify(|_, w| w.re().enabled());
595                $uart {
596                    uart: self.uart,
597                    rx,
598                    tx: self.tx,
599                }
600            }
601        }
602
603        impl<TX> $uart<NoRx, TX> {
604            /// Enable the UART receiver with a DMA channel.
605            ///
606            /// # Example
607            ///
608            /// ```no_run
609            /// use stm32wlxx_hal::{
610            ///     dma::{AllDma, Dma2Ch2},
611            ///     gpio::{pins, PortB},
612            ///     pac,
613            ///     uart::{self, LpUart, NoTx},
614            /// };
615            ///
616            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
617            ///
618            /// // enable the HSI16 source clock
619            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
620            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
621            ///
622            /// let dma: AllDma = AllDma::split(dp.DMAMUX, dp.DMA1, dp.DMA2, &mut dp.RCC);
623            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
624            /// let uart: LpUart<(pins::B10, Dma2Ch2), NoTx> = cortex_m::interrupt::free(|cs| {
625            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
626            ///         .enable_rx_dma(gpiob.b10, dma.d2.c2, cs)
627            /// });
628            /// ```
629            pub fn enable_rx_dma<RxPin: gpio::sealed::$trt, RxDma: DmaCh>(
630                self,
631                mut rx: RxPin,
632                mut rx_dma: RxDma,
633                cs: &CriticalSection,
634            ) -> $uart<(RxPin, RxDma), TX> {
635                rx.$method(cs);
636                self.uart.cr1.modify(|_, w| w.re().enabled());
637                self.uart.cr3.modify(|_, w| w.dmar().enabled());
638
639                rx_dma.set_cr(dma::Cr::DISABLE);
640                rx_dma.clear_all_flags();
641                rx_dma.set_periph_addr(Self::RDR as u32);
642                rx_dma.set_mux_cr_reqid(Self::DMA_RX_ID);
643
644                $uart {
645                    uart: self.uart,
646                    rx: (rx, rx_dma),
647                    tx: self.tx,
648                }
649            }
650        }
651
652        impl<RX, TX> $uart<RX, TX> {
653            /// Disable the UART receiver.
654            ///
655            /// # Example
656            ///
657            /// ```no_run
658            /// use stm32wlxx_hal::{
659            ///     gpio::{pins, PortB},
660            ///     pac,
661            ///     uart::{self, LpUart, NoRx, NoTx},
662            /// };
663            ///
664            /// let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
665            ///
666            /// // enable the HSI16 source clock
667            /// dp.RCC.cr.modify(|_, w| w.hsion().set_bit());
668            /// while dp.RCC.cr.read().hsirdy().is_not_ready() {}
669            ///
670            /// let gpiob: PortB = PortB::split(dp.GPIOB, &mut dp.RCC);
671            /// let uart: LpUart<pins::B10, NoTx> = cortex_m::interrupt::free(|cs| {
672            ///     LpUart::new(dp.LPUART, 115_200, uart::Clk::Hsi16, &mut dp.RCC)
673            ///         .enable_rx(gpiob.b10, cs)
674            /// });
675            ///
676            /// let (uart, b10): (LpUart<NoRx, NoTx>, pins::B10) = uart.disable_rx();
677            /// ```
678            pub fn disable_rx(self) -> ($uart<NoRx, TX>, RX) {
679                self.uart.cr1.modify(|_, w| w.re().disabled());
680                self.uart.cr3.modify(|_, w| w.dmar().disabled());
681                (
682                    $uart {
683                        uart: self.uart,
684                        rx: NoRx::new(),
685                        tx: self.tx,
686                    },
687                    self.rx,
688                )
689            }
690        }
691    };
692}
693
694impl_rx_en_dis!(LpUart, LpUart1Rx, set_lpuart1_rx_af);
695impl_rx_en_dis!(Uart1, Uart1Rx, set_uart1_rx_af);
696impl_rx_en_dis!(Uart2, Uart2Rx, set_uart2_rx_af);
697
698macro_rules! impl_status {
699    ($uart:ident, $pacmod:ident) => {
700        impl<RX, TX> $uart<RX, TX> {
701            #[inline]
702            fn status(&self) -> Result<pac::$pacmod::isr::R, Error> {
703                let isr = self.uart.isr.read();
704                if isr.pe().bit_is_set() {
705                    Err(Error::Parity)
706                } else if isr.fe().bit_is_set() {
707                    Err(Error::Framing)
708                } else if isr.ne().bit_is_set() {
709                    Err(Error::Noise)
710                } else if isr.ore().bit_is_set() {
711                    Err(Error::Overrun)
712                } else {
713                    Ok(isr)
714                }
715            }
716        }
717    };
718}
719
720impl_status!(LpUart, lpuart);
721impl_status!(Uart1, usart1);
722impl_status!(Uart2, usart1);
723
724macro_rules! impl_eh_traits {
725    ($uart:ident, $rx_trait:ident, $tx_trait:ident, $rxne:ident, $txnf:ident) => {
726        impl<RX, TX> embedded_hal::serial::Write<u8> for $uart<RX, TX>
727        where
728            TX: gpio::sealed::$tx_trait,
729        {
730            type Error = Error;
731
732            #[inline]
733            fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
734                if self.status()?.$txnf().bit_is_set() {
735                    self.uart.tdr.write(|w| w.tdr().bits(word as u16));
736                    Ok(())
737                } else {
738                    Err(nb::Error::WouldBlock)
739                }
740            }
741
742            #[inline]
743            fn flush(&mut self) -> nb::Result<(), Self::Error> {
744                if self.status()?.busy().bit_is_set() {
745                    Err(nb::Error::WouldBlock)
746                } else {
747                    Ok(())
748                }
749            }
750        }
751
752        impl<RX, TxPin, TxDma> embedded_hal::blocking::serial::Write<u8>
753            for $uart<RX, (TxPin, TxDma)>
754        where
755            TxPin: gpio::sealed::$tx_trait,
756            TxDma: DmaCh,
757        {
758            type Error = Error;
759
760            fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
761                if buffer.is_empty() {
762                    return Ok(());
763                }
764
765                const CR: dma::Cr = dma::Cr::RESET
766                    .set_dir_from_mem()
767                    .set_mem_inc(true)
768                    .set_enable(true);
769
770                self.tx.1.set_mem_addr(buffer.as_ptr() as u32);
771
772                let ndt: u32 = buffer.len() as u32;
773                self.tx.1.set_num_data_xfer(ndt);
774
775                self.tx.1.set_cr(CR);
776
777                let ret: Result<(), Error> = loop {
778                    self.status()?;
779                    let dma_flags: u8 = self.tx.1.flags();
780                    if dma_flags & dma::flags::XFER_ERR != 0 {
781                        break Err(Error::TxDma);
782                    } else if dma_flags & dma::flags::XFER_CPL != 0 {
783                        break Ok(());
784                    }
785                };
786
787                self.tx.1.set_cr(dma::Cr::DISABLE);
788                self.tx.1.clear_all_flags();
789
790                ret
791            }
792
793            #[inline]
794            fn bflush(&mut self) -> Result<(), Self::Error> {
795                while self.status()?.busy().bit_is_set() {}
796                Ok(())
797            }
798        }
799
800        impl<RX, TX> embedded_hal::serial::Read<u8> for $uart<RX, TX>
801        where
802            RX: gpio::sealed::$rx_trait,
803        {
804            type Error = Error;
805
806            #[inline]
807            fn read(&mut self) -> nb::Result<u8, Self::Error> {
808                if self.status()?.$rxne().bit_is_set() {
809                    Ok(self.uart.rdr.read().rdr().bits() as u8)
810                } else {
811                    Err(nb::Error::WouldBlock)
812                }
813            }
814        }
815
816        impl<RxPin, RxDma, TX> $uart<(RxPin, RxDma), TX>
817        where
818            RxPin: gpio::sealed::$rx_trait,
819            RxDma: DmaCh,
820        {
821            /// This is not an embedded-hal trait, it is added simply for
822            /// parity with what exists on the TX side.
823            pub fn bread_all(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
824                if buffer.is_empty() {
825                    return Ok(());
826                }
827
828                const CR: dma::Cr = dma::Cr::RESET
829                    .set_dir_from_periph()
830                    .set_mem_inc(true)
831                    .set_enable(true);
832
833                self.rx.1.set_mem_addr(buffer.as_ptr() as u32);
834
835                let ndt: u32 = buffer.len() as u32;
836                self.rx.1.set_num_data_xfer(ndt);
837
838                self.rx.1.set_cr(CR);
839
840                let ret: Result<(), Error> = loop {
841                    self.status()?;
842                    let dma_flags: u8 = self.rx.1.flags();
843                    if dma_flags & dma::flags::XFER_ERR != 0 {
844                        break Err(Error::TxDma);
845                    } else if dma_flags & dma::flags::XFER_CPL != 0 {
846                        break Ok(());
847                    }
848                };
849
850                self.rx.1.set_cr(dma::Cr::DISABLE);
851                self.rx.1.clear_all_flags();
852
853                ret
854            }
855        }
856
857        impl<RX, TX> core::fmt::Write for $uart<RX, TX>
858        where
859            $uart<RX, TX>: embedded_hal::serial::Write<u8>,
860        {
861            fn write_str(&mut self, s: &str) -> core::fmt::Result {
862                let _ = s
863                    .as_bytes()
864                    .into_iter()
865                    .map(|c| nb::block!(self.write(*c)))
866                    .last();
867                Ok(())
868            }
869        }
870    };
871}
872
873impl_eh_traits!(LpUart, LpUart1Rx, LpUart1Tx, rxfne, txfnf);
874impl_eh_traits!(Uart1, Uart1Rx, Uart1Tx, rxne, txe);
875impl_eh_traits!(Uart2, Uart2Rx, Uart2Tx, rxne, txe);