From b29cc2630c18387ee78535a61f4c96c3740dc82c Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 12 Sep 2022 17:06:27 +0200 Subject: [PATCH] Added set_fifos/set_rx_watermark/set_tx_watermark that permit to enable/disable the Rx/Tx FIFOs and to set the watermarks for the DMA/interrupts triggering --- rp2040-hal/src/uart/peripheral.rs | 25 +++++++++++++++++++++- rp2040-hal/src/uart/reader.rs | 35 ++++++++++++++++++++++++------- rp2040-hal/src/uart/utils.rs | 24 +++++++++++++++++++-- rp2040-hal/src/uart/writer.rs | 16 +++++++++++++- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/rp2040-hal/src/uart/peripheral.rs b/rp2040-hal/src/uart/peripheral.rs index 4a41768..7bdd0d2 100644 --- a/rp2040-hal/src/uart/peripheral.rs +++ b/rp2040-hal/src/uart/peripheral.rs @@ -62,7 +62,7 @@ impl> UartPeripheral { device.uartlcr_h.write(|w| { // FIFOs are enabled - w.fen().set_bit(); + w.fen().set_bit(); // Leaved here for backward compatibility set_format(w, &config.data_bits, &config.stop_bits, &config.parity); w }); @@ -108,6 +108,29 @@ impl> UartPeripheral { self.transition(Disabled) } + /// Enable/disable the rx/tx FIFO + /// + /// Unfortunately, it's not possible to enable/disable rx/tx + /// independently on this chip + /// Default is false + pub fn set_fifos(&mut self, enable: bool) { + super::reader::set_fifos(&self.device, enable) + } + + /// Set rx FIFO watermark + /// + /// See DS: Table 423 + pub fn set_rx_watermark(&mut self, watermark: FifoWatermark) { + super::reader::set_rx_watermark(&self.device, watermark) + } + + /// Set tx FIFO watermark + /// + /// See DS: Table 423 + pub fn set_tx_watermark(&mut self, watermark: FifoWatermark) { + super::writer::set_tx_watermark(&self.device, watermark) + } + /// Enables the Receive Interrupt. /// /// The relevant UARTx IRQ will fire when there is data in the receive register. diff --git a/rp2040-hal/src/uart/reader.rs b/rp2040-hal/src/uart/reader.rs index e8ab935..272d5b2 100644 --- a/rp2040-hal/src/uart/reader.rs +++ b/rp2040-hal/src/uart/reader.rs @@ -2,7 +2,7 @@ //! //! This module is for receiving data with a UART. -use super::{UartDevice, ValidUartPinout}; +use super::{FifoWatermark, UartDevice, ValidUartPinout}; use rp2040_pac::uart0::RegisterBlock; use embedded_hal::serial::Read; @@ -52,16 +52,37 @@ pub(crate) fn is_readable(device: &D) -> bool { device.uartfr.read().rxfe().bit_is_clear() } +/// Enable/disable the rx/tx FIFO +/// +/// Unfortunately, it's not possible to enable/disable rx/tx +/// independently on this chip +/// Default is false +pub fn set_fifos(rb: &RegisterBlock, enable: bool) { + if enable { + rb.uartlcr_h.modify(|_r, w| w.fen().set_bit()) + } else { + rb.uartlcr_h.modify(|_r, w| w.fen().clear_bit()) + } +} + +/// Set rx FIFO watermark +/// +/// See DS: Table 423 +pub fn set_rx_watermark(rb: &RegisterBlock, watermark: FifoWatermark) { + let wm = match watermark { + FifoWatermark::Bytes4 => 0, + FifoWatermark::Bytes8 => 1, + FifoWatermark::Bytes16 => 2, + FifoWatermark::Bytes24 => 3, + FifoWatermark::Bytes28 => 4, + }; + rb.uartifls.modify(|_r, w| unsafe { w.rxiflsel().bits(wm) }); +} + /// Enables the Receive Interrupt. /// /// The relevant UARTx IRQ will fire when there is data in the receive register. pub(crate) fn enable_rx_interrupt(rb: &RegisterBlock) { - // Access the UART FIFO Level Select. We set the RX FIFO trip level - // to be half-full. - - // 2 means '>= 1/2 full'. - rb.uartifls.modify(|_r, w| unsafe { w.rxiflsel().bits(2) }); - // Access the UART Interrupt Mask Set/Clear register. Setting a bit // high enables the interrupt. diff --git a/rp2040-hal/src/uart/utils.rs b/rp2040-hal/src/uart/utils.rs index 367683c..42eb9e6 100644 --- a/rp2040-hal/src/uart/utils.rs +++ b/rp2040-hal/src/uart/utils.rs @@ -44,7 +44,6 @@ pub enum DataBits { pub enum StopBits { /// 1 bit One, - /// 2 bits Two, } @@ -54,7 +53,6 @@ pub enum StopBits { pub enum Parity { /// Odd parity Odd, - /// Even parity Even, } @@ -86,6 +84,28 @@ pub struct UartConfig { pub parity: Option, } +/// Rx/Tx FIFO Watermark +/// +/// Determine the FIFO level that trigger DMA/Interrupt +/// Default is Bytes16, see DS Table 423 and UARTIFLS Register +/// Example of use: +/// uart0.set_fifos(true); // Default is false +/// uart0.set_rx_watermark(hal::uart::FifoWatermark::Bytes8); +/// uart0.enable_rx_interrupt(); +/// +pub enum FifoWatermark { + /// Trigger when 4 bytes are (Rx: filled / Tx: available) + Bytes4, + /// Trigger when 8 bytes are (Rx: filled / Tx: available) + Bytes8, + /// Trigger when 16 bytes are (Rx: filled / Tx: available) + Bytes16, + /// Trigger when 24 bytes are (Rx: filled / Tx: available) + Bytes24, + /// Trigger when 28 bytes are (Rx: filled / Tx: available) + Bytes28, +} + impl Default for UartConfig { fn default() -> Self { Self { diff --git a/rp2040-hal/src/uart/writer.rs b/rp2040-hal/src/uart/writer.rs index c67a5b6..34a50cf 100644 --- a/rp2040-hal/src/uart/writer.rs +++ b/rp2040-hal/src/uart/writer.rs @@ -2,7 +2,7 @@ //! //! This module is for transmitting data with a UART. -use super::{UartDevice, ValidUartPinout}; +use super::{FifoWatermark, UartDevice, ValidUartPinout}; use core::fmt; use core::{convert::Infallible, marker::PhantomData}; use embedded_hal::serial::Write; @@ -12,6 +12,20 @@ use rp2040_pac::uart0::RegisterBlock; #[cfg(feature = "eh1_0_alpha")] use eh1_0_alpha::serial as eh1; +/// Set tx FIFO watermark +/// +/// See DS: Table 423 +pub fn set_tx_watermark(rb: &RegisterBlock, watermark: FifoWatermark) { + let wm = match watermark { + FifoWatermark::Bytes4 => 4, + FifoWatermark::Bytes8 => 3, + FifoWatermark::Bytes16 => 2, + FifoWatermark::Bytes24 => 1, + FifoWatermark::Bytes28 => 0, + }; + rb.uartifls.modify(|_r, w| unsafe { w.txiflsel().bits(wm) }); +} + /// Returns `Err(WouldBlock)` if the UART TX FIFO still has data in it or /// `Ok(())` if the FIFO is empty. pub(crate) fn transmit_flushed(rb: &RegisterBlock) -> nb::Result<(), Infallible> {