aboutsummaryrefslogtreecommitdiff
path: root/embassy-nxp/src/usart
diff options
context:
space:
mode:
authorRoi Bachynskyi <[email protected]>2025-08-02 20:45:01 +0300
committerRoi Bachynskyi <[email protected]>2025-08-12 08:49:49 +0300
commitf3f819fc37720c1cbe24834df255cae9bfe68eb9 (patch)
tree0e953e4129603079fdc2dda8f7a92c0639ced1c8 /embassy-nxp/src/usart
parentcae93c5a27d596c9371b81c896598ce1a7fdaa83 (diff)
feat: lpc55 blocking usart added
Diffstat (limited to 'embassy-nxp/src/usart')
-rw-r--r--embassy-nxp/src/usart/lpc55.rs885
1 files changed, 885 insertions, 0 deletions
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
new file mode 100644
index 000000000..3f7456a2e
--- /dev/null
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -0,0 +1,885 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::{Peri, PeripheralType};
4use embedded_io::{self, ErrorKind};
5pub use sealed::SealedInstance;
6
7use crate::gpio::AnyPin;
8use crate::{Blocking, Mode};
9
10/// Serial error
11#[derive(Debug, Eq, PartialEq, Copy, Clone)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13#[non_exhaustive]
14pub enum Error {
15 /// Triggered when the FIFO (or shift-register) is overflowed.
16 Overrun,
17 /// Triggered when there is a parity mismatch between what's received and
18 /// our settings.
19 Parity,
20 /// Triggered when the received character didn't have a valid stop bit.
21 Framing,
22 /// Triggered when the receiver detects noise
23 Noise,
24 /// Triggered when the receiver gets a break
25 Break,
26}
27
28impl embedded_io::Error for Error {
29 fn kind(&self) -> ErrorKind {
30 match self {
31 Error::Overrun => ErrorKind::Other,
32 Error::Parity => ErrorKind::InvalidData,
33 Error::Framing => ErrorKind::InvalidData,
34 Error::Noise => ErrorKind::Other,
35 Error::Break => ErrorKind::Interrupted,
36 }
37 }
38}
39/// Word length.
40#[derive(Clone, Copy, PartialEq, Eq, Debug)]
41pub enum DataBits {
42 /// 7 bits data length.
43 DataBits7,
44 /// 8 bits data length.
45 DataBits8,
46 /// 9 bits data length. The 9th bit is commonly used for addressing in multidrop mode.
47 DataBits9,
48}
49
50impl DataBits {
51 fn bits(&self) -> u8 {
52 match self {
53 Self::DataBits7 => 0b00,
54 Self::DataBits8 => 0b01,
55 Self::DataBits9 => 0b10,
56 }
57 }
58}
59
60/// Parity bit.
61#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62pub enum Parity {
63 /// No parity.
64 ParityNone,
65 /// Even parity.
66 ParityEven,
67 /// Odd parity.
68 ParityOdd,
69}
70
71impl Parity {
72 fn bits(&self) -> u8 {
73 match self {
74 Self::ParityNone => 0b00,
75 Self::ParityEven => 0b10,
76 Self::ParityOdd => 0b11,
77 }
78 }
79}
80
81/// Stop bits.
82#[derive(Clone, Copy, PartialEq, Eq, Debug)]
83pub enum StopBits {
84 /// 1 stop bit.
85 Stop1,
86 /// 2 stop bits. This setting should only be used for asynchronous communication.
87 Stop2,
88}
89
90impl StopBits {
91 fn bits(&self) -> bool {
92 return match self {
93 Self::Stop1 => false,
94 Self::Stop2 => true,
95 };
96 }
97}
98
99/// UART config.
100#[non_exhaustive]
101#[derive(Clone, Debug)]
102pub struct Config {
103 /// Baud rate.
104 pub baudrate: u32,
105 /// Word length.
106 pub data_bits: DataBits,
107 /// Stop bits.
108 pub stop_bits: StopBits,
109 /// Parity bit.
110 pub parity: Parity,
111 /// Invert the tx pin output
112 pub invert_tx: bool,
113 /// Invert the rx pin input
114 pub invert_rx: bool,
115}
116
117impl Default for Config {
118 fn default() -> Self {
119 Self {
120 baudrate: 9600,
121 data_bits: DataBits::DataBits8,
122 stop_bits: StopBits::Stop1,
123 parity: Parity::ParityNone,
124 invert_rx: false,
125 invert_tx: false,
126 }
127 }
128}
129
130/// # Type parameters
131/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time
132/// T: the peripheral instance type allowing usage of peripheral specific registers
133/// M: the operating mode of USART peripheral
134pub struct Usart<'d, T: Instance, M: Mode> {
135 tx: UsartTx<'d, T, M>,
136 rx: UsartRx<'d, T, M>,
137}
138
139pub struct UsartTx<'d, T: Instance, M: Mode> {
140 phantom: PhantomData<(&'d (), T, M)>,
141}
142
143pub struct UsartRx<'d, T: Instance, M: Mode> {
144 phantom: PhantomData<(&'d (), T, M)>,
145}
146
147impl<'d, T: Instance, M: Mode> UsartTx<'d, T, M> {
148 pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
149 Usart::<T, M>::init(Some(tx.into()), None, config);
150 Self::new_inner()
151 }
152
153 #[inline]
154 fn new_inner() -> Self {
155 Self { phantom: PhantomData }
156 }
157
158 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
159 T::blocking_write(buffer)
160 }
161
162 pub fn blocking_flush(&mut self) -> Result<(), Error> {
163 T::blocking_flush()
164 }
165
166 pub fn tx_busy(&self) -> bool {
167 T::tx_busy()
168 }
169}
170
171impl<'d, T: Instance> UsartTx<'d, T, Blocking> {
172 pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
173 Usart::<T, Blocking>::init(Some(tx.into()), None, config);
174 Self::new_inner()
175 }
176}
177
178impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> {
179 pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
180 Usart::<T, M>::init(None, Some(rx.into()), config);
181 Self::new_inner()
182 }
183
184 #[inline]
185 fn new_inner() -> Self {
186 Self { phantom: PhantomData }
187 }
188
189 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
190 while !buffer.is_empty() {
191 match Self::drain_fifo(self, buffer) {
192 Ok(0) => continue, // Wait for more data
193 Ok(n) => buffer = &mut buffer[n..],
194 Err((_, err)) => return Err(err),
195 }
196 }
197 Ok(())
198 }
199
200 /// Returns:
201 /// - Ok(n) -> read n bytes
202 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte
203 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
204 T::drain_fifo(buffer)
205 }
206}
207
208impl<'d, T: Instance> UsartRx<'d, T, Blocking> {
209 pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
210 Usart::<T, Blocking>::init(None, Some(rx.into()), config);
211 Self::new_inner()
212 }
213}
214
215impl<'d, T: Instance> Usart<'d, T, Blocking> {
216 pub fn new_blocking(
217 usart: Peri<'d, T>,
218 tx: Peri<'d, impl TxPin<T>>,
219 rx: Peri<'d, impl RxPin<T>>,
220 config: Config,
221 ) -> Self {
222 Self::new_inner(usart, tx.into(), rx.into(), config)
223 }
224}
225
226impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
227 fn new_inner(_usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, config: Config) -> Self {
228 Self::init(Some(tx.reborrow()), Some(rx.reborrow()), config);
229 Self {
230 tx: UsartTx::new_inner(),
231 rx: UsartRx::new_inner(),
232 }
233 }
234
235 fn init(_tx: Option<Peri<'_, AnyPin>>, _rx: Option<Peri<'_, AnyPin>>, config: Config) {
236 T::enable_clock();
237 T::reset_flexcomm();
238 let source_clock: u32 = T::select_clock(config.baudrate);
239 T::configure_flexcomm();
240 T::tx_pin_config();
241 T::rx_pin_config();
242 Self::set_baudrate(source_clock, config.baudrate);
243 T::configure_usart(config);
244 T::disable_dma();
245 T::enable_usart();
246 }
247
248 fn set_baudrate(source_clock: u32, baudrate: u32) {
249 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
250 // and fractional divider (fractional rate divider).
251 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15
252
253 // The formulas are:
254
255 // FLCK = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
256 // DIV is always 256, then:
257 // FLCK = (clock selected via FCCLKSEL) / (1 + MULT / 256)
258
259 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) =>
260 // Baud rate = [FCLK / 16] / (BRGVAL + 1)
261
262 // There are 2 unknowns: MULT and BRGVAL.
263 // MULT is responsible for fractional division
264 // BRGVAL is responsible for integer division
265
266 // The Fractional Rate Generator can be used to obtain more precise baud rates when the
267 // function clock is not a good multiple of standard (or otherwise desirable) baud rates.
268 // The FRG is typically set up to produce an integer multiple of the highest required baud
269 // rate, or a very close approximation. The BRG is then used to obtain the actual baud rate
270 // needed.
271
272 // Firstly, BRGVAL is calculated to get the raw clock which is a rough approximation that has to be adjusted
273 // so that the desired baud rate is obtained.
274 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate.
275 // The deduced formulas are written below.
276
277 let brg_value = (source_clock / (16 * baudrate)).min(255);
278 let raw_clock = source_clock / (16 * brg_value);
279 let mult_value = ((raw_clock * 256 / baudrate) - 256).min(255);
280 T::set_baudrate(mult_value as u8, brg_value as u8);
281 }
282}
283
284impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
285 /// Transmit the provided buffer blocking execution until done.
286 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
287 self.tx.blocking_write(buffer)
288 }
289
290 /// Flush USART TX blocking execution until done.
291 pub fn blocking_flush(&mut self) -> Result<(), Error> {
292 self.tx.blocking_flush()
293 }
294
295 /// Read from USART RX blocking execution until done.
296 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
297 self.rx.blocking_read(buffer)
298 }
299
300 /// Check if UART is busy transmitting.
301 pub fn tx_busy(&self) -> bool {
302 self.tx.tx_busy()
303 }
304
305 /// Split the Usart into a transmitter and receiver, which is particularly
306 /// useful when having two tasks correlating to transmitting and receiving.
307 pub fn split(self) -> (UsartTx<'d, T, M>, UsartRx<'d, T, M>) {
308 (self.tx, self.rx)
309 }
310
311 /// Split the Usart into a transmitter and receiver by mutable reference,
312 /// which is particularly useful when having two tasks correlating to
313 /// transmitting and receiving.
314 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, T, M>, &mut UsartRx<'d, T, M>) {
315 (&mut self.tx, &mut self.rx)
316 }
317}
318
319impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, T, M> {
320 type Error = Error;
321
322 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
323 self.blocking_write(buffer)
324 }
325
326 fn bflush(&mut self) -> Result<(), Self::Error> {
327 self.blocking_flush()
328 }
329}
330
331impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, T, M> {
332 type Error = Error;
333
334 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
335 self.blocking_write(buffer)
336 }
337
338 fn bflush(&mut self) -> Result<(), Self::Error> {
339 self.blocking_flush()
340 }
341}
342
343impl<'d, T: Instance> embedded_io::ErrorType for UsartTx<'d, T, Blocking> {
344 type Error = Error;
345}
346
347impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> {
348 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
349 self.blocking_write(buf).map(|_| buf.len())
350 }
351
352 fn flush(&mut self) -> Result<(), Self::Error> {
353 self.blocking_flush()
354 }
355}
356
357impl<'d, T: Instance> embedded_io::ErrorType for UsartRx<'d, T, Blocking> {
358 type Error = Error;
359}
360
361impl<'d, T: Instance> embedded_io::Read for UsartRx<'d, T, Blocking> {
362 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
363 self.blocking_read(buf).map(|_| buf.len())
364 }
365}
366
367impl<'d, T: Instance> embedded_io::ErrorType for Usart<'d, T, Blocking> {
368 type Error = Error;
369}
370
371impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> {
372 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
373 self.blocking_write(buf).map(|_| buf.len())
374 }
375
376 fn flush(&mut self) -> Result<(), Self::Error> {
377 self.blocking_flush()
378 }
379}
380
381impl<'d, T: Instance> embedded_io::Read for Usart<'d, T, Blocking> {
382 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
383 self.blocking_read(buf).map(|_| buf.len())
384 }
385}
386
387type UsartRegBlock = crate::pac::usart0::RegisterBlock;
388
389mod sealed {
390 use crate::usart::inner::UsartRegBlock;
391 use crate::usart::{Config, Error};
392 pub trait SealedInstance {
393 fn usart_reg() -> &'static UsartRegBlock;
394 fn enable_clock();
395 fn select_clock(baudrate: u32) -> u32;
396 fn configure_flexcomm();
397 fn set_baudrate(mult_value: u8, brg_value: u8);
398 fn reset_flexcomm();
399 fn tx_pin_config();
400 fn rx_pin_config();
401
402 fn configure_usart(config: Config) {
403 // See section 34.6.1
404 Self::usart_reg().cfg.modify(|_, w| {
405 // LIN break mode enable
406 w.linmode()
407 // Disabled. Break detect and generate is configured for normal operation.
408 .disabled()
409 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
410 //input pin, or from the USART’s own RTS if loopback mode is enabled.
411 .ctsen()
412 // No flow control. The transmitter does not receive any automatic flow control signal.
413 .disabled()
414 // Selects synchronous or asynchronous operation.
415 .syncen()
416 .asynchronous_mode()
417 // Selects the clock polarity and sampling edge of received data in synchronous mode.
418 .clkpol()
419 .rising_edge()
420 // Synchronous mode Master select.
421 .syncmst()
422 // When synchronous mode is enabled, the USART is a master.
423 .master()
424 // Selects data loopback mode
425 .loop_()
426 // Normal operation
427 .normal()
428 // Output Enable Turnaround time enable for RS-485 operation.
429 .oeta()
430 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
431 // the last stop bit of a transmission.
432 .disabled()
433 // Output enable select.
434 .oesel()
435 // Standard. The RTS signal is used as the standard flow control function.
436 .standard()
437 // Automatic address matching enable.
438 .autoaddr()
439 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
440 // software. This provides the possibility of versatile addressing (e.g. respond to more
441 // than one address)
442 .disabled()
443 // Output enable polarity.
444 .oepol()
445 // Low. If selected by OESEL, the output enable is active low.
446 .low()
447 });
448
449 Self::usart_reg().cfg.modify(|_, w| unsafe {
450 w.datalen()
451 .bits(config.data_bits.bits())
452 .paritysel()
453 .bits(config.parity.bits())
454 .stoplen()
455 .bit(config.stop_bits.bits())
456 .rxpol()
457 .bit(config.invert_rx)
458 .txpol()
459 .bit(config.invert_tx)
460 });
461 }
462 fn disable_dma() {
463 Self::usart_reg()
464 .fifocfg
465 .modify(|_, w| w.dmatx().disabled().dmarx().disabled());
466 }
467 fn enable_usart() {
468 Self::usart_reg()
469 .fifocfg
470 .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
471 Self::usart_reg().cfg.modify(|_, w| w.enable().enabled());
472 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_set() {
473 let _ = Self::usart_reg().fiford.read().bits();
474 }
475 }
476 fn blocking_write(buffer: &[u8]) -> Result<(), Error> {
477 for &b in buffer {
478 while Self::usart_reg().fifostat.read().txnotfull().bit_is_clear() {}
479 Self::usart_reg()
480 .fifowr
481 .modify(|_, w| unsafe { w.txdata().bits(b as u16) });
482 }
483 Ok(())
484 }
485 fn blocking_flush() -> Result<(), Error> {
486 while Self::usart_reg().fifostat.read().txempty().bit_is_clear() {}
487 Ok(())
488 }
489 fn tx_busy() -> bool {
490 Self::usart_reg().fifostat.read().txempty().bit_is_clear()
491 }
492 fn drain_fifo(buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
493 for (i, b) in buffer.iter_mut().enumerate() {
494 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_clear() {}
495
496 if Self::usart_reg().fifostat.read().rxerr().bit_is_set() {
497 return Err((i, Error::Overrun));
498 } else if Self::usart_reg().fifordnopop.read().parityerr().bit_is_set() {
499 return Err((i, Error::Parity));
500 } else if Self::usart_reg().fifordnopop.read().framerr().bit_is_set() {
501 return Err((i, Error::Framing));
502 } else if Self::usart_reg().fifordnopop.read().rxnoise().bit_is_set() {
503 return Err((i, Error::Noise));
504 } else if Self::usart_reg().intstat.read().deltarxbrk().bit_is_set() {
505 return Err((i, Error::Break));
506 }
507 let dr = Self::usart_reg().fiford.read().bits() as u8;
508 *b = dr;
509 }
510 Ok(buffer.len())
511 }
512 }
513}
514
515/// UART instance.
516#[allow(private_bounds)]
517pub trait Instance: sealed::SealedInstance + PeripheralType {}
518
519#[macro_export]
520macro_rules! impl_instance {
521 (
522 $inst:ident,
523 usart_peripheral: $USARTX:ident,
524 usart_crate: $usartX:ident,
525
526 flexcomm: {
527 field: $FLEXCOMM_FIELD:ident,
528 clock_field: $FLEXCOMM_CLK_FIELD:ident
529 },
530
531 reset: {
532 bit: $RESET_BIT:ident
533 },
534
535 clock: {
536 sel_field: $CLKSEL_FIELD:ident,
537 frg_field: $FRG_FIELD:ident
538 },
539
540 pins: {
541 tx: $TX_IOCON:ident => $TX_FUNC:expr,
542 rx: $RX_IOCON:ident => $RX_FUNC:expr
543 }
544
545 ) => {
546 impl $crate::usart::SealedInstance for $crate::peripherals::$inst {
547 fn usart_reg() -> &'static UsartRegBlock {
548 unsafe { &*$crate::pac::$USARTX::ptr() }
549 }
550
551 fn enable_clock() {
552 critical_section::with(|_cs| {
553 if syscon_reg().ahbclkctrl0.read().iocon().is_disable() {
554 syscon_reg().ahbclkctrl0.modify(|_, w| w.iocon().enable());
555 }
556 if syscon_reg().ahbclkctrl1.read().$FLEXCOMM_CLK_FIELD().is_disable() {
557 syscon_reg()
558 .ahbclkctrl1
559 .modify(|_, w| w.$FLEXCOMM_CLK_FIELD().enable());
560 }
561 });
562 }
563
564 fn configure_flexcomm() {
565 let flexcomm = unsafe { &*$crate::pac::$FLEXCOMM_FIELD::ptr() };
566 flexcomm.pselid.modify(|_, w| w.persel().usart());
567 }
568
569 fn reset_flexcomm() {
570 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().set_bit());
571 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().clear_bit());
572 }
573
574 fn select_clock(baudrate: u32) -> u32 {
575 // Adaptive clock choice based on baud rate
576 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
577 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
578 // and fractional divider (fractional rate divider).
579
580 // By default, oversampling rate is 16 which is an industry standard.
581 // That means 16 clocks are used to deliver the byte to recipient.
582 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
583
584 // Minimum and maximum values were computed taking these formulas into account:
585 // For minimum value, MULT = 0, BRGVAL = 0
586 // For maximum value, MULT = 255, BRGVAL = 255
587 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
588 // By default, OSRVAL = 15 (see above)
589 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
590 return match baudrate {
591 750_001..=6000000 => {
592 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x3()); // 96 MHz
593 96_000_000
594 }
595 1501..=750_000 => {
596 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x2()); // 12 MHz
597 12_000_000
598 }
599 121..=1500 => {
600 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x4()); // 1 MHz
601 1_000_000
602 }
603 _ => {
604 panic!("{} baudrate is not permitted in this mode", baudrate);
605 }
606 };
607 }
608
609 fn set_baudrate(mult_value: u8, brg_value: u8) {
610 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV)
611 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
612 // to yield a denominator vale of 256. All other values are not supported
613 syscon_reg()
614 .$FRG_FIELD()
615 .modify(|_, w| unsafe { w.div().bits(0xFF).mult().bits(mult_value as u8) });
616
617 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
618 // By default, oversampling is 16x, i.e. OSRVAL = 15
619
620 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
621 // asynchronous data. This is the number of BRG clocks used for one data bit. The
622 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
623 // oversample clock. There is no oversampling in synchronous modes.
624 Self::usart_reg()
625 .brg
626 .modify(|_, w| unsafe { w.brgval().bits((brg_value - 1) as u16) });
627 }
628
629 fn tx_pin_config() {
630 iocon_reg().$TX_IOCON.modify(|_, w| unsafe {
631 w.func()
632 .bits($TX_FUNC)
633 .digimode()
634 .digital()
635 .slew()
636 .standard()
637 .mode()
638 .inactive()
639 .invert()
640 .disabled()
641 .od()
642 .normal()
643 });
644 }
645
646 fn rx_pin_config() {
647 iocon_reg().$RX_IOCON.modify(|_, w| unsafe {
648 w.func()
649 .bits($RX_FUNC)
650 .digimode()
651 .digital()
652 .slew()
653 .standard()
654 .mode()
655 .inactive()
656 .invert()
657 .disabled()
658 .od()
659 .normal()
660 });
661 }
662 }
663
664 impl $crate::usart::Instance for $crate::peripherals::$inst {}
665 };
666}
667
668impl_instance!(USART0, usart_peripheral: USART0, usart_crate: usart0,
669 flexcomm: {
670 field: FLEXCOMM0,
671 clock_field: fc0
672 },
673
674 reset: {
675 bit: fc0_rst
676 },
677
678 clock: {
679 sel_field: fcclksel0,
680 frg_field: flexfrg0ctrl
681 },
682
683 pins: {
684 tx: pio1_6 => 1,
685 rx: pio1_5 => 1
686 }
687);
688
689impl_instance!(USART1, usart_peripheral: USART1, usart_crate: usart1,
690 flexcomm: {
691 field: FLEXCOMM1,
692 clock_field: fc1
693 },
694
695 reset: {
696 bit: fc1_rst
697 },
698
699 clock: {
700 sel_field: fcclksel1,
701 frg_field: flexfrg1ctrl
702 },
703
704 pins: {
705 tx: pio1_11 => 2,
706 rx: pio1_10 => 2
707 }
708);
709
710impl_instance!(USART2, usart_peripheral: USART2, usart_crate: usart2,
711 flexcomm: {
712 field: FLEXCOMM2,
713 clock_field: fc2
714 },
715
716 reset: {
717 bit: fc2_rst
718 },
719
720 clock: {
721 sel_field: fcclksel2,
722 frg_field: flexfrg2ctrl
723 },
724
725 pins: {
726 tx: pio0_27 => 1,
727 rx: pio1_24 => 1
728 }
729);
730
731impl_instance!(USART3, usart_peripheral: USART3, usart_crate: usart3,
732 flexcomm: {
733 field: FLEXCOMM3,
734 clock_field: fc3
735 },
736
737 reset: {
738 bit: fc3_rst
739 },
740
741 clock: {
742 sel_field: fcclksel3,
743 frg_field: flexfrg3ctrl
744 },
745
746 pins: {
747 tx: pio0_2 => 1,
748 rx: pio0_3 => 1
749 }
750);
751
752impl_instance!(USART4, usart_peripheral: USART4, usart_crate: usart4,
753 flexcomm: {
754 field: FLEXCOMM4,
755 clock_field: fc4
756 },
757
758 reset: {
759 bit: fc4_rst
760 },
761
762 clock: {
763 sel_field: fcclksel4,
764 frg_field: flexfrg4ctrl
765 },
766
767 pins: {
768 tx: pio0_16 => 1,
769 rx: pio0_5 => 2
770 }
771);
772
773impl_instance!(USART5, usart_peripheral: USART5, usart_crate: usart5,
774 flexcomm: {
775 field: FLEXCOMM5,
776 clock_field: fc5
777 },
778
779 reset: {
780 bit: fc5_rst
781 },
782
783 clock: {
784 sel_field: fcclksel5,
785 frg_field: flexfrg5ctrl
786 },
787
788 pins: {
789 tx: pio0_9 => 3,
790 rx: pio0_8 => 3
791 }
792);
793
794impl_instance!(USART6, usart_peripheral: USART6, usart_crate: usart6,
795 flexcomm: {
796 field: FLEXCOMM6,
797 clock_field: fc6
798 },
799
800 reset: {
801 bit: fc6_rst
802 },
803
804 clock: {
805 sel_field: fcclksel6,
806 frg_field: flexfrg6ctrl
807 },
808
809 pins: {
810 tx: pio1_16 => 2,
811 rx: pio1_13 => 2
812 }
813);
814
815impl_instance!(USART7, usart_peripheral: USART7, usart_crate: usart7,
816 flexcomm: {
817 field: FLEXCOMM7,
818 clock_field: fc7
819 },
820
821 reset: {
822 bit: fc7_rst
823 },
824
825 clock: {
826 sel_field: fcclksel7,
827 frg_field: flexfrg7ctrl
828 },
829
830 pins: {
831 tx: pio0_19 => 7,
832 rx: pio0_20 => 7
833 }
834);
835
836/// Trait for TX pins.
837pub trait TxPin<T: Instance>: crate::gpio::Pin {}
838/// Trait for RX pins.
839pub trait RxPin<T: Instance>: crate::gpio::Pin {}
840
841// TODO: Add RTS, CTS and CLK pin traits
842
843macro_rules! impl_pin {
844 ($pin:ident, $instance:ident, Tx) => {
845 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
846 };
847 ($pin:ident, $instance:ident, Rx) => {
848 impl RxPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
849 };
850}
851
852impl_pin!(PIO1_5, USART0, Rx);
853impl_pin!(PIO1_6, USART0, Tx);
854impl_pin!(PIO1_10, USART1, Rx);
855impl_pin!(PIO1_11, USART1, Tx);
856impl_pin!(PIO0_27, USART2, Tx);
857impl_pin!(PIO1_24, USART2, Rx);
858impl_pin!(PIO0_2, USART3, Tx);
859impl_pin!(PIO0_3, USART3, Rx);
860impl_pin!(PIO0_16, USART4, Tx);
861impl_pin!(PIO0_5, USART4, Rx);
862impl_pin!(PIO0_8, USART5, Rx);
863impl_pin!(PIO0_9, USART5, Tx);
864impl_pin!(PIO1_16, USART6, Tx);
865impl_pin!(PIO1_13, USART6, Rx);
866impl_pin!(PIO0_20, USART7, Rx);
867impl_pin!(PIO0_19, USART7, Tx);
868
869/// Get the SYSCON register block.
870///
871/// # Safety
872/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
873/// registers are not accessed concurrently by multiple threads.
874pub(crate) fn syscon_reg() -> &'static crate::pac::syscon::RegisterBlock {
875 unsafe { &*crate::pac::SYSCON::ptr() }
876}
877
878/// Get the IOCON register block.
879///
880/// # Safety
881/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
882/// registers are not accessed concurrently by multiple threads.
883pub(crate) fn iocon_reg() -> &'static crate::pac::iocon::RegisterBlock {
884 unsafe { &*crate::pac::IOCON::ptr() }
885}