From 717346f21a4cf4993c2a1f046e26b6bf647d89cb Mon Sep 17 00:00:00 2001 From: JanKomarekNXP <151725448+JanKomarekNXP@users.noreply.github.com> Date: Mon, 1 Dec 2025 18:07:58 +0100 Subject: Refactor LPUART driver constructors (#51) * Refactor LPUART driver constructors - Add new_with_rtscts(), new_with_rts(), new_with_cts() methods - Store RTS/CTS pins in TX/RX structs - Remove enable_tx, enable_rx, enable_rx_rts, enable_tx_cts config fields - Fix typo: msb_firs -> msb_first - Fix write_byte() return type to Result<()> * Update hello example for LPUART driver changes * Refactor buffered LPUART initialization logic - Split new_inner() into init_common() and separate helpers for full-duplex, TX-only, and RX-only - Replace assert!() with proper Error::InvalidArgument returns for empty buffers - Simplify constructor implementations by removing expect() calls --- src/lpuart/buffered.rs | 505 +++++++++++++++++++++++++++++-------------------- src/lpuart/mod.rs | 141 +++++++++----- 2 files changed, 396 insertions(+), 250 deletions(-) (limited to 'src') diff --git a/src/lpuart/buffered.rs b/src/lpuart/buffered.rs index 6f41c33c9..8eb443ca7 100644 --- a/src/lpuart/buffered.rs +++ b/src/lpuart/buffered.rs @@ -16,11 +16,11 @@ use crate::interrupt; /// State for buffered LPUART operations pub struct State { - rx_waker: AtomicWaker, - rx_buf: RingBuffer, tx_waker: AtomicWaker, tx_buf: RingBuffer, tx_done: AtomicBool, + rx_waker: AtomicWaker, + rx_buf: RingBuffer, initialized: AtomicBool, } @@ -34,11 +34,11 @@ impl State { /// Create a new state instance pub const fn new() -> Self { Self { - rx_waker: AtomicWaker::new(), - rx_buf: RingBuffer::new(), tx_waker: AtomicWaker::new(), tx_buf: RingBuffer::new(), tx_done: AtomicBool::new(true), + rx_waker: AtomicWaker::new(), + rx_buf: RingBuffer::new(), initialized: AtomicBool::new(false), } } @@ -58,6 +58,7 @@ pub struct BufferedLpuartTx<'a> { info: Info, state: &'static State, _tx_pin: Peri<'a, AnyPin>, + _cts_pin: Option>, } /// Buffered LPUART RX driver @@ -65,6 +66,7 @@ pub struct BufferedLpuartRx<'a> { info: Info, state: &'static State, _rx_pin: Peri<'a, AnyPin>, + _rts_pin: Option>, } // ============================================================================ @@ -72,143 +74,41 @@ pub struct BufferedLpuartRx<'a> { // ============================================================================ impl<'a> BufferedLpuart<'a> { - /// Create a new buffered LPUART instance - pub fn new( - _inner: Peri<'a, T>, - tx_pin: Peri<'a, impl TxPin>, - rx_pin: Peri<'a, impl RxPin>, - _irq: impl interrupt::typelevel::Binding> + 'a, - tx_buffer: &'a mut [u8], - rx_buffer: &'a mut [u8], - config: Config, - ) -> Result { - // Configure pins - tx_pin.as_tx(); - rx_pin.as_rx(); - - // Convert pins to AnyPin - let tx_pin: Peri<'a, AnyPin> = tx_pin.into(); - let rx_pin: Peri<'a, AnyPin> = rx_pin.into(); - - let state = T::buffered_state(); - - // Initialize the peripheral - Self::init::(Some(&tx_pin), Some(&rx_pin), None, None, tx_buffer, rx_buffer, config)?; - - Ok(Self { - tx: BufferedLpuartTx { - info: T::info(), - state, - _tx_pin: tx_pin, - }, - rx: BufferedLpuartRx { - info: T::info(), - state, - _rx_pin: rx_pin, - }, - }) - } - - /// Create a new buffered LPUART with flexible pin configuration - #[allow(clippy::too_many_arguments)] - pub fn new_with_pins( - _inner: Peri<'a, T>, - tx_pin: Option>>, - rx_pin: Option>>, - rts_pin: Option>>, - cts_pin: Option>>, - _irq: impl interrupt::typelevel::Binding> + 'a, - tx_buffer: &'a mut [u8], - rx_buffer: &'a mut [u8], - config: Config, - ) -> Result { - // Configure pins if provided - let tx_pin: Option> = tx_pin.map(|pin| { - pin.as_tx(); - pin.into() - }); - - let rx_pin: Option> = rx_pin.map(|pin| { - pin.as_rx(); - pin.into() - }); - - let rts_pin: Option> = rts_pin.map(|pin| { - pin.as_rts(); - pin.into() - }); - - let cts_pin: Option> = cts_pin.map(|pin| { - pin.as_cts(); - pin.into() - }); - + /// Common initialization logic + fn init_common( + _inner: &Peri<'a, T>, + tx_buffer: Option<&'a mut [u8]>, + rx_buffer: Option<&'a mut [u8]>, + config: &Config, + enable_tx: bool, + enable_rx: bool, + enable_rts: bool, + enable_cts: bool, + ) -> Result<&'static State> { let state = T::buffered_state(); - // Initialize the peripheral - Self::init::( - tx_pin.as_ref(), - rx_pin.as_ref(), - rts_pin.as_ref(), - cts_pin.as_ref(), - tx_buffer, - rx_buffer, - config, - )?; - - // Create TX and RX instances - let (tx, rx) = if let (Some(tx_pin), Some(rx_pin)) = (tx_pin, rx_pin) { - ( - BufferedLpuartTx { - info: T::info(), - state, - _tx_pin: tx_pin, - }, - BufferedLpuartRx { - info: T::info(), - state, - _rx_pin: rx_pin, - }, - ) - } else { - return Err(Error::InvalidArgument); - }; - - Ok(Self { tx, rx }) - } - - fn init( - _tx: Option<&Peri<'a, AnyPin>>, - _rx: Option<&Peri<'a, AnyPin>>, - _rts: Option<&Peri<'a, AnyPin>>, - _cts: Option<&Peri<'a, AnyPin>>, - tx_buffer: &'a mut [u8], - rx_buffer: &'a mut [u8], - mut config: Config, - ) -> Result<()> { - let regs = T::info().regs; - let state = T::buffered_state(); - - // Check if already initialized if state.initialized.load(Ordering::Relaxed) { return Err(Error::InvalidArgument); } - // Initialize ring buffers - assert!(!tx_buffer.is_empty()); - unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), tx_buffer.len()) } + // Initialize buffers + if let Some(tx_buffer) = tx_buffer { + if tx_buffer.is_empty() { + return Err(Error::InvalidArgument); + } + unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), tx_buffer.len()) }; + } - assert!(!rx_buffer.is_empty()); - unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_buffer.len()) } + if let Some(rx_buffer) = rx_buffer { + if rx_buffer.is_empty() { + return Err(Error::InvalidArgument); + } + unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_buffer.len()) }; + } - // Mark as initialized state.initialized.store(true, Ordering::Relaxed); - // Enable TX and RX for buffered operation - config.enable_tx = true; - config.enable_rx = true; - - // Enable clocks + // Enable clocks and initialize hardware let conf = LpuartConfig { power: config.power, source: config.source, @@ -217,6 +117,68 @@ impl<'a> BufferedLpuart<'a> { }; let clock_freq = unsafe { enable_and_reset::(&conf).map_err(Error::ClockSetup)? }; + Self::init_hardware( + T::info().regs, + *config, + clock_freq, + enable_tx, + enable_rx, + enable_rts, + enable_cts, + )?; + + Ok(state) + } + + /// Helper for full-duplex initialization + fn new_inner( + inner: Peri<'a, T>, + tx_pin: Peri<'a, AnyPin>, + rx_pin: Peri<'a, AnyPin>, + rts_pin: Option>, + cts_pin: Option>, + tx_buffer: &'a mut [u8], + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result<(BufferedLpuartTx<'a>, BufferedLpuartRx<'a>)> { + let state = Self::init_common::( + &inner, + Some(tx_buffer), + Some(rx_buffer), + &config, + true, + true, + rts_pin.is_some(), + cts_pin.is_some(), + )?; + + let tx = BufferedLpuartTx { + info: T::info(), + state, + _tx_pin: tx_pin, + _cts_pin: cts_pin, + }; + + let rx = BufferedLpuartRx { + info: T::info(), + state, + _rx_pin: rx_pin, + _rts_pin: rts_pin, + }; + + Ok((tx, rx)) + } + + /// Common hardware initialization logic + fn init_hardware( + regs: &'static mcxa_pac::lpuart0::RegisterBlock, + config: Config, + clock_freq: u32, + enable_tx: bool, + enable_rx: bool, + enable_rts: bool, + enable_cts: bool, + ) -> Result<()> { // Perform standard initialization perform_software_reset(regs); disable_transceiver(regs); @@ -225,8 +187,8 @@ impl<'a> BufferedLpuart<'a> { configure_control_settings(regs, &config); configure_fifo(regs, &config); clear_all_status_flags(regs); - configure_flow_control(regs, &config); - configure_bit_order(regs, config.msb_firs); + configure_flow_control(regs, enable_rts, enable_cts, &config); + configure_bit_order(regs, config.msb_first); // Enable interrupts for buffered operation cortex_m::interrupt::free(|_| { @@ -245,17 +207,127 @@ impl<'a> BufferedLpuart<'a> { }); // Enable the transceiver - enable_transceiver(regs, config.enable_tx, config.enable_rx); - - // Enable the interrupt - // unsafe { - // // TODO: Used the propper interrupt enable method for the specific LPUART instance - // // T::Interrupt::enable(); - // } + enable_transceiver(regs, enable_rx, enable_tx); Ok(()) } + /// Create a new full duplex buffered LPUART + pub fn new( + inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + rx_pin: Peri<'a, impl RxPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_buffer: &'a mut [u8], + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + tx_pin.as_tx(); + rx_pin.as_rx(); + + let (tx, rx) = Self::new_inner::( + inner, + tx_pin.into(), + rx_pin.into(), + None, + None, + tx_buffer, + rx_buffer, + config, + )?; + + Ok(Self { tx, rx }) + } + + /// Create a new buffered LPUART instance with RTS/CTS flow control + pub fn new_with_rtscts( + inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + rx_pin: Peri<'a, impl RxPin>, + rts_pin: Peri<'a, impl RtsPin>, + cts_pin: Peri<'a, impl CtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_buffer: &'a mut [u8], + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + tx_pin.as_tx(); + rx_pin.as_rx(); + rts_pin.as_rts(); + cts_pin.as_cts(); + + let (tx, rx) = Self::new_inner::( + inner, + tx_pin.into(), + rx_pin.into(), + Some(rts_pin.into()), + Some(cts_pin.into()), + tx_buffer, + rx_buffer, + config, + )?; + + Ok(Self { tx, rx }) + } + + /// Create a new buffered LPUART with only RTS flow control (RX flow control) + pub fn new_with_rts( + inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + rx_pin: Peri<'a, impl RxPin>, + rts_pin: Peri<'a, impl RtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_buffer: &'a mut [u8], + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + tx_pin.as_tx(); + rx_pin.as_rx(); + rts_pin.as_rts(); + + let (tx, rx) = Self::new_inner::( + inner, + tx_pin.into(), + rx_pin.into(), + Some(rts_pin.into()), + None, + tx_buffer, + rx_buffer, + config, + )?; + + Ok(Self { tx, rx }) + } + + /// Create a new buffered LPUART with only CTS flow control (TX flow control) + pub fn new_with_cts( + inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + rx_pin: Peri<'a, impl RxPin>, + cts_pin: Peri<'a, impl CtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_buffer: &'a mut [u8], + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + tx_pin.as_tx(); + rx_pin.as_rx(); + cts_pin.as_cts(); + + let (tx, rx) = Self::new_inner::( + inner, + tx_pin.into(), + rx_pin.into(), + None, + Some(cts_pin.into()), + tx_buffer, + rx_buffer, + config, + )?; + + Ok(Self { tx, rx }) + } + /// Split the buffered LPUART into separate TX and RX parts pub fn split(self) -> (BufferedLpuartTx<'a>, BufferedLpuartRx<'a>) { (self.tx, self.rx) @@ -272,51 +344,62 @@ impl<'a> BufferedLpuart<'a> { // ============================================================================ impl<'a> BufferedLpuartTx<'a> { - /// Create a new TX-only buffered LPUART + /// Helper for TX-only initialization + fn new_inner( + inner: Peri<'a, T>, + tx_pin: Peri<'a, AnyPin>, + cts_pin: Option>, + tx_buffer: &'a mut [u8], + config: Config, + ) -> Result> { + let state = BufferedLpuart::init_common::( + &inner, + Some(tx_buffer), + None, + &config, + true, + false, + false, + cts_pin.is_some(), + )?; + + Ok(BufferedLpuartTx { + info: T::info(), + state, + _tx_pin: tx_pin, + _cts_pin: cts_pin, + }) + } + pub fn new( - _inner: Peri<'a, T>, + inner: Peri<'a, T>, tx_pin: Peri<'a, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'a, tx_buffer: &'a mut [u8], config: Config, ) -> Result { tx_pin.as_tx(); - let tx_pin: Peri<'a, AnyPin> = tx_pin.into(); - - let info = T::info(); - let state = T::buffered_state(); - - // Check if already initialized - if state.initialized.load(Ordering::Relaxed) { - return Err(Error::InvalidArgument); - } - // Initialize TX ring buffer only - unsafe { - let tx_buf = &state.tx_buf as *const _ as *mut RingBuffer; - (*tx_buf).init(tx_buffer.as_mut_ptr(), tx_buffer.len()); - } - - state.initialized.store(true, Ordering::Relaxed); + Self::new_inner::(inner, tx_pin.into(), None, tx_buffer, config) + } - // Initialize with TX only - BufferedLpuart::init::( - Some(&tx_pin), - None, - None, - None, - tx_buffer, - &mut [], // Empty RX buffer - config, - )?; + /// Create a new TX-only buffered LPUART with CTS flow control + pub fn new_with_cts( + inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + cts_pin: Peri<'a, impl CtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + tx_pin.as_tx(); + cts_pin.as_cts(); - Ok(Self { - info, - state, - _tx_pin: tx_pin, - }) + Self::new_inner::(inner, tx_pin.into(), Some(cts_pin.into()), tx_buffer, config) } +} +impl<'a> BufferedLpuartTx<'a> { /// Write data asynchronously pub async fn write(&mut self, buf: &[u8]) -> Result { let mut written = 0; @@ -401,51 +484,63 @@ impl<'a> BufferedLpuartTx<'a> { // ============================================================================ impl<'a> BufferedLpuartRx<'a> { + /// Helper for RX-only initialization + fn new_inner( + inner: Peri<'a, T>, + rx_pin: Peri<'a, AnyPin>, + rts_pin: Option>, + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result> { + let state = BufferedLpuart::init_common::( + &inner, + None, + Some(rx_buffer), + &config, + false, + true, + rts_pin.is_some(), + false, + )?; + + Ok(BufferedLpuartRx { + info: T::info(), + state, + _rx_pin: rx_pin, + _rts_pin: rts_pin, + }) + } + /// Create a new RX-only buffered LPUART pub fn new( - _inner: Peri<'a, T>, + inner: Peri<'a, T>, rx_pin: Peri<'a, impl RxPin>, _irq: impl interrupt::typelevel::Binding> + 'a, rx_buffer: &'a mut [u8], config: Config, ) -> Result { rx_pin.as_rx(); - let rx_pin: Peri<'a, AnyPin> = rx_pin.into(); - - let info = T::info(); - let state = T::buffered_state(); - - // Check if already initialized - if state.initialized.load(Ordering::Relaxed) { - return Err(Error::InvalidArgument); - } - // Initialize RX ring buffer only - unsafe { - let rx_buf = &state.rx_buf as *const _ as *mut RingBuffer; - (*rx_buf).init(rx_buffer.as_mut_ptr(), rx_buffer.len()); - } - - state.initialized.store(true, Ordering::Relaxed); + Self::new_inner::(inner, rx_pin.into(), None, rx_buffer, config) + } - // Initialize with RX only - BufferedLpuart::init::( - None, - Some(&rx_pin), - None, - None, - &mut [], // Empty TX buffer - rx_buffer, - config, - )?; + /// Create a new RX-only buffered LPUART with RTS flow control + pub fn new_with_rts( + inner: Peri<'a, T>, + rx_pin: Peri<'a, impl RxPin>, + rts_pin: Peri<'a, impl RtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + rx_buffer: &'a mut [u8], + config: Config, + ) -> Result { + rx_pin.as_rx(); + rts_pin.as_rts(); - Ok(Self { - info, - state, - _rx_pin: rx_pin, - }) + Self::new_inner::(inner, rx_pin.into(), Some(rts_pin.into()), rx_buffer, config) } +} +impl<'a> BufferedLpuartRx<'a> { /// Read data asynchronously pub async fn read(&mut self, buf: &mut [u8]) -> Result { if buf.is_empty() { diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs index 317274a79..2d8308ec8 100644 --- a/src/lpuart/mod.rs +++ b/src/lpuart/mod.rs @@ -203,8 +203,8 @@ pub fn clear_all_status_flags(regs: Regs) { } /// Configure hardware flow control if enabled -pub fn configure_flow_control(regs: Regs, config: &Config) { - if config.enable_rx_rts || config.enable_tx_cts { +pub fn configure_flow_control(regs: Regs, enable_tx_cts: bool, enable_rx_rts: bool, config: &Config) { + if enable_rx_rts || enable_tx_cts { regs.modir().modify(|_, w| { let mut w = w; @@ -212,13 +212,13 @@ pub fn configure_flow_control(regs: Regs, config: &Config) { w = w.txctsc().variant(config.tx_cts_config); w = w.txctssrc().variant(config.tx_cts_source); - if config.enable_rx_rts { + if enable_rx_rts { w = w.rxrtse().enabled(); } else { w = w.rxrtse().disabled(); } - if config.enable_tx_cts { + if enable_tx_cts { w = w.txctse().enabled(); } else { w = w.txctse().disabled(); @@ -586,17 +586,13 @@ pub struct Config { /// Number of data bits pub data_bits_count: DataBits, /// MSB First or LSB First configuration - pub msb_firs: MsbFirst, + pub msb_first: MsbFirst, /// Number of stop bits pub stop_bits_count: StopBits, /// TX FIFO watermark pub tx_fifo_watermark: u8, /// RX FIFO watermark pub rx_fifo_watermark: u8, - /// RX RTS enable - pub enable_rx_rts: bool, - /// TX CTS enable - pub enable_tx_cts: bool, /// TX CTS source pub tx_cts_source: TxCtsSource, /// TX CTS configure @@ -605,10 +601,6 @@ pub struct Config { pub rx_idle_type: IdleType, /// RX IDLE configuration pub rx_idle_config: IdleConfig, - /// Enable transmitter - pub enable_tx: bool, - /// Enable receiver - pub enable_rx: bool, /// Swap TXD and RXD pins pub swap_txd_rxd: bool, } @@ -619,18 +611,14 @@ impl Default for Config { baudrate_bps: 115_200u32, parity_mode: None, data_bits_count: DataBits::Data8, - msb_firs: MsbFirst::LsbFirst, + msb_first: MsbFirst::LsbFirst, stop_bits_count: StopBits::One, tx_fifo_watermark: 0, rx_fifo_watermark: 1, - enable_rx_rts: false, - enable_tx_cts: false, tx_cts_source: TxCtsSource::Cts, tx_cts_config: TxCtsConfig::Start, rx_idle_type: IdleType::FromStart, rx_idle_config: IdleConfig::Idle1, - enable_tx: false, - enable_rx: false, swap_txd_rxd: false, power: PoweredClock::NormalEnabledDeepSleepDisabled, source: LpuartClockSel::FroLfDiv, @@ -694,6 +682,7 @@ pub struct Lpuart<'a, M: Mode> { pub struct LpuartTx<'a, M: Mode> { info: Info, _tx_pin: Peri<'a, AnyPin>, + _cts_pin: Option>, _tx_dma: Option>, mode: PhantomData<(&'a (), M)>, } @@ -702,6 +691,7 @@ pub struct LpuartTx<'a, M: Mode> { pub struct LpuartRx<'a, M: Mode> { info: Info, _rx_pin: Peri<'a, AnyPin>, + _rts_pin: Option>, _rx_dma: Option>, mode: PhantomData<(&'a (), M)>, } @@ -712,10 +702,10 @@ pub struct LpuartRx<'a, M: Mode> { impl<'a, M: Mode> Lpuart<'a, M> { fn init( - _tx: Option<&Peri<'a, AnyPin>>, - _rx: Option<&Peri<'a, AnyPin>>, - _rts: Option<&Peri<'a, AnyPin>>, - _cts: Option<&Peri<'a, AnyPin>>, + enable_tx: bool, + enable_rx: bool, + enable_tx_cts: bool, + enable_rx_rts: bool, config: Config, ) -> Result<()> { let regs = T::info().regs; @@ -737,9 +727,9 @@ impl<'a, M: Mode> Lpuart<'a, M> { configure_control_settings(regs, &config); configure_fifo(regs, &config); clear_all_status_flags(regs); - configure_flow_control(regs, &config); - configure_bit_order(regs, config.msb_firs); - enable_transceiver(regs, config.enable_tx, config.enable_rx); + configure_flow_control(regs, enable_tx_cts, enable_rx_rts, &config); + configure_bit_order(regs, config.msb_first); + enable_transceiver(regs, enable_rx, enable_tx); Ok(()) } @@ -776,7 +766,7 @@ impl<'a, M: Mode> Lpuart<'a, M> { // ============================================================================ impl<'a> Lpuart<'a, Blocking> { - /// Create a new blocking LPUART instance with TX and RX pins. + /// Create a new blocking LPUART instance with RX/TX pins. pub fn new_blocking( _inner: Peri<'a, T>, tx_pin: Peri<'a, impl TxPin>, @@ -787,17 +777,38 @@ impl<'a> Lpuart<'a, Blocking> { tx_pin.as_tx(); rx_pin.as_rx(); - // Convert pins to AnyPin - let tx_pin: Peri<'a, AnyPin> = tx_pin.into(); - let rx_pin: Peri<'a, AnyPin> = rx_pin.into(); - // Initialize the peripheral - Self::init::(Some(&tx_pin), Some(&rx_pin), None, None, config)?; + Self::init::(true, true, false, false, config)?; Ok(Self { info: T::info(), - tx: LpuartTx::new_inner(T::info(), tx_pin, None), - rx: LpuartRx::new_inner(T::info(), rx_pin, None), + tx: LpuartTx::new_inner(T::info(), tx_pin.into(), None, None), + rx: LpuartRx::new_inner(T::info(), rx_pin.into(), None, None), + }) + } + + /// Create a new blocking LPUART instance with RX, TX and RTS/CTS flow control pins + pub fn new_blocking_with_rtscts( + _inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + rx_pin: Peri<'a, impl RxPin>, + cts_pin: Peri<'a, impl CtsPin>, + rts_pin: Peri<'a, impl RtsPin>, + config: Config, + ) -> Result { + // Configure the pins for LPUART usage + rx_pin.as_rx(); + tx_pin.as_tx(); + rts_pin.as_rts(); + cts_pin.as_cts(); + + // Initialize the peripheral with flow control + Self::init::(true, true, true, true, config)?; + + Ok(Self { + info: T::info(), + rx: LpuartRx::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None), + tx: LpuartTx::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None), }) } } @@ -807,10 +818,16 @@ impl<'a> Lpuart<'a, Blocking> { // ---------------------------------------------------------------------------- impl<'a, M: Mode> LpuartTx<'a, M> { - fn new_inner(info: Info, tx_pin: Peri<'a, AnyPin>, tx_dma: Option>) -> Self { + fn new_inner( + info: Info, + tx_pin: Peri<'a, AnyPin>, + cts_pin: Option>, + tx_dma: Option>, + ) -> Self { Self { info, _tx_pin: tx_pin, + _cts_pin: cts_pin, _tx_dma: tx_dma, mode: PhantomData, } @@ -818,19 +835,34 @@ impl<'a, M: Mode> LpuartTx<'a, M> { } impl<'a> LpuartTx<'a, Blocking> { - /// Create a new blocking LPUART which can only send data. + /// Create a new blocking LPUART transmitter instance pub fn new_blocking( _inner: Peri<'a, T>, tx_pin: Peri<'a, impl TxPin>, config: Config, ) -> Result { + // Configure the pins for LPUART usage tx_pin.as_tx(); - let tx_pin: Peri<'a, AnyPin> = tx_pin.into(); + // Initialize the peripheral + Lpuart::::init::(true, false, false, false, config)?; + + Ok(Self::new_inner(T::info(), tx_pin.into(), None, None)) + } + + /// Create a new blocking LPUART transmitter instance with CTS flow control + pub fn new_blocking_with_cts( + _inner: Peri<'a, T>, + tx_pin: Peri<'a, impl TxPin>, + cts_pin: Peri<'a, impl CtsPin>, + config: Config, + ) -> Result { + tx_pin.as_tx(); + cts_pin.as_cts(); - Lpuart::::init::(Some(&tx_pin), None, None, None, config)?; + Lpuart::::init::(true, false, true, false, config)?; - Ok(Self::new_inner(T::info(), tx_pin, None)) + Ok(Self::new_inner(T::info(), tx_pin.into(), Some(cts_pin.into()), None)) } fn write_byte_internal(&mut self, byte: u8) -> Result<()> { @@ -909,10 +941,16 @@ impl<'a> LpuartTx<'a, Blocking> { // ---------------------------------------------------------------------------- impl<'a, M: Mode> LpuartRx<'a, M> { - fn new_inner(info: Info, rx_pin: Peri<'a, AnyPin>, rx_dma: Option>) -> Self { + fn new_inner( + info: Info, + rx_pin: Peri<'a, AnyPin>, + rts_pin: Option>, + rx_dma: Option>, + ) -> Self { Self { info, _rx_pin: rx_pin, + _rts_pin: rts_pin, _rx_dma: rx_dma, mode: PhantomData, } @@ -920,7 +958,7 @@ impl<'a, M: Mode> LpuartRx<'a, M> { } impl<'a> LpuartRx<'a, Blocking> { - /// Create a new blocking LPUART which can only receive data. + /// Create a new blocking LPUART Receiver instance pub fn new_blocking( _inner: Peri<'a, T>, rx_pin: Peri<'a, impl RxPin>, @@ -928,11 +966,24 @@ impl<'a> LpuartRx<'a, Blocking> { ) -> Result { rx_pin.as_rx(); - let rx_pin: Peri<'a, AnyPin> = rx_pin.into(); + Lpuart::::init::(false, true, false, false, config)?; + + Ok(Self::new_inner(T::info(), rx_pin.into(), None, None)) + } + + /// Create a new blocking LPUART Receiver instance with RTS flow control + pub fn new_blocking_with_rts( + _inner: Peri<'a, T>, + rx_pin: Peri<'a, impl RxPin>, + rts_pin: Peri<'a, impl RtsPin>, + config: Config, + ) -> Result { + rx_pin.as_rx(); + rts_pin.as_rts(); - Lpuart::::init::(None, Some(&rx_pin), None, None, config)?; + Lpuart::::init::(false, true, false, true, config)?; - Ok(Self::new_inner(T::info(), rx_pin, None)) + Ok(Self::new_inner(T::info(), rx_pin.into(), Some(rts_pin.into()), None)) } fn read_byte_internal(&mut self) -> Result { @@ -994,8 +1045,8 @@ impl<'a> Lpuart<'a, Blocking> { self.tx.blocking_write(buf) } - pub fn write_byte(&mut self, byte: u8) { - _ = self.tx.write_byte(byte); + pub fn write_byte(&mut self, byte: u8) -> Result<()> { + self.tx.write_byte(byte) } pub fn read_byte_blocking(&mut self) -> u8 { -- cgit