diff --git a/rp2040-hal/src/uart/mod.rs b/rp2040-hal/src/uart/mod.rs index 780c1c8..d980e93 100644 --- a/rp2040-hal/src/uart/mod.rs +++ b/rp2040-hal/src/uart/mod.rs @@ -16,17 +16,20 @@ //! let mut watchdog = Watchdog::new(peripherals.WATCHDOG); //! let mut clocks = init_clocks_and_plls(XOSC_CRYSTAL_FREQ, peripherals.XOSC, peripherals.CLOCKS, peripherals.PLL_SYS, peripherals.PLL_USB, &mut peripherals.RESETS, &mut watchdog).ok().unwrap(); //! +//! // Set up UART on GP0 and GP1 (Pico pins 1 and 2) +//! let pins = ( +//! pins.gpio0.into_mode::(), +//! pins.gpio1.into_mode::(), +//! ); //! // Need to perform clock init before using UART or it will freeze. -//! let uart = UartPeripheral::<_, _>::enable( +//! let uart = UartPeripheral::enable( //! peripherals.UART0, +//! pins, //! &mut peripherals.RESETS, //! uart::common_configs::_9600_8_N_1, //! clocks.peripheral_clock.into(), //! ).unwrap(); //! -//! // Set up UART on GP0 and GP1 (Pico pins 1 and 2) -//! let _tx_pin = pins.gpio0.into_mode::(); -//! let _rx_pin = pins.gpio1.into_mode::(); //! uart.write_full_blocking(b"Hello World!\r\n"); //! ``` diff --git a/rp2040-hal/src/uart/peripheral.rs b/rp2040-hal/src/uart/peripheral.rs index 3136b08..2845cb7 100644 --- a/rp2040-hal/src/uart/peripheral.rs +++ b/rp2040-hal/src/uart/peripheral.rs @@ -53,40 +53,43 @@ impl eh1_0_alpha::serial::Error for ReadErrorType { } /// An UART Peripheral based on an underlying UART device. -pub struct UartPeripheral { +pub struct UartPeripheral> { device: D, _state: S, + pins: P, config: UartConfig, effective_baudrate: Baud, } -impl UartPeripheral { - fn transition(self, state: To) -> UartPeripheral { +impl> UartPeripheral { + fn transition(self, state: To) -> UartPeripheral { UartPeripheral { device: self.device, + pins: self.pins, config: self.config, effective_baudrate: self.effective_baudrate, _state: state, } } - /// Releases the underlying device. - pub fn free(self) -> D { - self.device + /// Releases the underlying device and pins. + pub fn free(self) -> (D, P) { + (self.device, self.pins) } } -impl UartPeripheral { +impl> UartPeripheral { /// Creates an UartPeripheral in Disabled state. - pub fn new(device: D, resets: &mut pac::RESETS) -> UartPeripheral { + pub fn new(device: D, pins: P, resets: &mut pac::RESETS) -> UartPeripheral { device.reset_bring_down(resets); device.reset_bring_up(resets); UartPeripheral { device, + _state: Disabled, + pins, config: common_configs::_9600_8_N_1, // placeholder effective_baudrate: Baud(0), - _state: Disabled, } } @@ -95,8 +98,8 @@ impl UartPeripheral { self, config: UartConfig, frequency: Hertz, - ) -> Result, Error> { - let mut device = self.free(); + ) -> Result, Error> { + let (mut device, pins) = self.free(); let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?; device.uartlcr_h.write(|w| { @@ -105,11 +108,14 @@ impl UartPeripheral { w }); - // Enable the UART, both TX and RX + // Enable the UART, and the TX,RC,CTS and RTS based on the pins device.uartcr.write(|w| { w.uarten().set_bit(); - w.txe().set_bit(); - w.rxe().set_bit(); + w.txe().bit(P::TX_ENABLED); + w.rxe().bit(P::RX_ENABLED); + w.ctsen().bit(P::CTS_ENABLED); + w.rtsen().bit(P::RTS_ENABLED); + w }); @@ -122,20 +128,23 @@ impl UartPeripheral { Ok(UartPeripheral { device, config, + pins, effective_baudrate, _state: Enabled, }) } } -impl UartPeripheral { +impl> UartPeripheral { /// Disable this UART Peripheral, falling back to the Disabled state. - pub fn disable(self) -> UartPeripheral { + pub fn disable(self) -> UartPeripheral { // Disable the UART, both TX and RX self.device.uartcr.write(|w| { w.uarten().clear_bit(); w.txe().clear_bit(); w.rxe().clear_bit(); + w.ctsen().clear_bit(); + w.rtsen().clear_bit(); w }); @@ -361,7 +370,7 @@ fn set_format<'w>( w } -impl Read for UartPeripheral { +impl> Read for UartPeripheral { type Error = ReadErrorType; fn read(&mut self) -> nb::Result { @@ -378,7 +387,7 @@ impl Read for UartPeripheral { } #[cfg(feature = "eh1_0_alpha")] -impl eh1::Read for UartPeripheral { +impl> eh1::Read for UartPeripheral { type Error = ReadErrorType; fn read(&mut self) -> nb::Result { @@ -417,7 +426,7 @@ impl eh1_0_alpha::serial::Error for SerialInfallible { } } -impl Write for UartPeripheral { +impl> Write for UartPeripheral { type Error = Infallible; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { @@ -434,7 +443,7 @@ impl Write for UartPeripheral { } #[cfg(feature = "eh1_0_alpha")] -impl eh1::Write for UartPeripheral { +impl> eh1::Write for UartPeripheral { type Error = SerialInfallible; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { @@ -453,7 +462,7 @@ impl eh1::Write for UartPeripheral { } } -impl fmt::Write for UartPeripheral { +impl> fmt::Write for UartPeripheral { fn write_str(&mut self, s: &str) -> fmt::Result { s.bytes() .try_for_each(|c| nb::block!(self.write(c))) diff --git a/rp2040-hal/src/uart/pins.rs b/rp2040-hal/src/uart/pins.rs index 2d49991..0cbfb03 100644 --- a/rp2040-hal/src/uart/pins.rs +++ b/rp2040-hal/src/uart/pins.rs @@ -2,7 +2,16 @@ use crate::gpio::{bank0, FunctionUart, Pin}; use crate::pac::{UART0, UART1}; /// Declares a valid UART pinout. -pub trait ValidUartPinout {} +pub trait ValidUartPinout { + /// Indicates TX should be enabled for this pinout + const TX_ENABLED: bool; + /// Indicates RX should be enabled for this pinout + const RX_ENABLED: bool; + /// Indicates CTS should be enabled for this pinout + const CTS_ENABLED: bool; + /// Indicates RTS should be enabled for this pinout + const RTS_ENABLED: bool; +} impl ValidUartPinout for Pins where @@ -11,6 +20,10 @@ where CTS: Cts, RTS: Rts, { + const TX_ENABLED: bool = TX::ENABLED; + const RX_ENABLED: bool = RX::ENABLED; + const CTS_ENABLED: bool = CTS::ENABLED; + const RTS_ENABLED: bool = RTS::ENABLED; } impl ValidUartPinout for (TX, RX) @@ -18,6 +31,10 @@ where TX: Tx, RX: Rx, { + const TX_ENABLED: bool = TX::ENABLED; + const RX_ENABLED: bool = RX::ENABLED; + const CTS_ENABLED: bool = false; + const RTS_ENABLED: bool = false; } impl ValidUartPinout for (TX, RX, CTS, RTS) @@ -27,6 +44,10 @@ where CTS: Cts, RTS: Rts, { + const TX_ENABLED: bool = TX::ENABLED; + const RX_ENABLED: bool = RX::ENABLED; + const CTS_ENABLED: bool = CTS::ENABLED; + const RTS_ENABLED: bool = RTS::ENABLED; } /// Customizable Uart pinout, allowing you to set the pins individually. @@ -41,6 +62,21 @@ where /// Every field can be set to `()` to not configure them. /// /// Note that you can also use tuples `(RX, TX)` or `(RX, TX, CTS, RTS)` instead of this type. +/// +/// This struct can either be filled manually or with a builder pattern: +/// +/// ```no_run +/// # use rp2040_hal::uart::{Pins, ValidUartPinout}; +/// # use rp2040_hal::pac::UART0; +/// # let gpio_pins: rp2040_hal::gpio::Pins = unsafe { core::mem::zeroed() }; +/// let pins = Pins::default() +/// .tx(gpio_pins.gpio0.into_mode()) +/// .rx(gpio_pins.gpio1.into_mode()); +/// +/// fn assert_is_valid_uart0>(_: T) {} +/// +/// assert_is_valid_uart0(pins); +/// ``` #[allow(missing_docs)] pub struct Pins { pub tx: TX, @@ -49,22 +85,8 @@ pub struct Pins { pub cts: CTS, } -impl Pins<(), (), (), ()> { - /// Create a new pinout. This can be used as a builder pattern - /// - /// ```no_run - /// # use rp2040_hal::uart::{Pins, ValidUartPinout}; - /// # use rp2040_hal::pac::UART0; - /// # let gpio_pins: rp2040_hal::gpio::Pins = unsafe { core::mem::zeroed() }; - /// let pins = Pins::new() - /// .tx(gpio_pins.gpio0.into_mode()) - /// .rx(gpio_pins.gpio1.into_mode()); - /// - /// fn assert_is_valid_uart0>(_: T) {} - /// - /// assert_is_valid_uart0(pins); - /// ``` - pub fn new() -> Self { +impl Default for Pins<(), (), (), ()> { + fn default() -> Self { Self { tx: (), rx: (), @@ -116,35 +138,35 @@ impl Pins { /// Indicates a valid TX pin for UART0 or UART1 pub trait Tx { #[allow(missing_docs)] - const IS_SET: bool; + const ENABLED: bool; } /// Indicates a valid RX pin for UART0 or UART1 pub trait Rx { #[allow(missing_docs)] - const IS_SET: bool; + const ENABLED: bool; } /// Indicates a valid CTS pin for UART0 or UART1 pub trait Cts { #[allow(missing_docs)] - const IS_SET: bool; + const ENABLED: bool; } /// Indicates a valid RTS pin for UART0 or UART1 pub trait Rts { #[allow(missing_docs)] - const IS_SET: bool; + const ENABLED: bool; } impl Tx for () { - const IS_SET: bool = false; + const ENABLED: bool = false; } impl Rx for () { - const IS_SET: bool = false; + const ENABLED: bool = false; } impl Cts for () { - const IS_SET: bool = false; + const ENABLED: bool = false; } impl Rts for () { - const IS_SET: bool = false; + const ENABLED: bool = false; } macro_rules! impl_valid_uart { @@ -157,22 +179,22 @@ macro_rules! impl_valid_uart { $( $( impl Tx<$uart> for Pin { - const IS_SET: bool = true; + const ENABLED: bool = true; } )* $( impl Rx<$uart> for Pin { - const IS_SET: bool = true; + const ENABLED: bool = true; } )* $( impl Cts<$uart> for Pin { - const IS_SET: bool = true; + const ENABLED: bool = true; } )* $( impl Rts<$uart> for Pin { - const IS_SET: bool = true; + const ENABLED: bool = true; } )* )*