Added pins to the uart constructor functions

This commit is contained in:
Victor Koenders 2021-11-25 13:55:14 +01:00
parent bdfb4d82c9
commit a4a0bcf987
No known key found for this signature in database
GPG key ID: 2E441540865B8A1C
3 changed files with 88 additions and 54 deletions

View file

@ -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::<FunctionUart>(),
//! pins.gpio1.into_mode::<FunctionUart>(),
//! );
//! // 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::<FunctionUart>();
//! let _rx_pin = pins.gpio1.into_mode::<FunctionUart>();
//! uart.write_full_blocking(b"Hello World!\r\n");
//! ```

View file

@ -53,40 +53,43 @@ impl eh1_0_alpha::serial::Error for ReadErrorType {
}
/// An UART Peripheral based on an underlying UART device.
pub struct UartPeripheral<S: State, D: UartDevice> {
pub struct UartPeripheral<S: State, D: UartDevice, P: ValidUartPinout<D>> {
device: D,
_state: S,
pins: P,
config: UartConfig,
effective_baudrate: Baud,
}
impl<S: State, D: UartDevice> UartPeripheral<S, D> {
fn transition<To: State>(self, state: To) -> UartPeripheral<To, D> {
impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
fn transition<To: State>(self, state: To) -> UartPeripheral<To, D, P> {
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<D: UartDevice> UartPeripheral<Disabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Disabled, D, P> {
/// Creates an UartPeripheral in Disabled state.
pub fn new(device: D, resets: &mut pac::RESETS) -> UartPeripheral<Disabled, D> {
pub fn new(device: D, pins: P, resets: &mut pac::RESETS) -> UartPeripheral<Disabled, D, P> {
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<D: UartDevice> UartPeripheral<Disabled, D> {
self,
config: UartConfig,
frequency: Hertz,
) -> Result<UartPeripheral<Enabled, D>, Error> {
let mut device = self.free();
) -> Result<UartPeripheral<Enabled, D, P>, 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<D: UartDevice> UartPeripheral<Disabled, D> {
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<D: UartDevice> UartPeripheral<Disabled, D> {
Ok(UartPeripheral {
device,
config,
pins,
effective_baudrate,
_state: Enabled,
})
}
}
impl<D: UartDevice> UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<Enabled, D, P> {
/// Disable this UART Peripheral, falling back to the Disabled state.
pub fn disable(self) -> UartPeripheral<Disabled, D> {
pub fn disable(self) -> UartPeripheral<Disabled, D, P> {
// 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<D: UartDevice> Read<u8> for UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> Read<u8> for UartPeripheral<Enabled, D, P> {
type Error = ReadErrorType;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
@ -378,7 +387,7 @@ impl<D: UartDevice> Read<u8> for UartPeripheral<Enabled, D> {
}
#[cfg(feature = "eh1_0_alpha")]
impl<D: UartDevice> eh1::Read<u8> for UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> eh1::Read<u8> for UartPeripheral<Enabled, D, P> {
type Error = ReadErrorType;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
@ -417,7 +426,7 @@ impl eh1_0_alpha::serial::Error for SerialInfallible {
}
}
impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for UartPeripheral<Enabled, D, P> {
type Error = Infallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
@ -434,7 +443,7 @@ impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
}
#[cfg(feature = "eh1_0_alpha")]
impl<D: UartDevice> eh1::Write<u8> for UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> eh1::Write<u8> for UartPeripheral<Enabled, D, P> {
type Error = SerialInfallible;
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
@ -453,7 +462,7 @@ impl<D: UartDevice> eh1::Write<u8> for UartPeripheral<Enabled, D> {
}
}
impl<D: UartDevice> fmt::Write for UartPeripheral<Enabled, D> {
impl<D: UartDevice, P: ValidUartPinout<D>> fmt::Write for UartPeripheral<Enabled, D, P> {
fn write_str(&mut self, s: &str) -> fmt::Result {
s.bytes()
.try_for_each(|c| nb::block!(self.write(c)))

View file

@ -2,7 +2,16 @@ use crate::gpio::{bank0, FunctionUart, Pin};
use crate::pac::{UART0, UART1};
/// Declares a valid UART pinout.
pub trait ValidUartPinout<UART> {}
pub trait ValidUartPinout<UART> {
/// 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<UART, TX, RX, CTS, RTS> ValidUartPinout<UART> for Pins<TX, RX, CTS, RTS>
where
@ -11,6 +20,10 @@ where
CTS: Cts<UART>,
RTS: Rts<UART>,
{
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<UART, TX, RX> ValidUartPinout<UART> for (TX, RX)
@ -18,6 +31,10 @@ where
TX: Tx<UART>,
RX: Rx<UART>,
{
const TX_ENABLED: bool = TX::ENABLED;
const RX_ENABLED: bool = RX::ENABLED;
const CTS_ENABLED: bool = false;
const RTS_ENABLED: bool = false;
}
impl<UART, TX, RX, CTS, RTS> ValidUartPinout<UART> for (TX, RX, CTS, RTS)
@ -27,6 +44,10 @@ where
CTS: Cts<UART>,
RTS: Rts<UART>,
{
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: ValidUartPinout<UART0>>(_: T) {}
///
/// assert_is_valid_uart0(pins);
/// ```
#[allow(missing_docs)]
pub struct Pins<TX, RX, CTS, RTS> {
pub tx: TX,
@ -49,22 +85,8 @@ pub struct Pins<TX, RX, CTS, RTS> {
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: ValidUartPinout<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<TX, RX, CTS, RTS> Pins<TX, RX, CTS, RTS> {
/// Indicates a valid TX pin for UART0 or UART1
pub trait Tx<UART> {
#[allow(missing_docs)]
const IS_SET: bool;
const ENABLED: bool;
}
/// Indicates a valid RX pin for UART0 or UART1
pub trait Rx<UART> {
#[allow(missing_docs)]
const IS_SET: bool;
const ENABLED: bool;
}
/// Indicates a valid CTS pin for UART0 or UART1
pub trait Cts<UART> {
#[allow(missing_docs)]
const IS_SET: bool;
const ENABLED: bool;
}
/// Indicates a valid RTS pin for UART0 or UART1
pub trait Rts<UART> {
#[allow(missing_docs)]
const IS_SET: bool;
const ENABLED: bool;
}
impl<UART> Tx<UART> for () {
const IS_SET: bool = false;
const ENABLED: bool = false;
}
impl<UART> Rx<UART> for () {
const IS_SET: bool = false;
const ENABLED: bool = false;
}
impl<UART> Cts<UART> for () {
const IS_SET: bool = false;
const ENABLED: bool = false;
}
impl<UART> Rts<UART> 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<bank0::$tx, FunctionUart> {
const IS_SET: bool = true;
const ENABLED: bool = true;
}
)*
$(
impl Rx<$uart> for Pin<bank0::$rx, FunctionUart> {
const IS_SET: bool = true;
const ENABLED: bool = true;
}
)*
$(
impl Cts<$uart> for Pin<bank0::$cts, FunctionUart> {
const IS_SET: bool = true;
const ENABLED: bool = true;
}
)*
$(
impl Rts<$uart> for Pin<bank0::$rts, FunctionUart> {
const IS_SET: bool = true;
const ENABLED: bool = true;
}
)*
)*