aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa/src/lpuart/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mcxa/src/lpuart/mod.rs')
-rw-r--r--embassy-mcxa/src/lpuart/mod.rs1292
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 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::{Peri, PeripheralType};
4use paste::paste;
5
6use crate::clocks::periph_helpers::{Div4, LpuartClockSel, LpuartConfig};
7use crate::clocks::{enable_and_reset, ClockError, Gate, PoweredClock};
8use crate::gpio::SealedPin;
9use crate::pac::lpuart0::baud::Sbns as StopBits;
10use crate::pac::lpuart0::ctrl::{Idlecfg as IdleConfig, Ilt as IdleType, Pt as Parity, M as DataBits};
11use crate::pac::lpuart0::modir::{Txctsc as TxCtsConfig, Txctssrc as TxCtsSource};
12use crate::pac::lpuart0::stat::Msbf as MsbFirst;
13use crate::{interrupt, pac, AnyPin};
14
15pub 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 ---
25mod dma {
26 pub struct Channel<'d> {
27 pub(super) _lifetime: core::marker::PhantomData<&'d ()>,
28 }
29}
30
31use dma::Channel;
32
33// --- END DMA ---
34
35// ============================================================================
36// MISC
37// ============================================================================
38
39mod sealed {
40 /// Simply seal a trait to prevent external implementations
41 pub trait Sealed {}
42}
43
44// ============================================================================
45// INSTANCE TRAIT
46// ============================================================================
47
48pub type Regs = &'static crate::pac::lpuart0::RegisterBlock;
49
50pub trait SealedInstance {
51 fn info() -> Info;
52 fn index() -> usize;
53 fn buffered_state() -> &'static buffered::State;
54}
55
56pub struct Info {
57 pub regs: Regs,
58}
59
60/// Trait for LPUART peripheral instances
61#[allow(private_bounds)]
62pub 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
67macro_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
99impl_instance!(0, 1, 2, 3, 4, 5);
100
101// ============================================================================
102// INSTANCE HELPER FUNCTIONS
103// ============================================================================
104
105/// Perform software reset on the LPUART peripheral
106pub 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
113pub fn disable_transceiver(regs: Regs) {
114 regs.ctrl().modify(|_, w| w.te().disabled().re().disabled());
115}
116
117/// Calculate and configure baudrate settings
118pub 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)
139pub 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)
148pub 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
183pub 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
201pub fn clear_all_status_flags(regs: Regs) {
202 regs.stat().reset();
203}
204
205/// Configure hardware flow control if enabled
206pub 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)
233pub 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
238pub 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
251pub 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
290pub 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
302pub 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
331pub 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
345impl<T: SealedPin> sealed::Sealed for T {}
346
347/// io configuration trait for Lpuart Tx configuration
348pub 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
354pub 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
360pub 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
366pub 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
371macro_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
386macro_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
402macro_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
412macro_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
423impl_tx_pin!(LPUART0, P0_3, Mux2);
424impl_tx_pin!(LPUART0, P0_21, Mux3);
425impl_tx_pin!(LPUART0, P2_1, Mux2);
426
427impl_rx_pin!(LPUART0, P0_2, Mux2);
428impl_rx_pin!(LPUART0, P0_20, Mux3);
429impl_rx_pin!(LPUART0, P2_0, Mux2);
430
431impl_cts_pin!(LPUART0, P0_1, Mux2);
432impl_cts_pin!(LPUART0, P0_23, Mux3);
433impl_cts_pin!(LPUART0, P2_3, Mux2);
434
435impl_rts_pin!(LPUART0, P0_0, Mux2);
436impl_rts_pin!(LPUART0, P0_22, Mux3);
437impl_rts_pin!(LPUART0, P2_2, Mux2);
438
439// LPUART 1
440impl_tx_pin!(LPUART1, P1_9, Mux2);
441impl_tx_pin!(LPUART1, P2_13, Mux3);
442impl_tx_pin!(LPUART1, P3_9, Mux3);
443impl_tx_pin!(LPUART1, P3_21, Mux3);
444
445impl_rx_pin!(LPUART1, P1_8, Mux2);
446impl_rx_pin!(LPUART1, P2_12, Mux3);
447impl_rx_pin!(LPUART1, P3_8, Mux3);
448impl_rx_pin!(LPUART1, P3_20, Mux3);
449
450impl_cts_pin!(LPUART1, P1_11, Mux2);
451impl_cts_pin!(LPUART1, P2_17, Mux3);
452impl_cts_pin!(LPUART1, P3_11, Mux3);
453impl_cts_pin!(LPUART1, P3_23, Mux3);
454
455impl_rts_pin!(LPUART1, P1_10, Mux2);
456impl_rts_pin!(LPUART1, P2_15, Mux3);
457impl_rts_pin!(LPUART1, P2_16, Mux3);
458impl_rts_pin!(LPUART1, P3_10, Mux3);
459
460// LPUART 2
461impl_tx_pin!(LPUART2, P1_5, Mux3);
462impl_tx_pin!(LPUART2, P1_13, Mux3);
463impl_tx_pin!(LPUART2, P2_2, Mux3);
464impl_tx_pin!(LPUART2, P2_10, Mux3);
465impl_tx_pin!(LPUART2, P3_15, Mux2);
466
467impl_rx_pin!(LPUART2, P1_4, Mux3);
468impl_rx_pin!(LPUART2, P1_12, Mux3);
469impl_rx_pin!(LPUART2, P2_3, Mux3);
470impl_rx_pin!(LPUART2, P2_11, Mux3);
471impl_rx_pin!(LPUART2, P3_14, Mux2);
472
473impl_cts_pin!(LPUART2, P1_7, Mux3);
474impl_cts_pin!(LPUART2, P1_15, Mux3);
475impl_cts_pin!(LPUART2, P2_4, Mux3);
476impl_cts_pin!(LPUART2, P3_13, Mux2);
477
478impl_rts_pin!(LPUART2, P1_6, Mux3);
479impl_rts_pin!(LPUART2, P1_14, Mux3);
480impl_rts_pin!(LPUART2, P2_5, Mux3);
481impl_rts_pin!(LPUART2, P3_12, Mux2);
482
483// LPUART 3
484impl_tx_pin!(LPUART3, P3_1, Mux3);
485impl_tx_pin!(LPUART3, P3_12, Mux3);
486impl_tx_pin!(LPUART3, P4_5, Mux3);
487
488impl_rx_pin!(LPUART3, P3_0, Mux3);
489impl_rx_pin!(LPUART3, P3_13, Mux3);
490impl_rx_pin!(LPUART3, P4_2, Mux3);
491
492impl_cts_pin!(LPUART3, P3_7, Mux3);
493impl_cts_pin!(LPUART3, P3_14, Mux3);
494impl_cts_pin!(LPUART3, P4_6, Mux3);
495
496impl_rts_pin!(LPUART3, P3_6, Mux3);
497impl_rts_pin!(LPUART3, P3_15, Mux3);
498impl_rts_pin!(LPUART3, P4_7, Mux3);
499
500// LPUART 4
501impl_tx_pin!(LPUART4, P2_7, Mux3);
502impl_tx_pin!(LPUART4, P3_19, Mux2);
503impl_tx_pin!(LPUART4, P3_27, Mux3);
504impl_tx_pin!(LPUART4, P4_3, Mux3);
505
506impl_rx_pin!(LPUART4, P2_6, Mux3);
507impl_rx_pin!(LPUART4, P3_18, Mux2);
508impl_rx_pin!(LPUART4, P3_28, Mux3);
509impl_rx_pin!(LPUART4, P4_4, Mux3);
510
511impl_cts_pin!(LPUART4, P2_0, Mux3);
512impl_cts_pin!(LPUART4, P3_17, Mux2);
513impl_cts_pin!(LPUART4, P3_31, Mux3);
514
515impl_rts_pin!(LPUART4, P2_1, Mux3);
516impl_rts_pin!(LPUART4, P3_16, Mux2);
517impl_rts_pin!(LPUART4, P3_30, Mux3);
518
519// LPUART 5
520impl_tx_pin!(LPUART5, P1_10, Mux8);
521impl_tx_pin!(LPUART5, P1_17, Mux8);
522
523impl_rx_pin!(LPUART5, P1_11, Mux8);
524impl_rx_pin!(LPUART5, P1_16, Mux8);
525
526impl_cts_pin!(LPUART5, P1_12, Mux8);
527impl_cts_pin!(LPUART5, P1_19, Mux8);
528
529impl_rts_pin!(LPUART5, P1_13, Mux8);
530impl_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))]
539pub 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
567pub type Result<T> = core::result::Result<T, Error>;
568
569// ============================================================================
570// CONFIGURATION STRUCTURES
571// ============================================================================
572
573/// Lpuart config
574#[derive(Debug, Clone, Copy)]
575pub 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
608impl 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))]
633pub 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)]
658pub trait Mode: sealed::Sealed {}
659
660/// Blocking mode.
661pub struct Blocking;
662impl sealed::Sealed for Blocking {}
663impl Mode for Blocking {}
664
665/// Async mode.
666pub struct Async;
667impl sealed::Sealed for Async {}
668impl Mode for Async {}
669
670// ============================================================================
671// CORE DRIVER STRUCTURES
672// ============================================================================
673
674/// Lpuart driver.
675pub struct Lpuart<'a, M: Mode> {
676 info: Info,
677 tx: LpuartTx<'a, M>,
678 rx: LpuartRx<'a, M>,
679}
680
681/// Lpuart TX driver.
682pub 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.
691pub 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
703impl<'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
768impl<'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
820impl<'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
837impl<'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
943impl<'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
960impl<'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
1032impl<'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
1090impl 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
1103impl 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
1123impl 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
1135impl 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
1143impl 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
1155impl 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
1171impl 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
1183impl embedded_hal_nb::serial::ErrorType for LpuartRx<'_, Blocking> {
1184 type Error = Error;
1185}
1186
1187impl embedded_hal_nb::serial::ErrorType for LpuartTx<'_, Blocking> {
1188 type Error = Error;
1189}
1190
1191impl embedded_hal_nb::serial::ErrorType for Lpuart<'_, Blocking> {
1192 type Error = Error;
1193}
1194
1195impl 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
1206impl 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
1224impl 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
1230impl 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
1244impl embedded_io::Error for Error {
1245 fn kind(&self) -> embedded_io::ErrorKind {
1246 embedded_io::ErrorKind::Other
1247 }
1248}
1249
1250impl embedded_io::ErrorType for LpuartRx<'_, Blocking> {
1251 type Error = Error;
1252}
1253
1254impl embedded_io::ErrorType for LpuartTx<'_, Blocking> {
1255 type Error = Error;
1256}
1257
1258impl embedded_io::ErrorType for Lpuart<'_, Blocking> {
1259 type Error = Error;
1260}
1261
1262impl 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
1268impl 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
1278impl 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
1284impl 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}