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}