aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nxp/src/usart.rs1
-rw-r--r--embassy-nxp/src/usart/lpc55.rs884
2 files changed, 332 insertions, 553 deletions
diff --git a/embassy-nxp/src/usart.rs b/embassy-nxp/src/usart.rs
index 009c251e2..c426ab96d 100644
--- a/embassy-nxp/src/usart.rs
+++ b/embassy-nxp/src/usart.rs
@@ -1,5 +1,4 @@
1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. 1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver.
2#![macro_use]
3 2
4#[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")] 3#[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")]
5mod inner; 4mod inner;
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
index 3f7456a2e..428b80c4b 100644
--- a/embassy-nxp/src/usart/lpc55.rs
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -2,9 +2,12 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::{Peri, PeripheralType}; 3use embassy_hal_internal::{Peri, PeripheralType};
4use embedded_io::{self, ErrorKind}; 4use embedded_io::{self, ErrorKind};
5pub use sealed::SealedInstance;
6 5
7use crate::gpio::AnyPin; 6use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin};
7use crate::pac::flexcomm::Flexcomm as FlexcommReg;
8use crate::pac::iocon::vals::PioFunc;
9use crate::pac::usart::Usart as UsartReg;
10use crate::pac::*;
8use crate::{Blocking, Mode}; 11use crate::{Blocking, Mode};
9 12
10/// Serial error 13/// Serial error
@@ -47,16 +50,6 @@ pub enum DataBits {
47 DataBits9, 50 DataBits9,
48} 51}
49 52
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. 53/// Parity bit.
61#[derive(Clone, Copy, PartialEq, Eq, Debug)] 54#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62pub enum Parity { 55pub enum Parity {
@@ -68,16 +61,6 @@ pub enum Parity {
68 ParityOdd, 61 ParityOdd,
69} 62}
70 63
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. 64/// Stop bits.
82#[derive(Clone, Copy, PartialEq, Eq, Debug)] 65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
83pub enum StopBits { 66pub enum StopBits {
@@ -87,15 +70,6 @@ pub enum StopBits {
87 Stop2, 70 Stop2,
88} 71}
89 72
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. 73/// UART config.
100#[non_exhaustive] 74#[non_exhaustive]
101#[derive(Clone, Debug)] 75#[derive(Clone, Debug)]
@@ -117,7 +91,7 @@ pub struct Config {
117impl Default for Config { 91impl Default for Config {
118 fn default() -> Self { 92 fn default() -> Self {
119 Self { 93 Self {
120 baudrate: 9600, 94 baudrate: 115200,
121 data_bits: DataBits::DataBits8, 95 data_bits: DataBits::DataBits8,
122 stop_bits: StopBits::Stop1, 96 stop_bits: StopBits::Stop1,
123 parity: Parity::ParityNone, 97 parity: Parity::ParityNone,
@@ -131,59 +105,72 @@ impl Default for Config {
131/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time 105/// '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 106/// T: the peripheral instance type allowing usage of peripheral specific registers
133/// M: the operating mode of USART peripheral 107/// M: the operating mode of USART peripheral
134pub struct Usart<'d, T: Instance, M: Mode> { 108pub struct Usart<'d, M: Mode> {
135 tx: UsartTx<'d, T, M>, 109 tx: UsartTx<'d, M>,
136 rx: UsartRx<'d, T, M>, 110 rx: UsartRx<'d, M>,
137} 111}
138 112
139pub struct UsartTx<'d, T: Instance, M: Mode> { 113pub struct UsartTx<'d, M: Mode> {
140 phantom: PhantomData<(&'d (), T, M)>, 114 info: &'static Info,
115 phantom: PhantomData<(&'d (), M)>,
141} 116}
142 117
143pub struct UsartRx<'d, T: Instance, M: Mode> { 118pub struct UsartRx<'d, M: Mode> {
144 phantom: PhantomData<(&'d (), T, M)>, 119 info: &'static Info,
120 phantom: PhantomData<(&'d (), M)>,
145} 121}
146 122
147impl<'d, T: Instance, M: Mode> UsartTx<'d, T, M> { 123impl<'d, M: Mode> UsartTx<'d, M> {
148 pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 124 pub fn new<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
149 Usart::<T, M>::init(Some(tx.into()), None, config); 125 Usart::<M>::init::<T>(Some(tx.into()), None, config);
150 Self::new_inner() 126 Self::new_inner(T::info())
151 } 127 }
152 128
153 #[inline] 129 #[inline]
154 fn new_inner() -> Self { 130 fn new_inner(info: &'static Info) -> Self {
155 Self { phantom: PhantomData } 131 Self {
132 info,
133 phantom: PhantomData,
134 }
156 } 135 }
157 136
158 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 137 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
159 T::blocking_write(buffer) 138 for &b in buffer {
139 while !(self.info.usart_reg.fifostat().read().txnotfull()) {}
140 self.info.usart_reg.fifowr().write(|w| w.set_txdata(b as u16));
141 }
142 Ok(())
160 } 143 }
161 144
162 pub fn blocking_flush(&mut self) -> Result<(), Error> { 145 pub fn blocking_flush(&mut self) -> Result<(), Error> {
163 T::blocking_flush() 146 while !(self.info.usart_reg.fifostat().read().txempty()) {}
147 Ok(())
164 } 148 }
165 149
166 pub fn tx_busy(&self) -> bool { 150 pub fn tx_busy(&self) -> bool {
167 T::tx_busy() 151 !(self.info.usart_reg.fifostat().read().txempty())
168 } 152 }
169} 153}
170 154
171impl<'d, T: Instance> UsartTx<'d, T, Blocking> { 155impl<'d> UsartTx<'d, Blocking> {
172 pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 156 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
173 Usart::<T, Blocking>::init(Some(tx.into()), None, config); 157 Usart::<Blocking>::init::<T>(Some(tx.into()), None, config);
174 Self::new_inner() 158 Self::new_inner(T::info())
175 } 159 }
176} 160}
177 161
178impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> { 162impl<'d, M: Mode> UsartRx<'d, M> {
179 pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 163 pub fn new<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
180 Usart::<T, M>::init(None, Some(rx.into()), config); 164 Usart::<M>::init::<T>(None, Some(rx.into()), config);
181 Self::new_inner() 165 Self::new_inner(T::info())
182 } 166 }
183 167
184 #[inline] 168 #[inline]
185 fn new_inner() -> Self { 169 fn new_inner(info: &'static Info) -> Self {
186 Self { phantom: PhantomData } 170 Self {
171 info,
172 phantom: PhantomData,
173 }
187 } 174 }
188 175
189 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 176 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
@@ -201,19 +188,35 @@ impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> {
201 /// - Ok(n) -> read n bytes 188 /// - Ok(n) -> read n bytes
202 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte 189 /// - 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)> { 190 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
204 T::drain_fifo(buffer) 191 for (i, b) in buffer.iter_mut().enumerate() {
192 while !(self.info.usart_reg.fifostat().read().rxnotempty()) {}
193 if self.info.usart_reg.fifostat().read().rxerr() {
194 return Err((i, Error::Overrun));
195 } else if self.info.usart_reg.fifordnopop().read().parityerr() {
196 return Err((i, Error::Parity));
197 } else if self.info.usart_reg.fifordnopop().read().framerr() {
198 return Err((i, Error::Framing));
199 } else if self.info.usart_reg.fifordnopop().read().rxnoise() {
200 return Err((i, Error::Noise));
201 } else if self.info.usart_reg.intstat().read().deltarxbrk() {
202 return Err((i, Error::Break));
203 }
204 let dr = self.info.usart_reg.fiford().read().rxdata() as u8;
205 *b = dr;
206 }
207 Ok(buffer.len())
205 } 208 }
206} 209}
207 210
208impl<'d, T: Instance> UsartRx<'d, T, Blocking> { 211impl<'d> UsartRx<'d, Blocking> {
209 pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 212 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
210 Usart::<T, Blocking>::init(None, Some(rx.into()), config); 213 Usart::<Blocking>::init::<T>(None, Some(rx.into()), config);
211 Self::new_inner() 214 Self::new_inner(T::info())
212 } 215 }
213} 216}
214 217
215impl<'d, T: Instance> Usart<'d, T, Blocking> { 218impl<'d> Usart<'d, Blocking> {
216 pub fn new_blocking( 219 pub fn new_blocking<T: Instance>(
217 usart: Peri<'d, T>, 220 usart: Peri<'d, T>,
218 tx: Peri<'d, impl TxPin<T>>, 221 tx: Peri<'d, impl TxPin<T>>,
219 rx: Peri<'d, impl RxPin<T>>, 222 rx: Peri<'d, impl RxPin<T>>,
@@ -223,29 +226,70 @@ impl<'d, T: Instance> Usart<'d, T, Blocking> {
223 } 226 }
224} 227}
225 228
226impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 229impl<'d, M: Mode> Usart<'d, M> {
227 fn new_inner(_usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, config: Config) -> Self { 230 fn new_inner<T: Instance>(
228 Self::init(Some(tx.reborrow()), Some(rx.reborrow()), config); 231 _usart: Peri<'d, T>,
232 mut tx: Peri<'d, AnyPin>,
233 mut rx: Peri<'d, AnyPin>,
234 config: Config,
235 ) -> Self {
236 Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config);
229 Self { 237 Self {
230 tx: UsartTx::new_inner(), 238 tx: UsartTx::new_inner(T::info()),
231 rx: UsartRx::new_inner(), 239 rx: UsartRx::new_inner(T::info()),
232 } 240 }
233 } 241 }
234 242
235 fn init(_tx: Option<Peri<'_, AnyPin>>, _rx: Option<Peri<'_, AnyPin>>, config: Config) { 243 fn init<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>, config: Config) {
236 T::enable_clock(); 244 Self::configure_flexcomm(T::info().fc_reg, T::instance_number());
237 T::reset_flexcomm(); 245 Self::configure_clock::<T>(&config);
238 let source_clock: u32 = T::select_clock(config.baudrate); 246 Self::pin_config::<T>(tx, rx);
239 T::configure_flexcomm(); 247 Self::configure_usart(T::info(), &config);
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 } 248 }
247 249
248 fn set_baudrate(source_clock: u32, baudrate: u32) { 250 fn configure_clock<T: Instance>(config: &Config) {
251 // Select source clock
252
253 // Adaptive clock choice based on baud rate
254 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
255 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
256 // and fractional divider (fractional rate divider).
257
258 // By default, oversampling rate is 16 which is an industry standard.
259 // That means 16 clocks are used to deliver the byte to recipient.
260 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
261
262 // Minimum and maximum values were computed taking these formulas into account:
263 // For minimum value, MULT = 0, BRGVAL = 0
264 // For maximum value, MULT = 255, BRGVAL = 255
265 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
266 // By default, OSRVAL = 15 (see above)
267 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
268 let source_clock = match config.baudrate {
269 750_001..=6_000_000 => {
270 SYSCON
271 .fcclksel(T::instance_number())
272 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X3)); // 96 MHz
273 96_000_000
274 }
275 1501..=750_000 => {
276 SYSCON
277 .fcclksel(T::instance_number())
278 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); // 12 MHz
279 12_000_000
280 }
281 121..=1500 => {
282 SYSCON
283 .fcclksel(T::instance_number())
284 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X4)); // 1 MHz
285 1_000_000
286 }
287 _ => {
288 panic!("{} baudrate is not permitted in this mode", config.baudrate);
289 }
290 };
291 // Calculate MULT and BRG values based on baudrate
292
249 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) 293 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
250 // and fractional divider (fractional rate divider). 294 // and fractional divider (fractional rate divider).
251 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 295 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15
@@ -274,14 +318,167 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
274 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. 318 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate.
275 // The deduced formulas are written below. 319 // The deduced formulas are written below.
276 320
277 let brg_value = (source_clock / (16 * baudrate)).min(255); 321 let brg_value = (source_clock / (16 * config.baudrate)).min(255);
278 let raw_clock = source_clock / (16 * brg_value); 322 let raw_clock = source_clock / (16 * brg_value);
279 let mult_value = ((raw_clock * 256 / baudrate) - 256).min(255); 323 let mult_value = ((raw_clock * 256 / config.baudrate) - 256).min(255);
280 T::set_baudrate(mult_value as u8, brg_value as u8); 324
325 // Write values to the registers
326
327 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV)
328 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
329 // to yield a denominator vale of 256. All other values are not supported
330 SYSCON.flexfrgctrl(T::instance_number()).modify(|w| {
331 w.set_div(0xFF);
332 w.set_mult(mult_value as u8);
333 });
334
335 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
336 // By default, oversampling is 16x, i.e. OSRVAL = 15
337
338 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
339 // asynchronous data. This is the number of BRG clocks used for one data bit. The
340 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
341 // oversample clock. There is no oversampling in synchronous modes.
342 T::info()
343 .usart_reg
344 .brg()
345 .modify(|w| w.set_brgval((brg_value - 1) as u16));
346 }
347
348 fn pin_config<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>) {
349 if let Some(tx_pin) = tx {
350 match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), {
351 register.modify(|w| {
352 w.set_func(T::tx_pin_func());
353 w.set_mode(iocon::vals::PioMode::INACTIVE);
354 w.set_slew(iocon::vals::PioSlew::STANDARD);
355 w.set_invert(false);
356 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
357 w.set_od(iocon::vals::PioOd::NORMAL);
358 });
359 })
360 }
361
362 if let Some(rx_pin) = rx {
363 match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), {
364 register.modify(|w| {
365 w.set_func(T::rx_pin_func());
366 w.set_mode(iocon::vals::PioMode::INACTIVE);
367 w.set_slew(iocon::vals::PioSlew::STANDARD);
368 w.set_invert(false);
369 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
370 w.set_od(iocon::vals::PioOd::NORMAL);
371 });
372 })
373 };
374 }
375
376 fn configure_flexcomm(flexcomm_register: crate::pac::flexcomm::Flexcomm, instance_number: usize) {
377 critical_section::with(|_cs| {
378 if !(SYSCON.ahbclkctrl0().read().iocon()) {
379 SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true));
380 }
381 });
382 critical_section::with(|_cs| {
383 if !(SYSCON.ahbclkctrl1().read().fc(instance_number)) {
384 SYSCON.ahbclkctrl1().modify(|w| w.set_fc(instance_number, true));
385 }
386 });
387 SYSCON
388 .presetctrl1()
389 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::ASSERTED));
390 SYSCON
391 .presetctrl1()
392 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED));
393 flexcomm_register
394 .pselid()
395 .modify(|w| w.set_persel(flexcomm::vals::Persel::USART));
396 }
397
398 fn configure_usart(info: &'static Info, config: &Config) {
399 let registers = info.usart_reg;
400 // See section 34.6.1
401 registers.cfg().modify(|w| {
402 // LIN break mode enable
403 // Disabled. Break detect and generate is configured for normal operation.
404 w.set_linmode(false);
405 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
406 //input pin, or from the USART’s own RTS if loopback mode is enabled.
407 // No flow control. The transmitter does not receive any automatic flow control signal.
408 w.set_ctsen(false);
409 // Selects synchronous or asynchronous operation.
410 w.set_syncen(usart::vals::Syncen::ASYNCHRONOUS_MODE);
411 // Selects the clock polarity and sampling edge of received data in synchronous mode.
412 w.set_clkpol(usart::vals::Clkpol::RISING_EDGE);
413 // Synchronous mode Master select.
414 // When synchronous mode is enabled, the USART is a master.
415 w.set_syncmst(usart::vals::Syncmst::MASTER);
416 // Selects data loopback mode
417 w.set_loop_(usart::vals::Loop::NORMAL);
418 // Output Enable Turnaround time enable for RS-485 operation.
419 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
420 // the last stop bit of a transmission.
421 w.set_oeta(false);
422 // Output enable select.
423 // Standard. The RTS signal is used as the standard flow control function.
424 w.set_oesel(usart::vals::Oesel::STANDARD);
425 // Automatic address matching enable.
426 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
427 // software. This provides the possibility of versatile addressing (e.g. respond to more
428 // than one address)
429 w.set_autoaddr(false);
430 // Output enable polarity.
431 // Low. If selected by OESEL, the output enable is active low.
432 w.set_oepol(usart::vals::Oepol::LOW);
433 });
434
435 // Configurations based on the config written by a user
436 registers.cfg().modify(|w| {
437 w.set_datalen(match config.data_bits {
438 DataBits::DataBits7 => usart::vals::Datalen::BIT_7,
439 DataBits::DataBits8 => usart::vals::Datalen::BIT_8,
440 DataBits::DataBits9 => usart::vals::Datalen::BIT_9,
441 });
442 w.set_paritysel(match config.parity {
443 Parity::ParityNone => usart::vals::Paritysel::NO_PARITY,
444 Parity::ParityEven => usart::vals::Paritysel::EVEN_PARITY,
445 Parity::ParityOdd => usart::vals::Paritysel::ODD_PARITY,
446 });
447 w.set_stoplen(match config.stop_bits {
448 StopBits::Stop1 => usart::vals::Stoplen::BIT_1,
449 StopBits::Stop2 => usart::vals::Stoplen::BITS_2,
450 });
451 w.set_rxpol(match config.invert_rx {
452 false => usart::vals::Rxpol::STANDARD,
453 true => usart::vals::Rxpol::INVERTED,
454 });
455 w.set_txpol(match config.invert_tx {
456 false => usart::vals::Txpol::STANDARD,
457 true => usart::vals::Txpol::INVERTED,
458 });
459 });
460
461 // DMA-related settings
462 registers.fifocfg().modify(|w| {
463 w.set_dmatx(false);
464 w.set_dmatx(false);
465 });
466
467 // Enabling USART
468 registers.fifocfg().modify(|w| {
469 w.set_enabletx(true);
470 w.set_enablerx(true);
471 });
472 registers.cfg().modify(|w| w.set_enable(true));
473
474 // Drain RX FIFO in case it still has some unrelevant data
475 while registers.fifostat().read().rxnotempty() {
476 let _ = registers.fiford().read().0;
477 }
281 } 478 }
282} 479}
283 480
284impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 481impl<'d, M: Mode> Usart<'d, M> {
285 /// Transmit the provided buffer blocking execution until done. 482 /// Transmit the provided buffer blocking execution until done.
286 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 483 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
287 self.tx.blocking_write(buffer) 484 self.tx.blocking_write(buffer)
@@ -304,19 +501,19 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
304 501
305 /// Split the Usart into a transmitter and receiver, which is particularly 502 /// Split the Usart into a transmitter and receiver, which is particularly
306 /// useful when having two tasks correlating to transmitting and receiving. 503 /// useful when having two tasks correlating to transmitting and receiving.
307 pub fn split(self) -> (UsartTx<'d, T, M>, UsartRx<'d, T, M>) { 504 pub fn split(self) -> (UsartTx<'d, M>, UsartRx<'d, M>) {
308 (self.tx, self.rx) 505 (self.tx, self.rx)
309 } 506 }
310 507
311 /// Split the Usart into a transmitter and receiver by mutable reference, 508 /// Split the Usart into a transmitter and receiver by mutable reference,
312 /// which is particularly useful when having two tasks correlating to 509 /// which is particularly useful when having two tasks correlating to
313 /// transmitting and receiving. 510 /// transmitting and receiving.
314 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, T, M>, &mut UsartRx<'d, T, M>) { 511 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, M>, &mut UsartRx<'d, M>) {
315 (&mut self.tx, &mut self.rx) 512 (&mut self.tx, &mut self.rx)
316 } 513 }
317} 514}
318 515
319impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, T, M> { 516impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> {
320 type Error = Error; 517 type Error = Error;
321 518
322 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 519 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -328,7 +525,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
328 } 525 }
329} 526}
330 527
331impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, T, M> { 528impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, M> {
332 type Error = Error; 529 type Error = Error;
333 530
334 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 531 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -340,11 +537,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
340 } 537 }
341} 538}
342 539
343impl<'d, T: Instance> embedded_io::ErrorType for UsartTx<'d, T, Blocking> { 540impl<'d> embedded_io::ErrorType for UsartTx<'d, Blocking> {
344 type Error = Error; 541 type Error = Error;
345} 542}
346 543
347impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> { 544impl<'d> embedded_io::Write for UsartTx<'d, Blocking> {
348 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 545 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
349 self.blocking_write(buf).map(|_| buf.len()) 546 self.blocking_write(buf).map(|_| buf.len())
350 } 547 }
@@ -354,21 +551,21 @@ impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> {
354 } 551 }
355} 552}
356 553
357impl<'d, T: Instance> embedded_io::ErrorType for UsartRx<'d, T, Blocking> { 554impl<'d> embedded_io::ErrorType for UsartRx<'d, Blocking> {
358 type Error = Error; 555 type Error = Error;
359} 556}
360 557
361impl<'d, T: Instance> embedded_io::Read for UsartRx<'d, T, Blocking> { 558impl<'d> embedded_io::Read for UsartRx<'d, Blocking> {
362 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 559 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
363 self.blocking_read(buf).map(|_| buf.len()) 560 self.blocking_read(buf).map(|_| buf.len())
364 } 561 }
365} 562}
366 563
367impl<'d, T: Instance> embedded_io::ErrorType for Usart<'d, T, Blocking> { 564impl<'d> embedded_io::ErrorType for Usart<'d, Blocking> {
368 type Error = Error; 565 type Error = Error;
369} 566}
370 567
371impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> { 568impl<'d> embedded_io::Write for Usart<'d, Blocking> {
372 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 569 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
373 self.blocking_write(buf).map(|_| buf.len()) 570 self.blocking_write(buf).map(|_| buf.len())
374 } 571 }
@@ -378,468 +575,69 @@ impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> {
378 } 575 }
379} 576}
380 577
381impl<'d, T: Instance> embedded_io::Read for Usart<'d, T, Blocking> { 578impl<'d> embedded_io::Read for Usart<'d, Blocking> {
382 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 579 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
383 self.blocking_read(buf).map(|_| buf.len()) 580 self.blocking_read(buf).map(|_| buf.len())
384 } 581 }
385} 582}
386 583
387type UsartRegBlock = crate::pac::usart0::RegisterBlock; 584struct Info {
388 585 usart_reg: UsartReg,
389mod sealed { 586 fc_reg: FlexcommReg,
390 use crate::usart::inner::UsartRegBlock; 587}
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 588
449 Self::usart_reg().cfg.modify(|_, w| unsafe { 589trait SealedInstance {
450 w.datalen() 590 fn info() -> &'static Info;
451 .bits(config.data_bits.bits()) 591 fn instance_number() -> usize;
452 .paritysel() 592 fn tx_pin_func() -> PioFunc;
453 .bits(config.parity.bits()) 593 fn rx_pin_func() -> PioFunc;
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} 594}
514 595
515/// UART instance. 596/// UART instance.
516#[allow(private_bounds)] 597#[allow(private_bounds)]
517pub trait Instance: sealed::SealedInstance + PeripheralType {} 598pub trait Instance: SealedInstance + PeripheralType {}
518 599
519#[macro_export]
520macro_rules! impl_instance { 600macro_rules! impl_instance {
521 ( 601 ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => {
522 $inst:ident, 602 impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst {
523 usart_peripheral: $USARTX:ident, 603 fn info() -> &'static Info {
524 usart_crate: $usartX:ident, 604 static INFO: Info = Info {
525 605 usart_reg: crate::pac::$inst,
526 flexcomm: { 606 fc_reg: crate::pac::$fc,
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 &INFO
607 } 609 }
608 610 #[inline]
609 fn set_baudrate(mult_value: u8, brg_value: u8) { 611 fn instance_number() -> usize {
610 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) 612 $fc_num
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 } 613 }
628 614 #[inline]
629 fn tx_pin_config() { 615 fn tx_pin_func() -> PioFunc {
630 iocon_reg().$TX_IOCON.modify(|_, w| unsafe { 616 PioFunc::$tx_pin
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 } 617 }
645 618 #[inline]
646 fn rx_pin_config() { 619 fn rx_pin_func() -> PioFunc {
647 iocon_reg().$RX_IOCON.modify(|_, w| unsafe { 620 PioFunc::$rx_pin
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 } 621 }
662 } 622 }
663
664 impl $crate::usart::Instance for $crate::peripherals::$inst {} 623 impl $crate::usart::Instance for $crate::peripherals::$inst {}
665 }; 624 };
666} 625}
667 626
668impl_instance!(USART0, usart_peripheral: USART0, usart_crate: usart0, 627impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0);
669 flexcomm: { 628impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1);
670 field: FLEXCOMM0, 629impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2);
671 clock_field: fc0 630impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3);
672 }, 631impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4);
673 632impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5);
674 reset: { 633impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6);
675 bit: fc0_rst 634impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7);
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 635
836/// Trait for TX pins. 636/// Trait for TX pins.
837pub trait TxPin<T: Instance>: crate::gpio::Pin {} 637pub trait TxPin<T: Instance>: crate::gpio::Pin {}
838/// Trait for RX pins. 638/// Trait for RX pins.
839pub trait RxPin<T: Instance>: crate::gpio::Pin {} 639pub trait RxPin<T: Instance>: crate::gpio::Pin {}
840 640
841// TODO: Add RTS, CTS and CLK pin traits
842
843macro_rules! impl_pin { 641macro_rules! impl_pin {
844 ($pin:ident, $instance:ident, Tx) => { 642 ($pin:ident, $instance:ident, Tx) => {
845 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} 643 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
@@ -849,37 +647,19 @@ macro_rules! impl_pin {
849 }; 647 };
850} 648}
851 649
852impl_pin!(PIO1_5, USART0, Rx);
853impl_pin!(PIO1_6, USART0, Tx); 650impl_pin!(PIO1_6, USART0, Tx);
854impl_pin!(PIO1_10, USART1, Rx); 651impl_pin!(PIO1_5, USART0, Rx);
855impl_pin!(PIO1_11, USART1, Tx); 652impl_pin!(PIO1_11, USART1, Tx);
653impl_pin!(PIO1_10, USART1, Rx);
856impl_pin!(PIO0_27, USART2, Tx); 654impl_pin!(PIO0_27, USART2, Tx);
857impl_pin!(PIO1_24, USART2, Rx); 655impl_pin!(PIO1_24, USART2, Rx);
858impl_pin!(PIO0_2, USART3, Tx); 656impl_pin!(PIO0_2, USART3, Tx);
859impl_pin!(PIO0_3, USART3, Rx); 657impl_pin!(PIO0_3, USART3, Rx);
860impl_pin!(PIO0_16, USART4, Tx); 658impl_pin!(PIO0_16, USART4, Tx);
861impl_pin!(PIO0_5, USART4, Rx); 659impl_pin!(PIO0_5, USART4, Rx);
862impl_pin!(PIO0_8, USART5, Rx);
863impl_pin!(PIO0_9, USART5, Tx); 660impl_pin!(PIO0_9, USART5, Tx);
661impl_pin!(PIO0_8, USART5, Rx);
864impl_pin!(PIO1_16, USART6, Tx); 662impl_pin!(PIO1_16, USART6, Tx);
865impl_pin!(PIO1_13, USART6, Rx); 663impl_pin!(PIO1_13, USART6, Rx);
866impl_pin!(PIO0_20, USART7, Rx);
867impl_pin!(PIO0_19, USART7, Tx); 664impl_pin!(PIO0_19, USART7, Tx);
868 665impl_pin!(PIO0_20, USART7, Rx);
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}