diff options
Diffstat (limited to 'embassy-mcxa/src/lpuart/mod.rs')
| -rw-r--r-- | embassy-mcxa/src/lpuart/mod.rs | 1292 |
1 files changed, 1292 insertions, 0 deletions
diff --git a/embassy-mcxa/src/lpuart/mod.rs b/embassy-mcxa/src/lpuart/mod.rs new file mode 100644 index 000000000..2d8308ec8 --- /dev/null +++ b/embassy-mcxa/src/lpuart/mod.rs | |||
| @@ -0,0 +1,1292 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 4 | use paste::paste; | ||
| 5 | |||
| 6 | use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig}; | ||
| 7 | use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock}; | ||
| 8 | use crate::gpio::SealedPin; | ||
| 9 | use crate::pac::lpuart0::baud::Sbns as StopBits; | ||
| 10 | use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits}; | ||
| 11 | use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource}; | ||
| 12 | use crate::pac::lpuart0::stat::Msbf as MsbFirst; | ||
| 13 | use crate::{interrupt, pac, AnyPin}; | ||
| 14 | |||
| 15 | pub mod buffered; | ||
| 16 | |||
| 17 | // ============================================================================ | ||
| 18 | // STUB IMPLEMENTATION | ||
| 19 | // ============================================================================ | ||
| 20 | |||
| 21 | // Stub implementation for LIB (Peripherals), GPIO, DMA and CLOCK until stable API | ||
| 22 | // Pin and Clock initialization is currently done at the examples level. | ||
| 23 | |||
| 24 | // --- START DMA --- | ||
| 25 | mod dma { | ||
| 26 | pub struct Channel<'d> { | ||
| 27 | pub(super) _lifetime: core::marker::PhantomData<&'d ()>, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | use dma::Channel; | ||
| 32 | |||
| 33 | // --- END DMA --- | ||
| 34 | |||
| 35 | // ============================================================================ | ||
| 36 | // MISC | ||
| 37 | // ============================================================================ | ||
| 38 | |||
| 39 | mod sealed { | ||
| 40 | /// Simply seal a trait to prevent external implementations | ||
| 41 | pub trait Sealed {} | ||
| 42 | } | ||
| 43 | |||
| 44 | // ============================================================================ | ||
| 45 | // INSTANCE TRAIT | ||
| 46 | // ============================================================================ | ||
| 47 | |||
| 48 | pub type Regs = &'static crate::pac::lpuart0::RegisterBlock; | ||
| 49 | |||
| 50 | pub trait SealedInstance { | ||
| 51 | fn info() -> Info; | ||
| 52 | fn index() -> usize; | ||
| 53 | fn buffered_state() -> &'static buffered::State; | ||
| 54 | } | ||
| 55 | |||
| 56 | pub struct Info { | ||
| 57 | pub regs: Regs, | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Trait for LPUART peripheral instances | ||
| 61 | #[allow(private_bounds)] | ||
| 62 | pub trait Instance: SealedInstance + PeripheralType + 'static + Send + Gate<MrccPeriphConfig = LpuartConfig> { | ||
| 63 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance; | ||
| 64 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 65 | } | ||
| 66 | |||
| 67 | macro_rules! impl_instance { | ||
| 68 | ($($n:expr),*) => { | ||
| 69 | $( | ||
| 70 | paste!{ | ||
| 71 | impl SealedInstance for crate::peripherals::[<LPUART $n>] { | ||
| 72 | fn info() -> Info { | ||
| 73 | Info { | ||
| 74 | regs: unsafe { &*pac::[<Lpuart $n>]::ptr() }, | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | #[inline] | ||
| 79 | fn index() -> usize { | ||
| 80 | $n | ||
| 81 | } | ||
| 82 | |||
| 83 | fn buffered_state() -> &'static buffered::State { | ||
| 84 | static BUFFERED_STATE: buffered::State = buffered::State::new(); | ||
| 85 | &BUFFERED_STATE | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | impl Instance for crate::peripherals::[<LPUART $n>] { | ||
| 90 | const CLOCK_INSTANCE: crate::clocks::periph_helpers::LpuartInstance | ||
| 91 | = crate::clocks::periph_helpers::LpuartInstance::[<Lpuart $n>]; | ||
| 92 | type Interrupt = crate::interrupt::typelevel::[<LPUART $n>]; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | )* | ||
| 96 | }; | ||
| 97 | } | ||
| 98 | |||
| 99 | impl_instance!(0, 1, 2, 3, 4, 5); | ||
| 100 | |||
| 101 | // ============================================================================ | ||
| 102 | // INSTANCE HELPER FUNCTIONS | ||
| 103 | // ============================================================================ | ||
| 104 | |||
| 105 | /// Perform software reset on the LPUART peripheral | ||
| 106 | pub fn perform_software_reset(regs: Regs) { | ||
| 107 | // Software reset - set and clear RST bit (Global register) | ||
| 108 | regs.global().write(|w| w.rst().reset()); | ||
| 109 | regs.global().write(|w| w.rst().no_effect()); | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Disable both transmitter and receiver | ||
| 113 | pub fn disable_transceiver(regs: Regs) { | ||
| 114 | regs.ctrl().modify(|_, w| w.te().disabled().re().disabled()); | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Calculate and configure baudrate settings | ||
| 118 | pub fn configure_baudrate(regs: Regs, baudrate_bps: u32, clock_freq: u32) -> Result<()> { | ||
| 119 | let (osr, sbr) = calculate_baudrate(baudrate_bps, clock_freq)?; | ||
| 120 | |||
| 121 | // Configure BAUD register | ||
| 122 | regs.baud().modify(|_, w| unsafe { | ||
| 123 | // Clear and set OSR | ||
| 124 | w.osr().bits(osr - 1); | ||
| 125 | // Clear and set SBR | ||
| 126 | w.sbr().bits(sbr); | ||
| 127 | // Set BOTHEDGE if OSR is between 4 and 7 | ||
| 128 | if osr > 3 && osr < 8 { | ||
| 129 | w.bothedge().enabled() | ||
| 130 | } else { | ||
| 131 | w.bothedge().disabled() | ||
| 132 | } | ||
| 133 | }); | ||
| 134 | |||
| 135 | Ok(()) | ||
| 136 | } | ||
| 137 | |||
| 138 | /// Configure frame format (stop bits, data bits) | ||
| 139 | pub fn configure_frame_format(regs: Regs, config: &Config) { | ||
| 140 | // Configure stop bits | ||
| 141 | regs.baud().modify(|_, w| w.sbns().variant(config.stop_bits_count)); | ||
| 142 | |||
| 143 | // Clear M10 for now (10-bit mode) | ||
| 144 | regs.baud().modify(|_, w| w.m10().disabled()); | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Configure control settings (parity, data bits, idle config, pin swap) | ||
| 148 | pub fn configure_control_settings(regs: Regs, config: &Config) { | ||
| 149 | regs.ctrl().modify(|_, w| { | ||
| 150 | // Parity configuration | ||
| 151 | let mut w = if let Some(parity) = config.parity_mode { | ||
| 152 | w.pe().enabled().pt().variant(parity) | ||
| 153 | } else { | ||
| 154 | w.pe().disabled() | ||
| 155 | }; | ||
| 156 | |||
| 157 | // Data bits configuration | ||
| 158 | w = match config.data_bits_count { | ||
| 159 | DataBits::Data8 => { | ||
| 160 | if config.parity_mode.is_some() { | ||
| 161 | w.m().data9() // 8 data + 1 parity = 9 bits | ||
| 162 | } else { | ||
| 163 | w.m().data8() // 8 data bits only | ||
| 164 | } | ||
| 165 | } | ||
| 166 | DataBits::Data9 => w.m().data9(), | ||
| 167 | }; | ||
| 168 | |||
| 169 | // Idle configuration | ||
| 170 | w = w.idlecfg().variant(config.rx_idle_config); | ||
| 171 | w = w.ilt().variant(config.rx_idle_type); | ||
| 172 | |||
| 173 | // Swap TXD/RXD if configured | ||
| 174 | if config.swap_txd_rxd { | ||
| 175 | w.swap().swap() | ||
| 176 | } else { | ||
| 177 | w.swap().standard() | ||
| 178 | } | ||
| 179 | }); | ||
| 180 | } | ||
| 181 | |||
| 182 | /// Configure FIFO settings and watermarks | ||
| 183 | pub fn configure_fifo(regs: Regs, config: &Config) { | ||
| 184 | // Configure WATER register for FIFO watermarks | ||
| 185 | regs.water().write(|w| unsafe { | ||
| 186 | w.rxwater() | ||
| 187 | .bits(config.rx_fifo_watermark) | ||
| 188 | .txwater() | ||
| 189 | .bits(config.tx_fifo_watermark) | ||
| 190 | }); | ||
| 191 | |||
| 192 | // Enable TX/RX FIFOs | ||
| 193 | regs.fifo().modify(|_, w| w.txfe().enabled().rxfe().enabled()); | ||
| 194 | |||
| 195 | // Flush FIFOs | ||
| 196 | regs.fifo() | ||
| 197 | .modify(|_, w| w.txflush().txfifo_rst().rxflush().rxfifo_rst()); | ||
| 198 | } | ||
| 199 | |||
| 200 | /// Clear all status flags | ||
| 201 | pub fn clear_all_status_flags(regs: Regs) { | ||
| 202 | regs.stat().reset(); | ||
| 203 | } | ||
| 204 | |||
| 205 | /// Configure hardware flow control if enabled | ||
| 206 | pub fn configure_flow_control(regs: Regs, enable_tx_cts: bool, enable_rx_rts: bool, config: &Config) { | ||
| 207 | if enable_rx_rts || enable_tx_cts { | ||
| 208 | regs.modir().modify(|_, w| { | ||
| 209 | let mut w = w; | ||
| 210 | |||
| 211 | // Configure TX CTS | ||
| 212 | w = w.txctsc().variant(config.tx_cts_config); | ||
| 213 | w = w.txctssrc().variant(config.tx_cts_source); | ||
| 214 | |||
| 215 | if enable_rx_rts { | ||
| 216 | w = w.rxrtse().enabled(); | ||
| 217 | } else { | ||
| 218 | w = w.rxrtse().disabled(); | ||
| 219 | } | ||
| 220 | |||
| 221 | if enable_tx_cts { | ||
| 222 | w = w.txctse().enabled(); | ||
| 223 | } else { | ||
| 224 | w = w.txctse().disabled(); | ||
| 225 | } | ||
| 226 | |||
| 227 | w | ||
| 228 | }); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | /// Configure bit order (MSB first or LSB first) | ||
| 233 | pub fn configure_bit_order(regs: Regs, msb_first: MsbFirst) { | ||
| 234 | regs.stat().modify(|_, w| w.msbf().variant(msb_first)); | ||
| 235 | } | ||
| 236 | |||
| 237 | /// Enable transmitter and/or receiver based on configuration | ||
| 238 | pub fn enable_transceiver(regs: Regs, enable_tx: bool, enable_rx: bool) { | ||
| 239 | regs.ctrl().modify(|_, w| { | ||
| 240 | let mut w = w; | ||
| 241 | if enable_tx { | ||
| 242 | w = w.te().enabled(); | ||
| 243 | } | ||
| 244 | if enable_rx { | ||
| 245 | w = w.re().enabled(); | ||
| 246 | } | ||
| 247 | w | ||
| 248 | }); | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn calculate_baudrate(baudrate: u32, src_clock_hz: u32) -> Result<(u8, u16)> { | ||
| 252 | let mut baud_diff = baudrate; | ||
| 253 | let mut osr = 0u8; | ||
| 254 | let mut sbr = 0u16; | ||
| 255 | |||
| 256 | // Try OSR values from 4 to 32 | ||
| 257 | for osr_temp in 4u8..=32u8 { | ||
| 258 | // Calculate SBR: (srcClock_Hz * 2 / (baudRate * osr) + 1) / 2 | ||
| 259 | let sbr_calc = ((src_clock_hz * 2) / (baudrate * osr_temp as u32)).div_ceil(2); | ||
| 260 | |||
| 261 | let sbr_temp = if sbr_calc == 0 { | ||
| 262 | 1 | ||
| 263 | } else if sbr_calc > 0x1FFF { | ||
| 264 | 0x1FFF | ||
| 265 | } else { | ||
| 266 | sbr_calc as u16 | ||
| 267 | }; | ||
| 268 | |||
| 269 | // Calculate actual baud rate | ||
| 270 | let calculated_baud = src_clock_hz / (osr_temp as u32 * sbr_temp as u32); | ||
| 271 | |||
| 272 | let temp_diff = calculated_baud.abs_diff(baudrate); | ||
| 273 | |||
| 274 | if temp_diff <= baud_diff { | ||
| 275 | baud_diff = temp_diff; | ||
| 276 | osr = osr_temp; | ||
| 277 | sbr = sbr_temp; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | // Check if baud rate difference is within 3% | ||
| 282 | if baud_diff > (baudrate / 100) * 3 { | ||
| 283 | return Err(Error::UnsupportedBaudrate); | ||
| 284 | } | ||
| 285 | |||
| 286 | Ok((osr, sbr)) | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Wait for all transmit operations to complete | ||
| 290 | pub fn wait_for_tx_complete(regs: Regs) { | ||
| 291 | // Wait for TX FIFO to empty | ||
| 292 | while regs.water().read().txcount().bits() != 0 { | ||
| 293 | // Wait for TX FIFO to drain | ||
| 294 | } | ||
| 295 | |||
| 296 | // Wait for last character to shift out (TC = Transmission Complete) | ||
| 297 | while regs.stat().read().tc().is_active() { | ||
| 298 | // Wait for transmission to complete | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | pub fn check_and_clear_rx_errors(regs: Regs) -> Result<()> { | ||
| 303 | let stat = regs.stat().read(); | ||
| 304 | let mut status = Ok(()); | ||
| 305 | |||
| 306 | // Check for overrun first - other error flags are prevented when OR is set | ||
| 307 | if stat.or().is_overrun() { | ||
| 308 | regs.stat().write(|w| w.or().clear_bit_by_one()); | ||
| 309 | |||
| 310 | return Err(Error::Overrun); | ||
| 311 | } | ||
| 312 | |||
| 313 | if stat.pf().is_parity() { | ||
| 314 | regs.stat().write(|w| w.pf().clear_bit_by_one()); | ||
| 315 | status = Err(Error::Parity); | ||
| 316 | } | ||
| 317 | |||
| 318 | if stat.fe().is_error() { | ||
| 319 | regs.stat().write(|w| w.fe().clear_bit_by_one()); | ||
| 320 | status = Err(Error::Framing); | ||
| 321 | } | ||
| 322 | |||
| 323 | if stat.nf().is_noise() { | ||
| 324 | regs.stat().write(|w| w.nf().clear_bit_by_one()); | ||
| 325 | status = Err(Error::Noise); | ||
| 326 | } | ||
| 327 | |||
| 328 | status | ||
| 329 | } | ||
| 330 | |||
| 331 | pub fn has_data(regs: Regs) -> bool { | ||
| 332 | if regs.param().read().rxfifo().bits() > 0 { | ||
| 333 | // FIFO is available - check RXCOUNT in WATER register | ||
| 334 | regs.water().read().rxcount().bits() > 0 | ||
| 335 | } else { | ||
| 336 | // No FIFO - check RDRF flag in STAT register | ||
| 337 | regs.stat().read().rdrf().is_rxdata() | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | // ============================================================================ | ||
| 342 | // PIN TRAITS FOR LPUART FUNCTIONALITY | ||
| 343 | // ============================================================================ | ||
| 344 | |||
| 345 | impl<T: SealedPin> sealed::Sealed for T {} | ||
| 346 | |||
| 347 | /// io configuration trait for Lpuart Tx configuration | ||
| 348 | pub trait TxPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 349 | /// convert the pin to appropriate function for Lpuart Tx usage | ||
| 350 | fn as_tx(&self); | ||
| 351 | } | ||
| 352 | |||
| 353 | /// io configuration trait for Lpuart Rx configuration | ||
| 354 | pub trait RxPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 355 | /// convert the pin to appropriate function for Lpuart Rx usage | ||
| 356 | fn as_rx(&self); | ||
| 357 | } | ||
| 358 | |||
| 359 | /// io configuration trait for Lpuart Cts | ||
| 360 | pub trait CtsPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 361 | /// convert the pin to appropriate function for Lpuart Cts usage | ||
| 362 | fn as_cts(&self); | ||
| 363 | } | ||
| 364 | |||
| 365 | /// io configuration trait for Lpuart Rts | ||
| 366 | pub trait RtsPin<T: Instance>: Into<AnyPin> + sealed::Sealed + PeripheralType { | ||
| 367 | /// convert the pin to appropriate function for Lpuart Rts usage | ||
| 368 | fn as_rts(&self); | ||
| 369 | } | ||
| 370 | |||
| 371 | macro_rules! impl_tx_pin { | ||
| 372 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 373 | impl TxPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 374 | fn as_tx(&self) { | ||
| 375 | // TODO: Check these are right | ||
| 376 | self.set_pull(crate::gpio::Pull::Up); | ||
| 377 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 378 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 379 | self.set_function(crate::pac::port0::pcr0::Mux::$alt); | ||
| 380 | self.set_enable_input_buffer(); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | }; | ||
| 384 | } | ||
| 385 | |||
| 386 | macro_rules! impl_rx_pin { | ||
| 387 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 388 | impl RxPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 389 | fn as_rx(&self) { | ||
| 390 | // TODO: Check these are right | ||
| 391 | self.set_pull(crate::gpio::Pull::Up); | ||
| 392 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 393 | self.set_drive_strength(crate::gpio::DriveStrength::Double.into()); | ||
| 394 | self.set_function(crate::pac::port0::pcr0::Mux::$alt); | ||
| 395 | self.set_enable_input_buffer(); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | }; | ||
| 399 | } | ||
| 400 | |||
| 401 | // TODO: Macro and impls for CTS/RTS pins | ||
| 402 | macro_rules! impl_cts_pin { | ||
| 403 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 404 | impl CtsPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 405 | fn as_cts(&self) { | ||
| 406 | todo!() | ||
| 407 | } | ||
| 408 | } | ||
| 409 | }; | ||
| 410 | } | ||
| 411 | |||
| 412 | macro_rules! impl_rts_pin { | ||
| 413 | ($inst:ident, $pin:ident, $alt:ident) => { | ||
| 414 | impl RtsPin<crate::peripherals::$inst> for crate::peripherals::$pin { | ||
| 415 | fn as_rts(&self) { | ||
| 416 | todo!() | ||
| 417 | } | ||
| 418 | } | ||
| 419 | }; | ||
| 420 | } | ||
| 421 | |||
| 422 | // LPUART 0 | ||
| 423 | impl_tx_pin!(LPUART0, P0_3, Mux2); | ||
| 424 | impl_tx_pin!(LPUART0, P0_21, Mux3); | ||
| 425 | impl_tx_pin!(LPUART0, P2_1, Mux2); | ||
| 426 | |||
| 427 | impl_rx_pin!(LPUART0, P0_2, Mux2); | ||
| 428 | impl_rx_pin!(LPUART0, P0_20, Mux3); | ||
| 429 | impl_rx_pin!(LPUART0, P2_0, Mux2); | ||
| 430 | |||
| 431 | impl_cts_pin!(LPUART0, P0_1, Mux2); | ||
| 432 | impl_cts_pin!(LPUART0, P0_23, Mux3); | ||
| 433 | impl_cts_pin!(LPUART0, P2_3, Mux2); | ||
| 434 | |||
| 435 | impl_rts_pin!(LPUART0, P0_0, Mux2); | ||
| 436 | impl_rts_pin!(LPUART0, P0_22, Mux3); | ||
| 437 | impl_rts_pin!(LPUART0, P2_2, Mux2); | ||
| 438 | |||
| 439 | // LPUART 1 | ||
| 440 | impl_tx_pin!(LPUART1, P1_9, Mux2); | ||
| 441 | impl_tx_pin!(LPUART1, P2_13, Mux3); | ||
| 442 | impl_tx_pin!(LPUART1, P3_9, Mux3); | ||
| 443 | impl_tx_pin!(LPUART1, P3_21, Mux3); | ||
| 444 | |||
| 445 | impl_rx_pin!(LPUART1, P1_8, Mux2); | ||
| 446 | impl_rx_pin!(LPUART1, P2_12, Mux3); | ||
| 447 | impl_rx_pin!(LPUART1, P3_8, Mux3); | ||
| 448 | impl_rx_pin!(LPUART1, P3_20, Mux3); | ||
| 449 | |||
| 450 | impl_cts_pin!(LPUART1, P1_11, Mux2); | ||
| 451 | impl_cts_pin!(LPUART1, P2_17, Mux3); | ||
| 452 | impl_cts_pin!(LPUART1, P3_11, Mux3); | ||
| 453 | impl_cts_pin!(LPUART1, P3_23, Mux3); | ||
| 454 | |||
| 455 | impl_rts_pin!(LPUART1, P1_10, Mux2); | ||
| 456 | impl_rts_pin!(LPUART1, P2_15, Mux3); | ||
| 457 | impl_rts_pin!(LPUART1, P2_16, Mux3); | ||
| 458 | impl_rts_pin!(LPUART1, P3_10, Mux3); | ||
| 459 | |||
| 460 | // LPUART 2 | ||
| 461 | impl_tx_pin!(LPUART2, P1_5, Mux3); | ||
| 462 | impl_tx_pin!(LPUART2, P1_13, Mux3); | ||
| 463 | impl_tx_pin!(LPUART2, P2_2, Mux3); | ||
| 464 | impl_tx_pin!(LPUART2, P2_10, Mux3); | ||
| 465 | impl_tx_pin!(LPUART2, P3_15, Mux2); | ||
| 466 | |||
| 467 | impl_rx_pin!(LPUART2, P1_4, Mux3); | ||
| 468 | impl_rx_pin!(LPUART2, P1_12, Mux3); | ||
| 469 | impl_rx_pin!(LPUART2, P2_3, Mux3); | ||
| 470 | impl_rx_pin!(LPUART2, P2_11, Mux3); | ||
| 471 | impl_rx_pin!(LPUART2, P3_14, Mux2); | ||
| 472 | |||
| 473 | impl_cts_pin!(LPUART2, P1_7, Mux3); | ||
| 474 | impl_cts_pin!(LPUART2, P1_15, Mux3); | ||
| 475 | impl_cts_pin!(LPUART2, P2_4, Mux3); | ||
| 476 | impl_cts_pin!(LPUART2, P3_13, Mux2); | ||
| 477 | |||
| 478 | impl_rts_pin!(LPUART2, P1_6, Mux3); | ||
| 479 | impl_rts_pin!(LPUART2, P1_14, Mux3); | ||
| 480 | impl_rts_pin!(LPUART2, P2_5, Mux3); | ||
| 481 | impl_rts_pin!(LPUART2, P3_12, Mux2); | ||
| 482 | |||
| 483 | // LPUART 3 | ||
| 484 | impl_tx_pin!(LPUART3, P3_1, Mux3); | ||
| 485 | impl_tx_pin!(LPUART3, P3_12, Mux3); | ||
| 486 | impl_tx_pin!(LPUART3, P4_5, Mux3); | ||
| 487 | |||
| 488 | impl_rx_pin!(LPUART3, P3_0, Mux3); | ||
| 489 | impl_rx_pin!(LPUART3, P3_13, Mux3); | ||
| 490 | impl_rx_pin!(LPUART3, P4_2, Mux3); | ||
| 491 | |||
| 492 | impl_cts_pin!(LPUART3, P3_7, Mux3); | ||
| 493 | impl_cts_pin!(LPUART3, P3_14, Mux3); | ||
| 494 | impl_cts_pin!(LPUART3, P4_6, Mux3); | ||
| 495 | |||
| 496 | impl_rts_pin!(LPUART3, P3_6, Mux3); | ||
| 497 | impl_rts_pin!(LPUART3, P3_15, Mux3); | ||
| 498 | impl_rts_pin!(LPUART3, P4_7, Mux3); | ||
| 499 | |||
| 500 | // LPUART 4 | ||
| 501 | impl_tx_pin!(LPUART4, P2_7, Mux3); | ||
| 502 | impl_tx_pin!(LPUART4, P3_19, Mux2); | ||
| 503 | impl_tx_pin!(LPUART4, P3_27, Mux3); | ||
| 504 | impl_tx_pin!(LPUART4, P4_3, Mux3); | ||
| 505 | |||
| 506 | impl_rx_pin!(LPUART4, P2_6, Mux3); | ||
| 507 | impl_rx_pin!(LPUART4, P3_18, Mux2); | ||
| 508 | impl_rx_pin!(LPUART4, P3_28, Mux3); | ||
| 509 | impl_rx_pin!(LPUART4, P4_4, Mux3); | ||
| 510 | |||
| 511 | impl_cts_pin!(LPUART4, P2_0, Mux3); | ||
| 512 | impl_cts_pin!(LPUART4, P3_17, Mux2); | ||
| 513 | impl_cts_pin!(LPUART4, P3_31, Mux3); | ||
| 514 | |||
| 515 | impl_rts_pin!(LPUART4, P2_1, Mux3); | ||
| 516 | impl_rts_pin!(LPUART4, P3_16, Mux2); | ||
| 517 | impl_rts_pin!(LPUART4, P3_30, Mux3); | ||
| 518 | |||
| 519 | // LPUART 5 | ||
| 520 | impl_tx_pin!(LPUART5, P1_10, Mux8); | ||
| 521 | impl_tx_pin!(LPUART5, P1_17, Mux8); | ||
| 522 | |||
| 523 | impl_rx_pin!(LPUART5, P1_11, Mux8); | ||
| 524 | impl_rx_pin!(LPUART5, P1_16, Mux8); | ||
| 525 | |||
| 526 | impl_cts_pin!(LPUART5, P1_12, Mux8); | ||
| 527 | impl_cts_pin!(LPUART5, P1_19, Mux8); | ||
| 528 | |||
| 529 | impl_rts_pin!(LPUART5, P1_13, Mux8); | ||
| 530 | impl_rts_pin!(LPUART5, P1_18, Mux8); | ||
| 531 | |||
| 532 | // ============================================================================ | ||
| 533 | // ERROR TYPES AND RESULTS | ||
| 534 | // ============================================================================ | ||
| 535 | |||
| 536 | /// LPUART error types | ||
| 537 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 538 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 539 | pub enum Error { | ||
| 540 | /// Read error | ||
| 541 | Read, | ||
| 542 | /// Buffer overflow | ||
| 543 | Overrun, | ||
| 544 | /// Noise error | ||
| 545 | Noise, | ||
| 546 | /// Framing error | ||
| 547 | Framing, | ||
| 548 | /// Parity error | ||
| 549 | Parity, | ||
| 550 | /// Failure | ||
| 551 | Fail, | ||
| 552 | /// Invalid argument | ||
| 553 | InvalidArgument, | ||
| 554 | /// Lpuart baud rate cannot be supported with the given clock | ||
| 555 | UnsupportedBaudrate, | ||
| 556 | /// RX FIFO Empty | ||
| 557 | RxFifoEmpty, | ||
| 558 | /// TX FIFO Full | ||
| 559 | TxFifoFull, | ||
| 560 | /// TX Busy | ||
| 561 | TxBusy, | ||
| 562 | /// Clock Error | ||
| 563 | ClockSetup(ClockError), | ||
| 564 | } | ||
| 565 | |||
| 566 | /// A specialized Result type for LPUART operations | ||
| 567 | pub type Result<T> = core::result::Result<T, Error>; | ||
| 568 | |||
| 569 | // ============================================================================ | ||
| 570 | // CONFIGURATION STRUCTURES | ||
| 571 | // ============================================================================ | ||
| 572 | |||
| 573 | /// Lpuart config | ||
| 574 | #[derive(Debug, Clone, Copy)] | ||
| 575 | pub struct Config { | ||
| 576 | /// Power state required for this peripheral | ||
| 577 | pub power: PoweredClock, | ||
| 578 | /// Clock source | ||
| 579 | pub source: LpuartClockSel, | ||
| 580 | /// Clock divisor | ||
| 581 | pub div: Div4, | ||
| 582 | /// Baud rate in bits per second | ||
| 583 | pub baudrate_bps: u32, | ||
| 584 | /// Parity configuration | ||
| 585 | pub parity_mode: Option<Parity>, | ||
| 586 | /// Number of data bits | ||
| 587 | pub data_bits_count: DataBits, | ||
| 588 | /// MSB First or LSB First configuration | ||
| 589 | pub msb_first: MsbFirst, | ||
| 590 | /// Number of stop bits | ||
| 591 | pub stop_bits_count: StopBits, | ||
| 592 | /// TX FIFO watermark | ||
| 593 | pub tx_fifo_watermark: u8, | ||
| 594 | /// RX FIFO watermark | ||
| 595 | pub rx_fifo_watermark: u8, | ||
| 596 | /// TX CTS source | ||
| 597 | pub tx_cts_source: TxCtsSource, | ||
| 598 | /// TX CTS configure | ||
| 599 | pub tx_cts_config: TxCtsConfig, | ||
| 600 | /// RX IDLE type | ||
| 601 | pub rx_idle_type: IdleType, | ||
| 602 | /// RX IDLE configuration | ||
| 603 | pub rx_idle_config: IdleConfig, | ||
| 604 | /// Swap TXD and RXD pins | ||
| 605 | pub swap_txd_rxd: bool, | ||
| 606 | } | ||
| 607 | |||
| 608 | impl Default for Config { | ||
| 609 | fn default() -> Self { | ||
| 610 | Self { | ||
| 611 | baudrate_bps: 115_200u32, | ||
| 612 | parity_mode: None, | ||
| 613 | data_bits_count: DataBits::Data8, | ||
| 614 | msb_first: MsbFirst::LsbFirst, | ||
| 615 | stop_bits_count: StopBits::One, | ||
| 616 | tx_fifo_watermark: 0, | ||
| 617 | rx_fifo_watermark: 1, | ||
| 618 | tx_cts_source: TxCtsSource::Cts, | ||
| 619 | tx_cts_config: TxCtsConfig::Start, | ||
| 620 | rx_idle_type: IdleType::FromStart, | ||
| 621 | rx_idle_config: IdleConfig::Idle1, | ||
| 622 | swap_txd_rxd: false, | ||
| 623 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | ||
| 624 | source: LpuartClockSel::FroLfDiv, | ||
| 625 | div: Div4::no_div(), | ||
| 626 | } | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | /// LPUART status flags | ||
| 631 | #[derive(Debug, Clone, Copy)] | ||
| 632 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 633 | pub struct Status { | ||
| 634 | /// Transmit data register empty | ||
| 635 | pub tx_empty: bool, | ||
| 636 | /// Transmission complete | ||
| 637 | pub tx_complete: bool, | ||
| 638 | /// Receive data register full | ||
| 639 | pub rx_full: bool, | ||
| 640 | /// Idle line detected | ||
| 641 | pub idle: bool, | ||
| 642 | /// Receiver overrun | ||
| 643 | pub overrun: bool, | ||
| 644 | /// Noise error | ||
| 645 | pub noise: bool, | ||
| 646 | /// Framing error | ||
| 647 | pub framing: bool, | ||
| 648 | /// Parity error | ||
| 649 | pub parity: bool, | ||
| 650 | } | ||
| 651 | |||
| 652 | // ============================================================================ | ||
| 653 | // MODE TRAITS (BLOCKING/ASYNC) | ||
| 654 | // ============================================================================ | ||
| 655 | |||
| 656 | /// Driver move trait. | ||
| 657 | #[allow(private_bounds)] | ||
| 658 | pub trait Mode: sealed::Sealed {} | ||
| 659 | |||
| 660 | /// Blocking mode. | ||
| 661 | pub struct Blocking; | ||
| 662 | impl sealed::Sealed for Blocking {} | ||
| 663 | impl Mode for Blocking {} | ||
| 664 | |||
| 665 | /// Async mode. | ||
| 666 | pub struct Async; | ||
| 667 | impl sealed::Sealed for Async {} | ||
| 668 | impl Mode for Async {} | ||
| 669 | |||
| 670 | // ============================================================================ | ||
| 671 | // CORE DRIVER STRUCTURES | ||
| 672 | // ============================================================================ | ||
| 673 | |||
| 674 | /// Lpuart driver. | ||
| 675 | pub struct Lpuart<'a, M: Mode> { | ||
| 676 | info: Info, | ||
| 677 | tx: LpuartTx<'a, M>, | ||
| 678 | rx: LpuartRx<'a, M>, | ||
| 679 | } | ||
| 680 | |||
| 681 | /// Lpuart TX driver. | ||
| 682 | pub struct LpuartTx<'a, M: Mode> { | ||
| 683 | info: Info, | ||
| 684 | _tx_pin: Peri<'a, AnyPin>, | ||
| 685 | _cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 686 | _tx_dma: Option<Channel<'a>>, | ||
| 687 | mode: PhantomData<(&'a (), M)>, | ||
| 688 | } | ||
| 689 | |||
| 690 | /// Lpuart Rx driver. | ||
| 691 | pub struct LpuartRx<'a, M: Mode> { | ||
| 692 | info: Info, | ||
| 693 | _rx_pin: Peri<'a, AnyPin>, | ||
| 694 | _rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 695 | _rx_dma: Option<Channel<'a>>, | ||
| 696 | mode: PhantomData<(&'a (), M)>, | ||
| 697 | } | ||
| 698 | |||
| 699 | // ============================================================================ | ||
| 700 | // LPUART CORE IMPLEMENTATION | ||
| 701 | // ============================================================================ | ||
| 702 | |||
| 703 | impl<'a, M: Mode> Lpuart<'a, M> { | ||
| 704 | fn init<T: Instance>( | ||
| 705 | enable_tx: bool, | ||
| 706 | enable_rx: bool, | ||
| 707 | enable_tx_cts: bool, | ||
| 708 | enable_rx_rts: bool, | ||
| 709 | config: Config, | ||
| 710 | ) -> Result<()> { | ||
| 711 | let regs = T::info().regs; | ||
| 712 | |||
| 713 | // Enable clocks | ||
| 714 | let conf = LpuartConfig { | ||
| 715 | power: config.power, | ||
| 716 | source: config.source, | ||
| 717 | div: config.div, | ||
| 718 | instance: T::CLOCK_INSTANCE, | ||
| 719 | }; | ||
| 720 | let clock_freq = unsafe { enable_and_reset::<T>(&conf).map_err(Error::ClockSetup)? }; | ||
| 721 | |||
| 722 | // Perform initialization sequence | ||
| 723 | perform_software_reset(regs); | ||
| 724 | disable_transceiver(regs); | ||
| 725 | configure_baudrate(regs, config.baudrate_bps, clock_freq)?; | ||
| 726 | configure_frame_format(regs, &config); | ||
| 727 | configure_control_settings(regs, &config); | ||
| 728 | configure_fifo(regs, &config); | ||
| 729 | clear_all_status_flags(regs); | ||
| 730 | configure_flow_control(regs, enable_tx_cts, enable_rx_rts, &config); | ||
| 731 | configure_bit_order(regs, config.msb_first); | ||
| 732 | enable_transceiver(regs, enable_rx, enable_tx); | ||
| 733 | |||
| 734 | Ok(()) | ||
| 735 | } | ||
| 736 | |||
| 737 | /// Deinitialize the LPUART peripheral | ||
| 738 | pub fn deinit(&self) -> Result<()> { | ||
| 739 | let regs = self.info.regs; | ||
| 740 | |||
| 741 | // Wait for TX operations to complete | ||
| 742 | wait_for_tx_complete(regs); | ||
| 743 | |||
| 744 | // Clear all status flags | ||
| 745 | clear_all_status_flags(regs); | ||
| 746 | |||
| 747 | // Disable the module - clear all CTRL register bits | ||
| 748 | regs.ctrl().reset(); | ||
| 749 | |||
| 750 | Ok(()) | ||
| 751 | } | ||
| 752 | |||
| 753 | /// Split the Lpuart into a transmitter and receiver | ||
| 754 | pub fn split(self) -> (LpuartTx<'a, M>, LpuartRx<'a, M>) { | ||
| 755 | (self.tx, self.rx) | ||
| 756 | } | ||
| 757 | |||
| 758 | /// Split the Lpuart into a transmitter and receiver by mutable reference | ||
| 759 | pub fn split_ref(&mut self) -> (&mut LpuartTx<'a, M>, &mut LpuartRx<'a, M>) { | ||
| 760 | (&mut self.tx, &mut self.rx) | ||
| 761 | } | ||
| 762 | } | ||
| 763 | |||
| 764 | // ============================================================================ | ||
| 765 | // BLOCKING MODE IMPLEMENTATIONS | ||
| 766 | // ============================================================================ | ||
| 767 | |||
| 768 | impl<'a> Lpuart<'a, Blocking> { | ||
| 769 | /// Create a new blocking LPUART instance with RX/TX pins. | ||
| 770 | pub fn new_blocking<T: Instance>( | ||
| 771 | _inner: Peri<'a, T>, | ||
| 772 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 773 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 774 | config: Config, | ||
| 775 | ) -> Result<Self> { | ||
| 776 | // Configure the pins for LPUART usage | ||
| 777 | tx_pin.as_tx(); | ||
| 778 | rx_pin.as_rx(); | ||
| 779 | |||
| 780 | // Initialize the peripheral | ||
| 781 | Self::init::<T>(true, true, false, false, config)?; | ||
| 782 | |||
| 783 | Ok(Self { | ||
| 784 | info: T::info(), | ||
| 785 | tx: LpuartTx::new_inner(T::info(), tx_pin.into(), None, None), | ||
| 786 | rx: LpuartRx::new_inner(T::info(), rx_pin.into(), None, None), | ||
| 787 | }) | ||
| 788 | } | ||
| 789 | |||
| 790 | /// Create a new blocking LPUART instance with RX, TX and RTS/CTS flow control pins | ||
| 791 | pub fn new_blocking_with_rtscts<T: Instance>( | ||
| 792 | _inner: Peri<'a, T>, | ||
| 793 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 794 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 795 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 796 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 797 | config: Config, | ||
| 798 | ) -> Result<Self> { | ||
| 799 | // Configure the pins for LPUART usage | ||
| 800 | rx_pin.as_rx(); | ||
| 801 | tx_pin.as_tx(); | ||
| 802 | rts_pin.as_rts(); | ||
| 803 | cts_pin.as_cts(); | ||
| 804 | |||
| 805 | // Initialize the peripheral with flow control | ||
| 806 | Self::init::<T>(true, true, true, true, config)?; | ||
| 807 | |||
| 808 | Ok(Self { | ||
| 809 | info: T::info(), | ||
| 810 | rx: LpuartRx::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None), | ||
| 811 | tx: LpuartTx::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None), | ||
| 812 | }) | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | // ---------------------------------------------------------------------------- | ||
| 817 | // Blocking TX Implementation | ||
| 818 | // ---------------------------------------------------------------------------- | ||
| 819 | |||
| 820 | impl<'a, M: Mode> LpuartTx<'a, M> { | ||
| 821 | fn new_inner( | ||
| 822 | info: Info, | ||
| 823 | tx_pin: Peri<'a, AnyPin>, | ||
| 824 | cts_pin: Option<Peri<'a, AnyPin>>, | ||
| 825 | tx_dma: Option<Channel<'a>>, | ||
| 826 | ) -> Self { | ||
| 827 | Self { | ||
| 828 | info, | ||
| 829 | _tx_pin: tx_pin, | ||
| 830 | _cts_pin: cts_pin, | ||
| 831 | _tx_dma: tx_dma, | ||
| 832 | mode: PhantomData, | ||
| 833 | } | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | impl<'a> LpuartTx<'a, Blocking> { | ||
| 838 | /// Create a new blocking LPUART transmitter instance | ||
| 839 | pub fn new_blocking<T: Instance>( | ||
| 840 | _inner: Peri<'a, T>, | ||
| 841 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 842 | config: Config, | ||
| 843 | ) -> Result<Self> { | ||
| 844 | // Configure the pins for LPUART usage | ||
| 845 | tx_pin.as_tx(); | ||
| 846 | |||
| 847 | // Initialize the peripheral | ||
| 848 | Lpuart::<Blocking>::init::<T>(true, false, false, false, config)?; | ||
| 849 | |||
| 850 | Ok(Self::new_inner(T::info(), tx_pin.into(), None, None)) | ||
| 851 | } | ||
| 852 | |||
| 853 | /// Create a new blocking LPUART transmitter instance with CTS flow control | ||
| 854 | pub fn new_blocking_with_cts<T: Instance>( | ||
| 855 | _inner: Peri<'a, T>, | ||
| 856 | tx_pin: Peri<'a, impl TxPin<T>>, | ||
| 857 | cts_pin: Peri<'a, impl CtsPin<T>>, | ||
| 858 | config: Config, | ||
| 859 | ) -> Result<Self> { | ||
| 860 | tx_pin.as_tx(); | ||
| 861 | cts_pin.as_cts(); | ||
| 862 | |||
| 863 | Lpuart::<Blocking>::init::<T>(true, false, true, false, config)?; | ||
| 864 | |||
| 865 | Ok(Self::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None)) | ||
| 866 | } | ||
| 867 | |||
| 868 | fn write_byte_internal(&mut self, byte: u8) -> Result<()> { | ||
| 869 | self.info.regs.data().modify(|_, w| unsafe { w.bits(u32::from(byte)) }); | ||
| 870 | |||
| 871 | Ok(()) | ||
| 872 | } | ||
| 873 | |||
| 874 | fn blocking_write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 875 | while self.info.regs.stat().read().tdre().is_txdata() {} | ||
| 876 | self.write_byte_internal(byte) | ||
| 877 | } | ||
| 878 | |||
| 879 | fn write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 880 | if self.info.regs.stat().read().tdre().is_txdata() { | ||
| 881 | Err(Error::TxFifoFull) | ||
| 882 | } else { | ||
| 883 | self.write_byte_internal(byte) | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | /// Write data to LPUART TX blocking execution until all data is sent. | ||
| 888 | pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 889 | for x in buf { | ||
| 890 | self.blocking_write_byte(*x)?; | ||
| 891 | } | ||
| 892 | |||
| 893 | Ok(()) | ||
| 894 | } | ||
| 895 | |||
| 896 | pub fn write_str_blocking(&mut self, buf: &str) { | ||
| 897 | let _ = self.blocking_write(buf.as_bytes()); | ||
| 898 | } | ||
| 899 | |||
| 900 | /// Write data to LPUART TX without blocking. | ||
| 901 | pub fn write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 902 | for x in buf { | ||
| 903 | self.write_byte(*x)?; | ||
| 904 | } | ||
| 905 | |||
| 906 | Ok(()) | ||
| 907 | } | ||
| 908 | |||
| 909 | /// Flush LPUART TX blocking execution until all data has been transmitted. | ||
| 910 | pub fn blocking_flush(&mut self) -> Result<()> { | ||
| 911 | while self.info.regs.water().read().txcount().bits() != 0 { | ||
| 912 | // Wait for TX FIFO to drain | ||
| 913 | } | ||
| 914 | |||
| 915 | // Wait for last character to shift out | ||
| 916 | while self.info.regs.stat().read().tc().is_active() { | ||
| 917 | // Wait for transmission to complete | ||
| 918 | } | ||
| 919 | |||
| 920 | Ok(()) | ||
| 921 | } | ||
| 922 | |||
| 923 | /// Flush LPUART TX. | ||
| 924 | pub fn flush(&mut self) -> Result<()> { | ||
| 925 | // Check if TX FIFO is empty | ||
| 926 | if self.info.regs.water().read().txcount().bits() != 0 { | ||
| 927 | return Err(Error::TxBusy); | ||
| 928 | } | ||
| 929 | |||
| 930 | // Check if transmission is complete | ||
| 931 | if self.info.regs.stat().read().tc().is_active() { | ||
| 932 | return Err(Error::TxBusy); | ||
| 933 | } | ||
| 934 | |||
| 935 | Ok(()) | ||
| 936 | } | ||
| 937 | } | ||
| 938 | |||
| 939 | // ---------------------------------------------------------------------------- | ||
| 940 | // Blocking RX Implementation | ||
| 941 | // ---------------------------------------------------------------------------- | ||
| 942 | |||
| 943 | impl<'a, M: Mode> LpuartRx<'a, M> { | ||
| 944 | fn new_inner( | ||
| 945 | info: Info, | ||
| 946 | rx_pin: Peri<'a, AnyPin>, | ||
| 947 | rts_pin: Option<Peri<'a, AnyPin>>, | ||
| 948 | rx_dma: Option<Channel<'a>>, | ||
| 949 | ) -> Self { | ||
| 950 | Self { | ||
| 951 | info, | ||
| 952 | _rx_pin: rx_pin, | ||
| 953 | _rts_pin: rts_pin, | ||
| 954 | _rx_dma: rx_dma, | ||
| 955 | mode: PhantomData, | ||
| 956 | } | ||
| 957 | } | ||
| 958 | } | ||
| 959 | |||
| 960 | impl<'a> LpuartRx<'a, Blocking> { | ||
| 961 | /// Create a new blocking LPUART Receiver instance | ||
| 962 | pub fn new_blocking<T: Instance>( | ||
| 963 | _inner: Peri<'a, T>, | ||
| 964 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 965 | config: Config, | ||
| 966 | ) -> Result<Self> { | ||
| 967 | rx_pin.as_rx(); | ||
| 968 | |||
| 969 | Lpuart::<Blocking>::init::<T>(false, true, false, false, config)?; | ||
| 970 | |||
| 971 | Ok(Self::new_inner(T::info(), rx_pin.into(), None, None)) | ||
| 972 | } | ||
| 973 | |||
| 974 | /// Create a new blocking LPUART Receiver instance with RTS flow control | ||
| 975 | pub fn new_blocking_with_rts<T: Instance>( | ||
| 976 | _inner: Peri<'a, T>, | ||
| 977 | rx_pin: Peri<'a, impl RxPin<T>>, | ||
| 978 | rts_pin: Peri<'a, impl RtsPin<T>>, | ||
| 979 | config: Config, | ||
| 980 | ) -> Result<Self> { | ||
| 981 | rx_pin.as_rx(); | ||
| 982 | rts_pin.as_rts(); | ||
| 983 | |||
| 984 | Lpuart::<Blocking>::init::<T>(false, true, false, true, config)?; | ||
| 985 | |||
| 986 | Ok(Self::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None)) | ||
| 987 | } | ||
| 988 | |||
| 989 | fn read_byte_internal(&mut self) -> Result<u8> { | ||
| 990 | let data = self.info.regs.data().read(); | ||
| 991 | |||
| 992 | Ok((data.bits() & 0xFF) as u8) | ||
| 993 | } | ||
| 994 | |||
| 995 | fn read_byte(&mut self) -> Result<u8> { | ||
| 996 | check_and_clear_rx_errors(self.info.regs)?; | ||
| 997 | |||
| 998 | if !has_data(self.info.regs) { | ||
| 999 | return Err(Error::RxFifoEmpty); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | self.read_byte_internal() | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | fn blocking_read_byte(&mut self) -> Result<u8> { | ||
| 1006 | loop { | ||
| 1007 | if has_data(self.info.regs) { | ||
| 1008 | return self.read_byte_internal(); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | check_and_clear_rx_errors(self.info.regs)?; | ||
| 1012 | } | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | /// Read data from LPUART RX without blocking. | ||
| 1016 | pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1017 | for byte in buf.iter_mut() { | ||
| 1018 | *byte = self.read_byte()?; | ||
| 1019 | } | ||
| 1020 | Ok(()) | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | /// Read data from LPUART RX blocking execution until the buffer is filled. | ||
| 1024 | pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1025 | for byte in buf.iter_mut() { | ||
| 1026 | *byte = self.blocking_read_byte()?; | ||
| 1027 | } | ||
| 1028 | Ok(()) | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | impl<'a> Lpuart<'a, Blocking> { | ||
| 1033 | /// Read data from LPUART RX blocking execution until the buffer is filled | ||
| 1034 | pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1035 | self.rx.blocking_read(buf) | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /// Read data from LPUART RX without blocking | ||
| 1039 | pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { | ||
| 1040 | self.rx.read(buf) | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | /// Write data to LPUART TX blocking execution until all data is sent | ||
| 1044 | pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 1045 | self.tx.blocking_write(buf) | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | pub fn write_byte(&mut self, byte: u8) -> Result<()> { | ||
| 1049 | self.tx.write_byte(byte) | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | pub fn read_byte_blocking(&mut self) -> u8 { | ||
| 1053 | loop { | ||
| 1054 | if let Ok(b) = self.rx.read_byte() { | ||
| 1055 | return b; | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | pub fn write_str_blocking(&mut self, buf: &str) { | ||
| 1061 | self.tx.write_str_blocking(buf); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /// Write data to LPUART TX without blocking | ||
| 1065 | pub fn write(&mut self, buf: &[u8]) -> Result<()> { | ||
| 1066 | self.tx.write(buf) | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | /// Flush LPUART TX blocking execution until all data has been transmitted | ||
| 1070 | pub fn blocking_flush(&mut self) -> Result<()> { | ||
| 1071 | self.tx.blocking_flush() | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | /// Flush LPUART TX without blocking | ||
| 1075 | pub fn flush(&mut self) -> Result<()> { | ||
| 1076 | self.tx.flush() | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | // ============================================================================ | ||
| 1081 | // ASYNC MODE IMPLEMENTATIONS | ||
| 1082 | // ============================================================================ | ||
| 1083 | |||
| 1084 | // TODO: Implement async mode for LPUART | ||
| 1085 | |||
| 1086 | // ============================================================================ | ||
| 1087 | // EMBEDDED-HAL 0.2 TRAIT IMPLEMENTATIONS | ||
| 1088 | // ============================================================================ | ||
| 1089 | |||
| 1090 | impl embedded_hal_02::serial::Read<u8> for LpuartRx<'_, Blocking> { | ||
| 1091 | type Error = Error; | ||
| 1092 | |||
| 1093 | fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> { | ||
| 1094 | let mut buf = [0; 1]; | ||
| 1095 | match self.read(&mut buf) { | ||
| 1096 | Ok(_) => Ok(buf[0]), | ||
| 1097 | Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), | ||
| 1098 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1099 | } | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | impl embedded_hal_02::serial::Write<u8> for LpuartTx<'_, Blocking> { | ||
| 1104 | type Error = Error; | ||
| 1105 | |||
| 1106 | fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1107 | match self.write(&[word]) { | ||
| 1108 | Ok(_) => Ok(()), | ||
| 1109 | Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), | ||
| 1110 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1111 | } | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1115 | match self.flush() { | ||
| 1116 | Ok(_) => Ok(()), | ||
| 1117 | Err(Error::TxBusy) => Err(nb::Error::WouldBlock), | ||
| 1118 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | impl embedded_hal_02::blocking::serial::Write<u8> for LpuartTx<'_, Blocking> { | ||
| 1124 | type Error = Error; | ||
| 1125 | |||
| 1126 | fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { | ||
| 1127 | self.blocking_write(buffer) | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | fn bflush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1131 | self.blocking_flush() | ||
| 1132 | } | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | impl embedded_hal_02::serial::Read<u8> for Lpuart<'_, Blocking> { | ||
| 1136 | type Error = Error; | ||
| 1137 | |||
| 1138 | fn read(&mut self) -> core::result::Result<u8, nb::Error<Self::Error>> { | ||
| 1139 | embedded_hal_02::serial::Read::read(&mut self.rx) | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | impl embedded_hal_02::serial::Write<u8> for Lpuart<'_, Blocking> { | ||
| 1144 | type Error = Error; | ||
| 1145 | |||
| 1146 | fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1147 | embedded_hal_02::serial::Write::write(&mut self.tx, word) | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | fn flush(&mut self) -> core::result::Result<(), nb::Error<Self::Error>> { | ||
| 1151 | embedded_hal_02::serial::Write::flush(&mut self.tx) | ||
| 1152 | } | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | impl embedded_hal_02::blocking::serial::Write<u8> for Lpuart<'_, Blocking> { | ||
| 1156 | type Error = Error; | ||
| 1157 | |||
| 1158 | fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { | ||
| 1159 | self.blocking_write(buffer) | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | fn bflush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1163 | self.blocking_flush() | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | // ============================================================================ | ||
| 1168 | // EMBEDDED-HAL-NB TRAIT IMPLEMENTATIONS | ||
| 1169 | // ============================================================================ | ||
| 1170 | |||
| 1171 | impl embedded_hal_nb::serial::Error for Error { | ||
| 1172 | fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { | ||
| 1173 | match *self { | ||
| 1174 | Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, | ||
| 1175 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, | ||
| 1176 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, | ||
| 1177 | Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise, | ||
| 1178 | _ => embedded_hal_nb::serial::ErrorKind::Other, | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | impl embedded_hal_nb::serial::ErrorType for LpuartRx<'_, Blocking> { | ||
| 1184 | type Error = Error; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | impl embedded_hal_nb::serial::ErrorType for LpuartTx<'_, Blocking> { | ||
| 1188 | type Error = Error; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | impl embedded_hal_nb::serial::ErrorType for Lpuart<'_, Blocking> { | ||
| 1192 | type Error = Error; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | impl embedded_hal_nb::serial::Read for LpuartRx<'_, Blocking> { | ||
| 1196 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 1197 | let mut buf = [0; 1]; | ||
| 1198 | match self.read(&mut buf) { | ||
| 1199 | Ok(_) => Ok(buf[0]), | ||
| 1200 | Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), | ||
| 1201 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | impl embedded_hal_nb::serial::Write for LpuartTx<'_, Blocking> { | ||
| 1207 | fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { | ||
| 1208 | match self.write(&[word]) { | ||
| 1209 | Ok(_) => Ok(()), | ||
| 1210 | Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), | ||
| 1211 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 1216 | match self.flush() { | ||
| 1217 | Ok(_) => Ok(()), | ||
| 1218 | Err(Error::TxBusy) => Err(nb::Error::WouldBlock), | ||
| 1219 | Err(e) => Err(nb::Error::Other(e)), | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | impl embedded_hal_nb::serial::Read for Lpuart<'_, Blocking> { | ||
| 1225 | fn read(&mut self) -> nb::Result<u8, Self::Error> { | ||
| 1226 | embedded_hal_nb::serial::Read::read(&mut self.rx) | ||
| 1227 | } | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | impl embedded_hal_nb::serial::Write for Lpuart<'_, Blocking> { | ||
| 1231 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | ||
| 1232 | embedded_hal_nb::serial::Write::write(&mut self.tx, char) | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | fn flush(&mut self) -> nb::Result<(), Self::Error> { | ||
| 1236 | embedded_hal_nb::serial::Write::flush(&mut self.tx) | ||
| 1237 | } | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | // ============================================================================ | ||
| 1241 | // EMBEDDED-IO TRAIT IMPLEMENTATIONS | ||
| 1242 | // ============================================================================ | ||
| 1243 | |||
| 1244 | impl embedded_io::Error for Error { | ||
| 1245 | fn kind(&self) -> embedded_io::ErrorKind { | ||
| 1246 | embedded_io::ErrorKind::Other | ||
| 1247 | } | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | impl embedded_io::ErrorType for LpuartRx<'_, Blocking> { | ||
| 1251 | type Error = Error; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | impl embedded_io::ErrorType for LpuartTx<'_, Blocking> { | ||
| 1255 | type Error = Error; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | impl embedded_io::ErrorType for Lpuart<'_, Blocking> { | ||
| 1259 | type Error = Error; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | impl embedded_io::Read for LpuartRx<'_, Blocking> { | ||
| 1263 | fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1264 | self.blocking_read(buf).map(|_| buf.len()) | ||
| 1265 | } | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | impl embedded_io::Write for LpuartTx<'_, Blocking> { | ||
| 1269 | fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1270 | self.blocking_write(buf).map(|_| buf.len()) | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1274 | self.blocking_flush() | ||
| 1275 | } | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | impl embedded_io::Read for Lpuart<'_, Blocking> { | ||
| 1279 | fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1280 | embedded_io::Read::read(&mut self.rx, buf) | ||
| 1281 | } | ||
| 1282 | } | ||
| 1283 | |||
| 1284 | impl embedded_io::Write for Lpuart<'_, Blocking> { | ||
| 1285 | fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> { | ||
| 1286 | embedded_io::Write::write(&mut self.tx, buf) | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | fn flush(&mut self) -> core::result::Result<(), Self::Error> { | ||
| 1290 | embedded_io::Write::flush(&mut self.tx) | ||
| 1291 | } | ||
| 1292 | } | ||
