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);