mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
Split uart in separate files, introduced a typesystem constraint for valid UART pin configurations
This commit is contained in:
parent
3eb65168ff
commit
bdfb4d82c9
42
rp2040-hal/src/uart/common_configs.rs
Normal file
42
rp2040-hal/src/uart/common_configs.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use super::{DataBits, StopBits, UartConfig};
|
||||
use embedded_time::rate::Baud;
|
||||
|
||||
/// 9600 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _9600_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(9600),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 19200 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _19200_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(19200),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 38400 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _38400_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(38400),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 57600 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _57600_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(57600),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 115200 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _115200_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(115200),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
42
rp2040-hal/src/uart/mod.rs
Normal file
42
rp2040-hal/src/uart/mod.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
//! Universal Asynchronous Receiver Transmitter (UART)
|
||||
//!
|
||||
//! See [Chapter 4 Section 2](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) of the datasheet for more details
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! See [examples/uart.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples/uart.rs) for a more complete example
|
||||
//! ```no_run
|
||||
//! use rp2040_hal::{clocks::init_clocks_and_plls, gpio::{Pins, FunctionUart}, pac, sio::Sio, uart::{self, UartPeripheral}, watchdog::Watchdog};
|
||||
//!
|
||||
//! const XOSC_CRYSTAL_FREQ: u32 = 12_000_000; // Typically found in BSP crates
|
||||
//!
|
||||
//! let mut peripherals = pac::Peripherals::take().unwrap();
|
||||
//! let sio = Sio::new(peripherals.SIO);
|
||||
//! let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS);
|
||||
//! 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();
|
||||
//!
|
||||
//! // Need to perform clock init before using UART or it will freeze.
|
||||
//! let uart = UartPeripheral::<_, _>::enable(
|
||||
//! peripherals.UART0,
|
||||
//! &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");
|
||||
//! ```
|
||||
|
||||
mod peripheral;
|
||||
mod pins;
|
||||
mod utils;
|
||||
|
||||
pub use self::peripheral::UartPeripheral;
|
||||
pub use self::pins::*;
|
||||
pub use self::utils::*;
|
||||
|
||||
/// Common configurations for UART.
|
||||
pub mod common_configs;
|
|
@ -30,58 +30,16 @@
|
|||
//! uart.write_full_blocking(b"Hello World!\r\n");
|
||||
//! ```
|
||||
|
||||
use super::*;
|
||||
use crate::pac::uart0::uartlcr_h::W as UART_LCR_H_Writer;
|
||||
use core::convert::Infallible;
|
||||
use core::fmt;
|
||||
use core::ops::Deref;
|
||||
use embedded_hal::serial::{Read, Write};
|
||||
use embedded_time::fixed_point::FixedPoint;
|
||||
use embedded_time::rate::Baud;
|
||||
use embedded_time::rate::Hertz;
|
||||
|
||||
#[cfg(feature = "eh1_0_alpha")]
|
||||
use eh1_0_alpha::serial::nb as eh1;
|
||||
use embedded_hal::serial::{Read, Write};
|
||||
|
||||
use nb::Error::{Other, WouldBlock};
|
||||
|
||||
use crate::pac::{
|
||||
uart0::{uartlcr_h::W as UART_LCR_H_Writer, RegisterBlock},
|
||||
UART0, UART1,
|
||||
};
|
||||
|
||||
use crate::resets::SubsystemReset;
|
||||
|
||||
/// Error type for UART operations.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Bad argument : when things overflow, ...
|
||||
BadArgument,
|
||||
}
|
||||
|
||||
/// When there's a read error.
|
||||
pub struct ReadError<'err> {
|
||||
/// The type of error
|
||||
pub err_type: ReadErrorType,
|
||||
|
||||
/// Reference to the data that was read but eventually discared because of the error.
|
||||
pub discared: &'err [u8],
|
||||
}
|
||||
|
||||
/// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register"
|
||||
#[cfg_attr(feature = "eh1_0_alpha", derive(Debug))]
|
||||
pub enum ReadErrorType {
|
||||
/// Triggered when the FIFO (or shift-register) is overflowed.
|
||||
Overrun,
|
||||
|
||||
/// Triggered when a break is received
|
||||
Break,
|
||||
|
||||
/// Triggered when there is a parity mismatch between what's received and our settings.
|
||||
Parity,
|
||||
|
||||
/// Triggered when the received character didn't have a valid stop bit.
|
||||
Framing,
|
||||
}
|
||||
|
||||
#[cfg(feature = "eh1_0_alpha")]
|
||||
impl eh1_0_alpha::serial::Error for ReadErrorType {
|
||||
fn kind(&self) -> eh1_0_alpha::serial::ErrorKind {
|
||||
|
@ -94,113 +52,6 @@ impl eh1_0_alpha::serial::Error for ReadErrorType {
|
|||
}
|
||||
}
|
||||
|
||||
/// State of the UART Peripheral.
|
||||
pub trait State {}
|
||||
|
||||
/// Trait to handle both underlying devices (UART0 & UART1)
|
||||
pub trait UartDevice: Deref<Target = RegisterBlock> + SubsystemReset {}
|
||||
|
||||
impl UartDevice for UART0 {}
|
||||
impl UartDevice for UART1 {}
|
||||
|
||||
/// UART is enabled.
|
||||
pub struct Enabled;
|
||||
|
||||
/// UART is disabled.
|
||||
pub struct Disabled;
|
||||
|
||||
impl State for Enabled {}
|
||||
impl State for Disabled {}
|
||||
|
||||
/// Data bits
|
||||
pub enum DataBits {
|
||||
/// 5 bits
|
||||
Five,
|
||||
/// 6 bits
|
||||
Six,
|
||||
/// 7 bits
|
||||
Seven,
|
||||
/// 8 bits
|
||||
Eight,
|
||||
}
|
||||
|
||||
/// Stop bits
|
||||
pub enum StopBits {
|
||||
/// 1 bit
|
||||
One,
|
||||
|
||||
/// 2 bits
|
||||
Two,
|
||||
}
|
||||
|
||||
/// Parity
|
||||
/// The "none" state of parity is represented with the Option type (None).
|
||||
pub enum Parity {
|
||||
/// Odd parity
|
||||
Odd,
|
||||
|
||||
/// Even parity
|
||||
Even,
|
||||
}
|
||||
|
||||
/// A struct holding the configuration for an UART device.
|
||||
pub struct UartConfig {
|
||||
/// The desired baud rate for the peripheral
|
||||
pub baudrate: Baud,
|
||||
/// Number of data bits per character (5, 6, 7 or 8)
|
||||
pub data_bits: DataBits,
|
||||
/// Number of stop bits after each character
|
||||
pub stop_bits: StopBits,
|
||||
/// Parity Bit: None, Some(Even), Some(Odd)
|
||||
pub parity: Option<Parity>,
|
||||
}
|
||||
|
||||
/// Common configurations for UART.
|
||||
pub mod common_configs {
|
||||
use super::{DataBits, StopBits, UartConfig};
|
||||
use embedded_time::rate::Baud;
|
||||
|
||||
/// 9600 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _9600_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(9600),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 19200 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _19200_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(19200),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 38400 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _38400_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(38400),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 57600 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _57600_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(57600),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
|
||||
/// 115200 baud, 8 data bits, no parity, 1 stop bit
|
||||
pub const _115200_8_N_1: UartConfig = UartConfig {
|
||||
baudrate: Baud(115200),
|
||||
data_bits: DataBits::Eight,
|
||||
stop_bits: StopBits::One,
|
||||
parity: None,
|
||||
};
|
||||
}
|
||||
|
||||
/// An UART Peripheral based on an underlying UART device.
|
||||
pub struct UartPeripheral<S: State, D: UartDevice> {
|
||||
device: D,
|
195
rp2040-hal/src/uart/pins.rs
Normal file
195
rp2040-hal/src/uart/pins.rs
Normal file
|
@ -0,0 +1,195 @@
|
|||
use crate::gpio::{bank0, FunctionUart, Pin};
|
||||
use crate::pac::{UART0, UART1};
|
||||
|
||||
/// Declares a valid UART pinout.
|
||||
pub trait ValidUartPinout<UART> {}
|
||||
|
||||
impl<UART, TX, RX, CTS, RTS> ValidUartPinout<UART> for Pins<TX, RX, CTS, RTS>
|
||||
where
|
||||
TX: Tx<UART>,
|
||||
RX: Rx<UART>,
|
||||
CTS: Cts<UART>,
|
||||
RTS: Rts<UART>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<UART, TX, RX> ValidUartPinout<UART> for (TX, RX)
|
||||
where
|
||||
TX: Tx<UART>,
|
||||
RX: Rx<UART>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<UART, TX, RX, CTS, RTS> ValidUartPinout<UART> for (TX, RX, CTS, RTS)
|
||||
where
|
||||
TX: Tx<UART>,
|
||||
RX: Rx<UART>,
|
||||
CTS: Cts<UART>,
|
||||
RTS: Rts<UART>,
|
||||
{
|
||||
}
|
||||
|
||||
/// Customizable Uart pinout, allowing you to set the pins individually.
|
||||
///
|
||||
/// The following pins are valid UART pins:
|
||||
///
|
||||
/// |UART | TX | RX | CTS | RTS |
|
||||
/// |-----|-------------|-------------|-------------|-------------|
|
||||
/// |UART0|0, 12, 16, 28|1, 13, 17, 29|2, 14, 18 |3, 15, 19 |
|
||||
/// |UART1|4, 8, 20, 24 |5, 9, 21, 25 |6, 10, 22, 26|7, 11, 23, 27|
|
||||
///
|
||||
/// 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.
|
||||
#[allow(missing_docs)]
|
||||
pub struct Pins<TX, RX, CTS, RTS> {
|
||||
pub tx: TX,
|
||||
pub rx: RX,
|
||||
pub rts: 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 {
|
||||
Self {
|
||||
tx: (),
|
||||
rx: (),
|
||||
rts: (),
|
||||
cts: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TX, RX, CTS, RTS> Pins<TX, RX, CTS, RTS> {
|
||||
/// Set the TX pin
|
||||
pub fn tx<NTX>(self, tx: NTX) -> Pins<NTX, RX, CTS, RTS> {
|
||||
Pins {
|
||||
tx,
|
||||
rx: self.rx,
|
||||
rts: self.rts,
|
||||
cts: self.cts,
|
||||
}
|
||||
}
|
||||
/// Set the RX pin
|
||||
pub fn rx<NRX>(self, rx: NRX) -> Pins<TX, NRX, CTS, RTS> {
|
||||
Pins {
|
||||
tx: self.tx,
|
||||
rx,
|
||||
rts: self.rts,
|
||||
cts: self.cts,
|
||||
}
|
||||
}
|
||||
/// Set the CTS pin
|
||||
pub fn cts<NCTS>(self, cts: NCTS) -> Pins<TX, RX, NCTS, RTS> {
|
||||
Pins {
|
||||
tx: self.tx,
|
||||
rx: self.rx,
|
||||
rts: self.rts,
|
||||
cts,
|
||||
}
|
||||
}
|
||||
/// Set the RTS pin
|
||||
pub fn rts<NRTS>(self, rts: NRTS) -> Pins<TX, RX, CTS, NRTS> {
|
||||
Pins {
|
||||
tx: self.tx,
|
||||
rx: self.rx,
|
||||
rts,
|
||||
cts: self.cts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates a valid TX pin for UART0 or UART1
|
||||
pub trait Tx<UART> {
|
||||
#[allow(missing_docs)]
|
||||
const IS_SET: bool;
|
||||
}
|
||||
/// Indicates a valid RX pin for UART0 or UART1
|
||||
pub trait Rx<UART> {
|
||||
#[allow(missing_docs)]
|
||||
const IS_SET: bool;
|
||||
}
|
||||
/// Indicates a valid CTS pin for UART0 or UART1
|
||||
pub trait Cts<UART> {
|
||||
#[allow(missing_docs)]
|
||||
const IS_SET: bool;
|
||||
}
|
||||
/// Indicates a valid RTS pin for UART0 or UART1
|
||||
pub trait Rts<UART> {
|
||||
#[allow(missing_docs)]
|
||||
const IS_SET: bool;
|
||||
}
|
||||
|
||||
impl<UART> Tx<UART> for () {
|
||||
const IS_SET: bool = false;
|
||||
}
|
||||
impl<UART> Rx<UART> for () {
|
||||
const IS_SET: bool = false;
|
||||
}
|
||||
impl<UART> Cts<UART> for () {
|
||||
const IS_SET: bool = false;
|
||||
}
|
||||
impl<UART> Rts<UART> for () {
|
||||
const IS_SET: bool = false;
|
||||
}
|
||||
|
||||
macro_rules! impl_valid_uart {
|
||||
($($uart:ident: {
|
||||
tx: [$($tx:ident),*],
|
||||
rx: [$($rx:ident),*],
|
||||
cts: [$($cts:ident),*],
|
||||
rts: [$($rts:ident),*],
|
||||
}),*) => {
|
||||
$(
|
||||
$(
|
||||
impl Tx<$uart> for Pin<bank0::$tx, FunctionUart> {
|
||||
const IS_SET: bool = true;
|
||||
}
|
||||
)*
|
||||
$(
|
||||
impl Rx<$uart> for Pin<bank0::$rx, FunctionUart> {
|
||||
const IS_SET: bool = true;
|
||||
}
|
||||
)*
|
||||
$(
|
||||
impl Cts<$uart> for Pin<bank0::$cts, FunctionUart> {
|
||||
const IS_SET: bool = true;
|
||||
}
|
||||
)*
|
||||
$(
|
||||
impl Rts<$uart> for Pin<bank0::$rts, FunctionUart> {
|
||||
const IS_SET: bool = true;
|
||||
}
|
||||
)*
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_valid_uart!(
|
||||
UART0: {
|
||||
tx: [Gpio0, Gpio12, Gpio16, Gpio28],
|
||||
rx: [Gpio1, Gpio13, Gpio17, Gpio29],
|
||||
cts: [Gpio2, Gpio14, Gpio18],
|
||||
rts: [Gpio3, Gpio15, Gpio19],
|
||||
},
|
||||
UART1: {
|
||||
tx: [Gpio4, Gpio8, Gpio20, Gpio24],
|
||||
rx: [Gpio5, Gpio9, Gpio21, Gpio25],
|
||||
cts: [Gpio6, Gpio10, Gpio22, Gpio26],
|
||||
rts: [Gpio7, Gpio11, Gpio23, Gpio27],
|
||||
}
|
||||
);
|
101
rp2040-hal/src/uart/utils.rs
Normal file
101
rp2040-hal/src/uart/utils.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use crate::pac::{uart0::RegisterBlock, UART0, UART1};
|
||||
use crate::resets::SubsystemReset;
|
||||
use core::ops::Deref;
|
||||
use embedded_time::rate::Baud;
|
||||
|
||||
/// Error type for UART operations.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Bad argument : when things overflow, ...
|
||||
BadArgument,
|
||||
}
|
||||
|
||||
/// When there's a read error.
|
||||
pub struct ReadError<'err> {
|
||||
/// The type of error
|
||||
pub err_type: ReadErrorType,
|
||||
|
||||
/// Reference to the data that was read but eventually discared because of the error.
|
||||
pub discared: &'err [u8],
|
||||
}
|
||||
|
||||
/// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register"
|
||||
#[cfg_attr(feature = "eh1_0_alpha", derive(Debug))]
|
||||
pub enum ReadErrorType {
|
||||
/// Triggered when the FIFO (or shift-register) is overflowed.
|
||||
Overrun,
|
||||
|
||||
/// Triggered when a break is received
|
||||
Break,
|
||||
|
||||
/// Triggered when there is a parity mismatch between what's received and our settings.
|
||||
Parity,
|
||||
|
||||
/// Triggered when the received character didn't have a valid stop bit.
|
||||
Framing,
|
||||
}
|
||||
|
||||
/// State of the UART Peripheral.
|
||||
pub trait State {}
|
||||
|
||||
/// Trait to handle both underlying devices (UART0 & UART1)
|
||||
pub trait UartDevice: Deref<Target = RegisterBlock> + SubsystemReset {}
|
||||
|
||||
impl UartDevice for UART0 {}
|
||||
impl UartDevice for UART1 {}
|
||||
|
||||
/// UART is enabled.
|
||||
pub struct Enabled;
|
||||
|
||||
/// UART is disabled.
|
||||
pub struct Disabled;
|
||||
|
||||
impl State for Enabled {}
|
||||
impl State for Disabled {}
|
||||
|
||||
/// Data bits
|
||||
pub enum DataBits {
|
||||
/// 5 bits
|
||||
Five,
|
||||
/// 6 bits
|
||||
Six,
|
||||
/// 7 bits
|
||||
Seven,
|
||||
/// 8 bits
|
||||
Eight,
|
||||
}
|
||||
|
||||
/// Stop bits
|
||||
pub enum StopBits {
|
||||
/// 1 bit
|
||||
One,
|
||||
|
||||
/// 2 bits
|
||||
Two,
|
||||
}
|
||||
|
||||
/// Parity
|
||||
/// The "none" state of parity is represented with the Option type (None).
|
||||
pub enum Parity {
|
||||
/// Odd parity
|
||||
Odd,
|
||||
|
||||
/// Even parity
|
||||
Even,
|
||||
}
|
||||
|
||||
/// A struct holding the configuration for an UART device.
|
||||
#[non_exhaustive]
|
||||
pub struct UartConfig {
|
||||
/// The baudrate the uart will run at.
|
||||
pub baudrate: Baud,
|
||||
|
||||
/// The amount of data bits the uart should be configured to.
|
||||
pub data_bits: DataBits,
|
||||
|
||||
/// The amount of stop bits the uart should be configured to.
|
||||
pub stop_bits: StopBits,
|
||||
|
||||
/// The parity that this uart should have
|
||||
pub parity: Option<Parity>,
|
||||
}
|
Loading…
Reference in a new issue