//! Universal Asynchronous Receiver Transmitter (UART) // See [Chapter 4 Section 2](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details use core::convert::Infallible; use core::ops::Deref; use embedded_time::rate::Baud; use embedded_time::rate::Hertz; use embedded_time::fixed_point::FixedPoint; use nb::Error::WouldBlock; use crate::pac::{ uart0::{ uartlcr_h::W as UART_LCR_H_Writer, RegisterBlock }, UART0, UART1 }; /// Error type for UART operations. 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 {} 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 { baudrate: Baud, data_bits: DataBits, stop_bits: StopBits, parity: Option } /// Common configurations for UART. pub mod common_configs { use super::{ UARTConfig, DataBits, StopBits }; 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 { device: D, _state: S, config: UARTConfig, effective_baudrate: Baud } impl UARTPeripheral { fn transition(self, state: To) -> UARTPeripheral { UARTPeripheral { device: self.device, config: self.config, effective_baudrate: self.effective_baudrate, _state: state } } /// Releases the underlying device. pub fn free(self) -> D{ self.device } } impl UARTPeripheral { /// Enables the provided UART device with the given configuration. pub fn enable(mut device: D, config: UARTConfig, frequency: Hertz) -> Result, Error> { let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?; // Enable the UART, both TX and RX device.uartcr.write(|w| { w.uarten().set_bit(); w.txe().set_bit(); w.rxe().set_bit(); w }); device.uartlcr_h.write(|w| { w.fen().set_bit(); set_format(w, &config.data_bits, &config.stop_bits, &config.parity); w }); device.uartdmacr.write(|w| { w.txdmae().set_bit(); w.rxdmae().set_bit(); w }); Ok(UARTPeripheral { device, config, effective_baudrate, _state: Enabled }) } } impl UARTPeripheral { /// Disable this UART Peripheral, falling back to the Disabled state. 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 }); self.transition(Disabled) } 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. /// 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 number of written bytes is returned. pub fn write<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { let mut bytes_written = 0; 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; } return Ok(&data[bytes_written..]) } /// 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, the number of read bytes is returned. pub fn read<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], Infallible> { let mut bytes_read = 0; Ok(loop { if !self.uart_is_readable() { if bytes_read == 0 { return Err(WouldBlock) } else { break &mut buffer[bytes_read..] } } if bytes_read < buffer.len() { buffer[bytes_read] = self.device.uartdr.read().data().bits(); bytes_read += 1; } else { break &mut buffer[bytes_read..] } }) } /// Writes bytes to the UART. /// This function blocks until the full buffer has been sent. pub fn write_full_blocking(&self, data: &[u8]) { let mut temp = data; while !temp.is_empty() { temp = match self.write(temp) { Ok(remaining) => remaining, Err(WouldBlock) => continue, Err(_) => unreachable!() } } } /// Reads bytes from the UART. /// This function blocks until the full buffer has been received. pub fn read_full_blocking(&self, buffer: &mut [u8]) { let mut offset = 0; while offset != buffer.len() { offset += match self.read(&mut buffer[offset..]) { Ok(remaining) => { remaining.len() }, Err(WouldBlock) => continue, Err(_) => unreachable!() } } } } /// Baudrate dividers calculation. Code inspired from the C SDK. fn calculate_baudrate_dividers(wanted_baudrate: &Baud, frequency: &Hertz) -> Result<(u16, u16), Error> { // baudrate_div = frequency * 8 / wanted_baudrate let baudrate_div = frequency.checked_mul(&8). and_then(|r| r.checked_div(wanted_baudrate.integer())). ok_or(Error::BadArgument)?; let baudrate_div: u32 = *baudrate_div.integer(); Ok(match (baudrate_div >> 7, ((baudrate_div & 0x7F) + 1) / 2) { (0, _) => (1, 0), (ibrd, _) if ibrd >= 65535 => (65535, 0), (ibrd, fbrd) => (ibrd as u16, fbrd as u16) }) } /// Baudrate configuration. Code loosely inspired from the C SDK. fn configure_baudrate(device: &mut dyn UARTDevice, wanted_baudrate: &Baud, frequency: &Hertz) -> Result { let (baud_ibrd, baud_fbrd) = calculate_baudrate_dividers(wanted_baudrate, frequency)?; // Load PL011's baud divisor registers device.uartibrd.write(|w| unsafe { w.baud_divint().bits(baud_ibrd as u16); w }); device.uartfbrd.write(|w| unsafe { w.baud_divfrac().bits(baud_fbrd as u8); w }); // PL011 needs a (dummy) line control register write to latch in the // divisors. We don't want to actually change LCR contents here. device.uartlcr_h.modify(|_,w| { w }); Ok(Baud((4 * *frequency.integer()) / (64 * baud_ibrd + baud_fbrd) as u32)) } /// Format configuration. Code loosely inspired from the C SDK. fn set_format<'w>(w: &'w mut UART_LCR_H_Writer, data_bits: &DataBits, stop_bits: &StopBits, parity: &Option) -> &'w mut UART_LCR_H_Writer { match parity { Some(p) => { w.pen().set_bit(); match p { Parity::Odd => w.eps().bit(false), Parity::Even => w.eps().set_bit() }; }, None => { w.pen().bit(false); } }; unsafe { w.wlen().bits( match data_bits { DataBits::Five => { 0b00 } DataBits::Six => { 0b01 } DataBits::Seven => { 0b10 } DataBits::Eight => { 0b11 } } ) }; match stop_bits { StopBits::One => w.stp2().bit(false), StopBits::Two => w.stp2().set_bit() }; w }