mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
Merge pull request #210 from VictorKoenders/uart-owning-pins
UART owned pins + reader/writer split
This commit is contained in:
commit
cc53c1777f
|
@ -88,18 +88,20 @@ fn main() -> ! {
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut uart = hal::uart::UartPeripheral::<_, _>::new(pac.UART0, &mut pac.RESETS)
|
let uart_pins = (
|
||||||
|
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
||||||
|
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
||||||
|
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
|
||||||
.enable(
|
.enable(
|
||||||
hal::uart::common_configs::_115200_8_N_1,
|
hal::uart::common_configs::_115200_8_N_1,
|
||||||
clocks.peripheral_clock.into(),
|
clocks.peripheral_clock.into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
|
||||||
let _tx_pin = pins.gpio0.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
|
||||||
let _rx_pin = pins.gpio1.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
|
|
||||||
let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
|
let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
|
||||||
|
|
||||||
let mut i2c_pio = i2c_pio::I2C::new(
|
let mut i2c_pio = i2c_pio::I2C::new(
|
||||||
|
|
|
@ -84,18 +84,20 @@ fn main() -> ! {
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// UART TX (characters sent from pico) on pin 1 (GPIO0) and RX (on pin 2 (GPIO1)
|
||||||
|
let uart_pins = (
|
||||||
|
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create a UART driver
|
// Create a UART driver
|
||||||
let mut uart = hal::uart::UartPeripheral::<_, _>::new(pac.UART0, &mut pac.RESETS)
|
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
|
||||||
.enable(
|
.enable(
|
||||||
hal::uart::common_configs::_9600_8_N_1,
|
hal::uart::common_configs::_9600_8_N_1,
|
||||||
clocks.peripheral_clock.into(),
|
clocks.peripheral_clock.into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// UART TX (characters sent from pico) on pin 1 (GPIO0) and RX (on pin 2 (GPIO1)
|
|
||||||
let _tx_pin = pins.gpio0.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
let _rx_pin = pins.gpio1.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
|
|
||||||
// Write to the UART
|
// Write to the UART
|
||||||
uart.write_full_blocking(b"ADC example\r\n");
|
uart.write_full_blocking(b"ADC example\r\n");
|
||||||
|
|
||||||
|
|
|
@ -80,18 +80,19 @@ fn main() -> ! {
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut uart = hal::uart::UartPeripheral::<_, _>::new(pac.UART0, &mut pac.RESETS)
|
let uart_pins = (
|
||||||
|
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
||||||
|
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
||||||
|
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
);
|
||||||
|
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
|
||||||
.enable(
|
.enable(
|
||||||
hal::uart::common_configs::_9600_8_N_1,
|
hal::uart::common_configs::_9600_8_N_1,
|
||||||
clocks.peripheral_clock.into(),
|
clocks.peripheral_clock.into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
|
||||||
let _tx_pin = pins.gpio0.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
|
||||||
let _rx_pin = pins.gpio1.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
|
|
||||||
writeln!(uart, "ROM Copyright: {}", hal::rom_data::copyright_string()).unwrap();
|
writeln!(uart, "ROM Copyright: {}", hal::rom_data::copyright_string()).unwrap();
|
||||||
writeln!(
|
writeln!(
|
||||||
uart,
|
uart,
|
||||||
|
|
|
@ -82,18 +82,19 @@ fn main() -> ! {
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut uart = hal::uart::UartPeripheral::<_, _>::new(pac.UART0, &mut pac.RESETS)
|
let uart_pins = (
|
||||||
|
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
||||||
|
pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
||||||
|
pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
|
||||||
|
);
|
||||||
|
let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
|
||||||
.enable(
|
.enable(
|
||||||
hal::uart::common_configs::_9600_8_N_1,
|
hal::uart::common_configs::_9600_8_N_1,
|
||||||
clocks.peripheral_clock.into(),
|
clocks.peripheral_clock.into(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// UART TX (characters sent from RP2040) on pin 1 (GPIO0)
|
|
||||||
let _tx_pin = pins.gpio0.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
// UART RX (characters reveived by RP2040) on pin 2 (GPIO1)
|
|
||||||
let _rx_pin = pins.gpio1.into_mode::<hal::gpio::FunctionUart>();
|
|
||||||
|
|
||||||
uart.write_full_blocking(b"UART example\r\n");
|
uart.write_full_blocking(b"UART example\r\n");
|
||||||
|
|
||||||
let mut value = 0u32;
|
let mut value = 0u32;
|
||||||
|
|
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,
|
||||||
|
};
|
47
rp2040-hal/src/uart/mod.rs
Normal file
47
rp2040-hal/src/uart/mod.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//! 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();
|
||||||
|
//!
|
||||||
|
//! // 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::new(peripherals.UART0, pins, &mut peripherals.RESETS)
|
||||||
|
//! .enable(
|
||||||
|
//! uart::common_configs::_9600_8_N_1,
|
||||||
|
//! clocks.peripheral_clock.into(),
|
||||||
|
//! ).unwrap();
|
||||||
|
//!
|
||||||
|
//! uart.write_full_blocking(b"Hello World!\r\n");
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
mod peripheral;
|
||||||
|
mod pins;
|
||||||
|
mod reader;
|
||||||
|
mod utils;
|
||||||
|
mod writer;
|
||||||
|
|
||||||
|
pub use self::peripheral::UartPeripheral;
|
||||||
|
pub use self::pins::*;
|
||||||
|
pub use self::reader::{ReadError, ReadErrorType, Reader};
|
||||||
|
pub use self::utils::*;
|
||||||
|
pub use self::writer::Writer;
|
||||||
|
|
||||||
|
/// Common configurations for UART.
|
||||||
|
pub mod common_configs;
|
|
@ -16,226 +16,74 @@
|
||||||
//! let mut watchdog = Watchdog::new(peripherals.WATCHDOG);
|
//! 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();
|
//! 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.
|
//! // Need to perform clock init before using UART or it will freeze.
|
||||||
//! let uart = UartPeripheral::<_, _>::new(peripherals.UART0, &mut peripherals.RESETS)
|
//! let uart = UartPeripheral::new(peripherals.UART0, pins, &mut peripherals.RESETS)
|
||||||
//! .enable(
|
//! .enable(
|
||||||
//! uart::common_configs::_9600_8_N_1,
|
//! uart::common_configs::_9600_8_N_1,
|
||||||
//! clocks.peripheral_clock.into(),
|
//! clocks.peripheral_clock.into(),
|
||||||
//! )
|
//! )
|
||||||
//! .unwrap();
|
//! .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");
|
//! 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::convert::Infallible;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::Deref;
|
use embedded_hal::serial::{Read, Write};
|
||||||
use embedded_time::fixed_point::FixedPoint;
|
use embedded_time::fixed_point::FixedPoint;
|
||||||
use embedded_time::rate::Baud;
|
use embedded_time::rate::Baud;
|
||||||
use embedded_time::rate::Hertz;
|
use embedded_time::rate::Hertz;
|
||||||
|
use nb::Error::{Other, WouldBlock};
|
||||||
|
use rp2040_pac::{UART0, UART1};
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
use eh1_0_alpha::serial::nb as eh1;
|
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 {
|
|
||||||
match self {
|
|
||||||
ReadErrorType::Overrun => eh1_0_alpha::serial::ErrorKind::Overrun,
|
|
||||||
ReadErrorType::Break => eh1_0_alpha::serial::ErrorKind::Other,
|
|
||||||
ReadErrorType::Parity => eh1_0_alpha::serial::ErrorKind::Parity,
|
|
||||||
ReadErrorType::Framing => eh1_0_alpha::serial::ErrorKind::FrameFormat,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
/// 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,
|
device: D,
|
||||||
_state: S,
|
_state: S,
|
||||||
|
pins: P,
|
||||||
config: UartConfig,
|
config: UartConfig,
|
||||||
effective_baudrate: Baud,
|
effective_baudrate: Baud,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: State, D: UartDevice> UartPeripheral<S, D> {
|
impl<S: State, D: UartDevice, P: ValidUartPinout<D>> UartPeripheral<S, D, P> {
|
||||||
fn transition<To: State>(self, state: To) -> UartPeripheral<To, D> {
|
fn transition<To: State>(self, state: To) -> UartPeripheral<To, D, P> {
|
||||||
UartPeripheral {
|
UartPeripheral {
|
||||||
device: self.device,
|
device: self.device,
|
||||||
|
pins: self.pins,
|
||||||
config: self.config,
|
config: self.config,
|
||||||
effective_baudrate: self.effective_baudrate,
|
effective_baudrate: self.effective_baudrate,
|
||||||
_state: state,
|
_state: state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases the underlying device.
|
/// Releases the underlying device and pins.
|
||||||
pub fn free(self) -> D {
|
pub fn free(self) -> (D, P) {
|
||||||
self.device
|
(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.
|
/// 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_down(resets);
|
||||||
device.reset_bring_up(resets);
|
device.reset_bring_up(resets);
|
||||||
|
|
||||||
UartPeripheral {
|
UartPeripheral {
|
||||||
device,
|
device,
|
||||||
|
_state: Disabled,
|
||||||
|
pins,
|
||||||
config: common_configs::_9600_8_N_1, // placeholder
|
config: common_configs::_9600_8_N_1, // placeholder
|
||||||
effective_baudrate: Baud(0),
|
effective_baudrate: Baud(0),
|
||||||
_state: Disabled,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,8 +92,8 @@ impl<D: UartDevice> UartPeripheral<Disabled, D> {
|
||||||
self,
|
self,
|
||||||
config: UartConfig,
|
config: UartConfig,
|
||||||
frequency: Hertz,
|
frequency: Hertz,
|
||||||
) -> Result<UartPeripheral<Enabled, D>, Error> {
|
) -> Result<UartPeripheral<Enabled, D, P>, Error> {
|
||||||
let mut device = self.free();
|
let (mut device, pins) = self.free();
|
||||||
let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?;
|
let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?;
|
||||||
|
|
||||||
device.uartlcr_h.write(|w| {
|
device.uartlcr_h.write(|w| {
|
||||||
|
@ -254,11 +102,14 @@ impl<D: UartDevice> UartPeripheral<Disabled, D> {
|
||||||
w
|
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| {
|
device.uartcr.write(|w| {
|
||||||
w.uarten().set_bit();
|
w.uarten().set_bit();
|
||||||
w.txe().set_bit();
|
w.txe().bit(P::TX_ENABLED);
|
||||||
w.rxe().set_bit();
|
w.rxe().bit(P::RX_ENABLED);
|
||||||
|
w.ctsen().bit(P::CTS_ENABLED);
|
||||||
|
w.rtsen().bit(P::RTS_ENABLED);
|
||||||
|
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -271,67 +122,36 @@ impl<D: UartDevice> UartPeripheral<Disabled, D> {
|
||||||
Ok(UartPeripheral {
|
Ok(UartPeripheral {
|
||||||
device,
|
device,
|
||||||
config,
|
config,
|
||||||
|
pins,
|
||||||
effective_baudrate,
|
effective_baudrate,
|
||||||
_state: Enabled,
|
_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.
|
/// 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
|
// Disable the UART, both TX and RX
|
||||||
self.device.uartcr.write(|w| {
|
self.device.uartcr.write(|w| {
|
||||||
w.uarten().clear_bit();
|
w.uarten().clear_bit();
|
||||||
w.txe().clear_bit();
|
w.txe().clear_bit();
|
||||||
w.rxe().clear_bit();
|
w.rxe().clear_bit();
|
||||||
|
w.ctsen().clear_bit();
|
||||||
|
w.rtsen().clear_bit();
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
self.transition(Disabled)
|
self.transition(Disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn transmit_flushed(&self) -> nb::Result<(), Infallible> {
|
|
||||||
if self.device.uartfr.read().txfe().bit_is_set() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(WouldBlock)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uart_is_writable(&self) -> bool {
|
|
||||||
self.device.uartfr.read().txff().bit_is_clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn uart_is_readable(&self) -> bool {
|
|
||||||
self.device.uartfr.read().rxfe().bit_is_clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes bytes to the UART.
|
/// Writes bytes to the UART.
|
||||||
/// This function writes as long as it can. As soon that the FIFO is full, if :
|
/// This function writes as long as it can. As soon that the FIFO is full, if :
|
||||||
/// - 0 bytes were written, a WouldBlock Error is returned
|
/// - 0 bytes were written, a WouldBlock Error is returned
|
||||||
/// - some bytes were written, it is deemed to be a success
|
/// - some bytes were written, it is deemed to be a success
|
||||||
/// Upon success, the remaining slice is returned.
|
/// Upon success, the remaining slice is returned.
|
||||||
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
|
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
|
||||||
let mut bytes_written = 0;
|
super::writer::write_raw(&self.device, data)
|
||||||
|
|
||||||
for c in data {
|
|
||||||
if !self.uart_is_writable() {
|
|
||||||
if bytes_written == 0 {
|
|
||||||
return Err(WouldBlock);
|
|
||||||
} else {
|
|
||||||
return Ok(&data[bytes_written..]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.device.uartdr.write(|w| unsafe {
|
|
||||||
w.data().bits(*c);
|
|
||||||
w
|
|
||||||
});
|
|
||||||
|
|
||||||
bytes_written += 1;
|
|
||||||
}
|
|
||||||
Ok(&data[bytes_written..])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads bytes from the UART.
|
/// Reads bytes from the UART.
|
||||||
|
@ -340,83 +160,75 @@ impl<D: UartDevice> UartPeripheral<Enabled, D> {
|
||||||
/// - some bytes were read, it is deemed to be a success
|
/// - some bytes were read, it is deemed to be a success
|
||||||
/// Upon success, it will return how many bytes were read.
|
/// Upon success, it will return how many bytes were read.
|
||||||
pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<usize, ReadError<'b>> {
|
pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<usize, ReadError<'b>> {
|
||||||
let mut bytes_read = 0;
|
super::reader::read_raw(&self.device, buffer)
|
||||||
|
|
||||||
Ok(loop {
|
|
||||||
if !self.uart_is_readable() {
|
|
||||||
if bytes_read == 0 {
|
|
||||||
return Err(WouldBlock);
|
|
||||||
} else {
|
|
||||||
break bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes_read < buffer.len() {
|
|
||||||
let mut error: Option<ReadErrorType> = None;
|
|
||||||
|
|
||||||
let read = self.device.uartdr.read();
|
|
||||||
|
|
||||||
if read.oe().bit_is_set() {
|
|
||||||
error = Some(ReadErrorType::Overrun);
|
|
||||||
}
|
|
||||||
|
|
||||||
if read.be().bit_is_set() {
|
|
||||||
error = Some(ReadErrorType::Break);
|
|
||||||
}
|
|
||||||
|
|
||||||
if read.pe().bit_is_set() {
|
|
||||||
error = Some(ReadErrorType::Parity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if read.fe().bit_is_set() {
|
|
||||||
error = Some(ReadErrorType::Framing);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(err_type) = error {
|
|
||||||
return Err(Other(ReadError {
|
|
||||||
err_type,
|
|
||||||
discared: buffer,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[bytes_read] = read.data().bits();
|
|
||||||
bytes_read += 1;
|
|
||||||
} else {
|
|
||||||
break bytes_read;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes bytes to the UART.
|
/// Writes bytes to the UART.
|
||||||
/// This function blocks until the full buffer has been sent.
|
/// This function blocks until the full buffer has been sent.
|
||||||
pub fn write_full_blocking(&self, data: &[u8]) {
|
pub fn write_full_blocking(&self, data: &[u8]) {
|
||||||
let mut temp = data;
|
super::writer::write_full_blocking(&self.device, data);
|
||||||
|
|
||||||
while !temp.is_empty() {
|
|
||||||
temp = match self.write_raw(temp) {
|
|
||||||
Ok(remaining) => remaining,
|
|
||||||
Err(WouldBlock) => continue,
|
|
||||||
Err(_) => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads bytes from the UART.
|
/// Reads bytes from the UART.
|
||||||
/// This function blocks until the full buffer has been received.
|
/// This function blocks until the full buffer has been received.
|
||||||
pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> {
|
pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> {
|
||||||
let mut offset = 0;
|
super::reader::read_full_blocking(&self.device, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
while offset != buffer.len() {
|
/// Join the reader and writer halves together back into the original Uart peripheral.
|
||||||
offset += match self.read_raw(&mut buffer[offset..]) {
|
///
|
||||||
Ok(bytes_read) => bytes_read,
|
/// A reader/writer pair can be obtained by calling [`split`].
|
||||||
Err(e) => match e {
|
///
|
||||||
Other(inner) => return Err(inner.err_type),
|
/// [`split`]: #method.split
|
||||||
WouldBlock => continue,
|
pub fn join(reader: Reader<D, P>, writer: Writer<D, P>) -> Self {
|
||||||
},
|
let _ = writer;
|
||||||
}
|
Self {
|
||||||
|
device: reader.device,
|
||||||
|
_state: Enabled,
|
||||||
|
pins: reader.pins,
|
||||||
|
config: reader.config,
|
||||||
|
effective_baudrate: reader.effective_baudrate,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
impl<P: ValidUartPinout<UART0>> UartPeripheral<Enabled, UART0, P> {
|
||||||
|
/// Split this peripheral into a separate reader and writer.
|
||||||
|
pub fn split(self) -> (Reader<UART0, P>, Writer<UART0, P>) {
|
||||||
|
let reader = Reader {
|
||||||
|
device: self.device,
|
||||||
|
pins: self.pins,
|
||||||
|
config: self.config,
|
||||||
|
effective_baudrate: self.effective_baudrate,
|
||||||
|
};
|
||||||
|
// Safety: reader and writer will never write to the same address
|
||||||
|
let device_copy = unsafe { &*UART0::ptr() };
|
||||||
|
let writer = Writer {
|
||||||
|
device: device_copy,
|
||||||
|
device_marker: core::marker::PhantomData,
|
||||||
|
pins: core::marker::PhantomData,
|
||||||
|
};
|
||||||
|
(reader, writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: ValidUartPinout<UART1>> UartPeripheral<Enabled, UART1, P> {
|
||||||
|
/// Split this peripheral into a separate reader and writer.
|
||||||
|
pub fn split(self) -> (Reader<UART1, P>, Writer<UART1, P>) {
|
||||||
|
let reader = Reader {
|
||||||
|
device: self.device,
|
||||||
|
pins: self.pins,
|
||||||
|
config: self.config,
|
||||||
|
effective_baudrate: self.effective_baudrate,
|
||||||
|
};
|
||||||
|
// Safety: reader and writer will never write to the same address
|
||||||
|
let device_copy = unsafe { &*UART1::ptr() };
|
||||||
|
let writer = Writer {
|
||||||
|
device: device_copy,
|
||||||
|
device_marker: core::marker::PhantomData,
|
||||||
|
pins: core::marker::PhantomData,
|
||||||
|
};
|
||||||
|
(reader, writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +322,7 @@ fn set_format<'w>(
|
||||||
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;
|
type Error = ReadErrorType;
|
||||||
|
|
||||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
@ -527,7 +339,7 @@ impl<D: UartDevice> Read<u8> for UartPeripheral<Enabled, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
#[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;
|
type Error = ReadErrorType;
|
||||||
|
|
||||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
@ -542,31 +354,7 @@ impl<D: UartDevice> eh1::Read<u8> for UartPeripheral<Enabled, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for UartPeripheral<Enabled, D, P> {
|
||||||
/// Same as core::convert::Infallible, but implementing spi::Error
|
|
||||||
///
|
|
||||||
/// For eh 1.0.0-alpha.6, Infallible doesn't implement spi::Error,
|
|
||||||
/// so use a locally defined type instead.
|
|
||||||
/// This should be removed with the next release of e-h.
|
|
||||||
/// (https://github.com/rust-embedded/embedded-hal/pull/328)
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
|
||||||
pub enum SerialInfallible {}
|
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
|
||||||
impl core::fmt::Debug for SerialInfallible {
|
|
||||||
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
|
||||||
impl eh1_0_alpha::serial::Error for SerialInfallible {
|
|
||||||
fn kind(&self) -> eh1_0_alpha::serial::ErrorKind {
|
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
|
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
@ -578,12 +366,12 @@ impl<D: UartDevice> Write<u8> for UartPeripheral<Enabled, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
self.transmit_flushed()
|
super::writer::transmit_flushed(&self.device)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "eh1_0_alpha")]
|
#[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;
|
type Error = SerialInfallible;
|
||||||
|
|
||||||
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
@ -595,14 +383,14 @@ impl<D: UartDevice> eh1::Write<u8> for UartPeripheral<Enabled, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
self.transmit_flushed().map_err(|e| match e {
|
super::writer::transmit_flushed(&self.device).map_err(|e| match e {
|
||||||
WouldBlock => WouldBlock,
|
WouldBlock => WouldBlock,
|
||||||
Other(v) => match v {},
|
Other(v) => match v {},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
s.bytes()
|
s.bytes()
|
||||||
.try_for_each(|c| nb::block!(self.write(c)))
|
.try_for_each(|c| nb::block!(self.write(c)))
|
222
rp2040-hal/src/uart/pins.rs
Normal file
222
rp2040-hal/src/uart/pins.rs
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
use crate::gpio::{bank0, FunctionUart, Pin};
|
||||||
|
use crate::pac::{UART0, UART1};
|
||||||
|
|
||||||
|
use super::UartDevice;
|
||||||
|
|
||||||
|
/// Declares a valid UART pinout.
|
||||||
|
pub trait ValidUartPinout<UART: UartDevice> {
|
||||||
|
/// 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
|
||||||
|
UART: UartDevice,
|
||||||
|
TX: Tx<UART>,
|
||||||
|
RX: Rx<UART>,
|
||||||
|
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)
|
||||||
|
where
|
||||||
|
UART: UartDevice,
|
||||||
|
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)
|
||||||
|
where
|
||||||
|
UART: UartDevice,
|
||||||
|
TX: Tx<UART>,
|
||||||
|
RX: Rx<UART>,
|
||||||
|
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.
|
||||||
|
///
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// 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,
|
||||||
|
pub rx: RX,
|
||||||
|
pub rts: RTS,
|
||||||
|
pub cts: CTS,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Pins<(), (), (), ()> {
|
||||||
|
fn default() -> 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: UartDevice> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
const ENABLED: bool;
|
||||||
|
}
|
||||||
|
/// Indicates a valid RX pin for UART0 or UART1
|
||||||
|
pub trait Rx<UART: UartDevice> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
const ENABLED: bool;
|
||||||
|
}
|
||||||
|
/// Indicates a valid CTS pin for UART0 or UART1
|
||||||
|
pub trait Cts<UART: UartDevice> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
const ENABLED: bool;
|
||||||
|
}
|
||||||
|
/// Indicates a valid RTS pin for UART0 or UART1
|
||||||
|
pub trait Rts<UART: UartDevice> {
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
const ENABLED: bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<UART: UartDevice> Tx<UART> for () {
|
||||||
|
const ENABLED: bool = false;
|
||||||
|
}
|
||||||
|
impl<UART: UartDevice> Rx<UART> for () {
|
||||||
|
const ENABLED: bool = false;
|
||||||
|
}
|
||||||
|
impl<UART: UartDevice> Cts<UART> for () {
|
||||||
|
const ENABLED: bool = false;
|
||||||
|
}
|
||||||
|
impl<UART: UartDevice> Rts<UART> for () {
|
||||||
|
const ENABLED: 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 ENABLED: bool = true;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
$(
|
||||||
|
impl Rx<$uart> for Pin<bank0::$rx, FunctionUart> {
|
||||||
|
const ENABLED: bool = true;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
$(
|
||||||
|
impl Cts<$uart> for Pin<bank0::$cts, FunctionUart> {
|
||||||
|
const ENABLED: bool = true;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
$(
|
||||||
|
impl Rts<$uart> for Pin<bank0::$rts, FunctionUart> {
|
||||||
|
const ENABLED: 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],
|
||||||
|
}
|
||||||
|
);
|
179
rp2040-hal/src/uart/reader.rs
Normal file
179
rp2040-hal/src/uart/reader.rs
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
use super::{UartConfig, UartDevice, ValidUartPinout};
|
||||||
|
use embedded_hal::serial::Read;
|
||||||
|
use embedded_time::rate::Baud;
|
||||||
|
use nb::Error::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
use eh1_0_alpha::serial::nb as eh1;
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
match self {
|
||||||
|
ReadErrorType::Overrun => eh1_0_alpha::serial::ErrorKind::Overrun,
|
||||||
|
ReadErrorType::Break => eh1_0_alpha::serial::ErrorKind::Other,
|
||||||
|
ReadErrorType::Parity => eh1_0_alpha::serial::ErrorKind::Parity,
|
||||||
|
ReadErrorType::Framing => eh1_0_alpha::serial::ErrorKind::FrameFormat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_readable<D: UartDevice>(device: &D) -> bool {
|
||||||
|
device.uartfr.read().rxfe().bit_is_clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_raw<'b, D: UartDevice>(
|
||||||
|
device: &D,
|
||||||
|
buffer: &'b mut [u8],
|
||||||
|
) -> nb::Result<usize, ReadError<'b>> {
|
||||||
|
let mut bytes_read = 0;
|
||||||
|
|
||||||
|
Ok(loop {
|
||||||
|
if !is_readable(device) {
|
||||||
|
if bytes_read == 0 {
|
||||||
|
return Err(WouldBlock);
|
||||||
|
} else {
|
||||||
|
break bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes_read < buffer.len() {
|
||||||
|
let mut error: Option<ReadErrorType> = None;
|
||||||
|
|
||||||
|
let read = device.uartdr.read();
|
||||||
|
|
||||||
|
if read.oe().bit_is_set() {
|
||||||
|
error = Some(ReadErrorType::Overrun);
|
||||||
|
}
|
||||||
|
|
||||||
|
if read.be().bit_is_set() {
|
||||||
|
error = Some(ReadErrorType::Break);
|
||||||
|
}
|
||||||
|
|
||||||
|
if read.pe().bit_is_set() {
|
||||||
|
error = Some(ReadErrorType::Parity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if read.fe().bit_is_set() {
|
||||||
|
error = Some(ReadErrorType::Framing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(err_type) = error {
|
||||||
|
return Err(Other(ReadError {
|
||||||
|
err_type,
|
||||||
|
discared: buffer,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[bytes_read] = read.data().bits();
|
||||||
|
bytes_read += 1;
|
||||||
|
} else {
|
||||||
|
break bytes_read;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_full_blocking<D: UartDevice>(
|
||||||
|
device: &D,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
) -> Result<(), ReadErrorType> {
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
while offset != buffer.len() {
|
||||||
|
offset += match read_raw(device, &mut buffer[offset..]) {
|
||||||
|
Ok(bytes_read) => bytes_read,
|
||||||
|
Err(e) => match e {
|
||||||
|
Other(inner) => return Err(inner.err_type),
|
||||||
|
WouldBlock => continue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Half of an [`UartPeripheral`] that is only capable of reading. Obtained by calling [`UartPeripheral::split()`]
|
||||||
|
///
|
||||||
|
/// [`UartPeripheral`]: struct.UartPeripheral.html
|
||||||
|
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
|
||||||
|
pub struct Reader<D: UartDevice, P: ValidUartPinout<D>> {
|
||||||
|
pub(super) device: D,
|
||||||
|
pub(super) pins: P,
|
||||||
|
pub(super) config: UartConfig,
|
||||||
|
pub(super) effective_baudrate: Baud,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> Reader<D, P> {
|
||||||
|
/// Reads bytes from the UART.
|
||||||
|
/// This function reads as long as it can. As soon that the FIFO is empty, if :
|
||||||
|
/// - 0 bytes were read, a WouldBlock Error is returned
|
||||||
|
/// - some bytes were read, it is deemed to be a success
|
||||||
|
/// Upon success, it will return how many bytes were read.
|
||||||
|
pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<usize, ReadError<'b>> {
|
||||||
|
read_raw(&self.device, buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads bytes from the UART.
|
||||||
|
/// This function blocks until the full buffer has been received.
|
||||||
|
pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> {
|
||||||
|
read_full_blocking(&self.device, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> Read<u8> for Reader<D, P> {
|
||||||
|
type Error = ReadErrorType;
|
||||||
|
|
||||||
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
let byte: &mut [u8] = &mut [0; 1];
|
||||||
|
|
||||||
|
match self.read_raw(byte) {
|
||||||
|
Ok(_) => Ok(byte[0]),
|
||||||
|
Err(e) => match e {
|
||||||
|
Other(inner) => Err(Other(inner.err_type)),
|
||||||
|
WouldBlock => Err(WouldBlock),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> eh1::Read<u8> for Reader<D, P> {
|
||||||
|
type Error = ReadErrorType;
|
||||||
|
|
||||||
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
|
let byte: &mut [u8] = &mut [0; 1];
|
||||||
|
|
||||||
|
match self.read_raw(byte) {
|
||||||
|
Ok(_) => Ok(byte[0]),
|
||||||
|
Err(e) => match e {
|
||||||
|
Other(inner) => Err(Other(inner.err_type)),
|
||||||
|
WouldBlock => Err(WouldBlock),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
rp2040-hal/src/uart/utils.rs
Normal file
98
rp2040-hal/src/uart/utils.rs
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
/// State of the UART Peripheral.
|
||||||
|
pub trait State {}
|
||||||
|
|
||||||
|
/// Trait to handle both underlying devices (UART0 & UART1)
|
||||||
|
pub trait UartDevice: Deref<Target = RegisterBlock> + SubsystemReset + 'static {}
|
||||||
|
|
||||||
|
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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as core::convert::Infallible, but implementing spi::Error
|
||||||
|
///
|
||||||
|
/// For eh 1.0.0-alpha.6, Infallible doesn't implement spi::Error,
|
||||||
|
/// so use a locally defined type instead.
|
||||||
|
/// This should be removed with the next release of e-h.
|
||||||
|
/// (https://github.com/rust-embedded/embedded-hal/pull/328)
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
pub enum SerialInfallible {}
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
impl core::fmt::Debug for SerialInfallible {
|
||||||
|
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
impl eh1_0_alpha::serial::Error for SerialInfallible {
|
||||||
|
fn kind(&self) -> eh1_0_alpha::serial::ErrorKind {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
129
rp2040-hal/src/uart/writer.rs
Normal file
129
rp2040-hal/src/uart/writer.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
use super::{UartDevice, ValidUartPinout};
|
||||||
|
use core::fmt;
|
||||||
|
use core::{convert::Infallible, marker::PhantomData};
|
||||||
|
use embedded_hal::serial::Write;
|
||||||
|
use nb::Error::*;
|
||||||
|
use rp2040_pac::uart0::RegisterBlock;
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
use eh1_0_alpha::serial::nb as eh1;
|
||||||
|
|
||||||
|
pub(crate) fn transmit_flushed(rb: &RegisterBlock) -> nb::Result<(), Infallible> {
|
||||||
|
if rb.uartfr.read().txfe().bit_is_set() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(WouldBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uart_is_writable(rb: &RegisterBlock) -> bool {
|
||||||
|
rb.uartfr.read().txff().bit_is_clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_raw<'d>(
|
||||||
|
rb: &RegisterBlock,
|
||||||
|
data: &'d [u8],
|
||||||
|
) -> nb::Result<&'d [u8], Infallible> {
|
||||||
|
let mut bytes_written = 0;
|
||||||
|
|
||||||
|
for c in data {
|
||||||
|
if !uart_is_writable(rb) {
|
||||||
|
if bytes_written == 0 {
|
||||||
|
return Err(WouldBlock);
|
||||||
|
} else {
|
||||||
|
return Ok(&data[bytes_written..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.uartdr.write(|w| unsafe {
|
||||||
|
w.data().bits(*c);
|
||||||
|
w
|
||||||
|
});
|
||||||
|
|
||||||
|
bytes_written += 1;
|
||||||
|
}
|
||||||
|
Ok(&data[bytes_written..])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_full_blocking(rb: &RegisterBlock, data: &[u8]) {
|
||||||
|
let mut temp = data;
|
||||||
|
|
||||||
|
while !temp.is_empty() {
|
||||||
|
temp = match write_raw(rb, temp) {
|
||||||
|
Ok(remaining) => remaining,
|
||||||
|
Err(WouldBlock) => continue,
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Half of an [`UartPeripheral`] that is only capable of writing. Obtained by calling [`UartPeripheral::split()`]
|
||||||
|
///
|
||||||
|
/// [`UartPeripheral`]: struct.UartPeripheral.html
|
||||||
|
/// [`UartPeripheral::split()`]: struct.UartPeripheral.html#method.split
|
||||||
|
pub struct Writer<D: UartDevice, P: ValidUartPinout<D>> {
|
||||||
|
pub(super) device: &'static RegisterBlock,
|
||||||
|
pub(super) device_marker: PhantomData<D>,
|
||||||
|
pub(super) pins: PhantomData<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> Writer<D, P> {
|
||||||
|
/// Writes bytes to the UART.
|
||||||
|
/// This function writes as long as it can. As soon that the FIFO is full, if :
|
||||||
|
/// - 0 bytes were written, a WouldBlock Error is returned
|
||||||
|
/// - some bytes were written, it is deemed to be a success
|
||||||
|
/// Upon success, the remaining slice is returned.
|
||||||
|
pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> {
|
||||||
|
write_raw(self.device, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes bytes to the UART.
|
||||||
|
/// This function blocks until the full buffer has been sent.
|
||||||
|
pub fn write_full_blocking(&self, data: &[u8]) {
|
||||||
|
super::writer::write_full_blocking(self.device, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> Write<u8> for Writer<D, P> {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
if self.write_raw(&[word]).is_err() {
|
||||||
|
Err(WouldBlock)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
|
super::writer::transmit_flushed(self.device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "eh1_0_alpha")]
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> eh1::Write<u8> for Writer<D, P> {
|
||||||
|
type Error = super::utils::SerialInfallible;
|
||||||
|
|
||||||
|
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
|
||||||
|
if self.write_raw(&[word]).is_err() {
|
||||||
|
Err(WouldBlock)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> nb::Result<(), Self::Error> {
|
||||||
|
transmit_flushed(&self.device).map_err(|e| match e {
|
||||||
|
WouldBlock => WouldBlock,
|
||||||
|
Other(v) => match v {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D: UartDevice, P: ValidUartPinout<D>> fmt::Write for Writer<D, P> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
s.bytes()
|
||||||
|
.try_for_each(|c| nb::block!(self.write(c)))
|
||||||
|
.map_err(|_| fmt::Error)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue