From b9080d0a926891295922700590d3d5f673969472 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 10:51:46 +0200 Subject: [PATCH 01/19] Working implementation of an UART HAL. --- rp2040-hal/Cargo.toml | 1 + rp2040-hal/src/uart.rs | 357 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 356 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 782adb1..b0c0238 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -14,3 +14,4 @@ cortex-m = "0.7.1" embedded-hal = "0.2.4" nb = "1.0.0" rp2040-pac = "0.1.1" +embedded-time = "0.10.1" diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index c4e1f76..2f59c00 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -1,3 +1,356 @@ -//! Universal asynchronous receiver-transmitter (UART) +//! Universal Asynchronous Receiver Transmitter (UART) // See [Chapter 4 Section 2](https://datasheets.raspberrypi.org/rp2040/rp2040_datasheet.pdf) for more details -// TODO + +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 rp2040_pac::{ + uart0::uartlcr_h::W as UART_LCR_H_Writer +}; + + +/// State of the UART Peripheral. +pub trait State {} + +/// Trait to handle both underlying devices (UART0 & UART1) +pub trait UARTDevice: Deref {} + +impl UARTDevice for rp2040_pac::UART0 {} +impl UARTDevice for rp2040_pac::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) -> UARTPeripheral { + + 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 + }); + + UARTPeripheral { + device, config, effective_baudrate, _state: Enabled + } + } +} + +impl UARTPeripheral { + + /// Disable this UART Peripheral, falling back to the Disabled state. + pub fn disable(self) -> UARTPeripheral { + 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(&self, data: &[u8]) -> nb::Result { + + let mut bytes_written = 0; + + for c in data { + + if !self.uart_is_writable() { + if bytes_written == 0 { + return Err(WouldBlock) + } + else { + return Ok(bytes_written) + } + } + + bytes_written += 1; + + self.device.uartdr.write(|w| unsafe { + w.data().bits(*c); + w + }) + } + Ok(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(&self, buffer: &mut [u8]) -> nb::Result { + + let mut bytes_read = 0; + + Ok(loop { + if !self.uart_is_readable() { + if bytes_read == 0 { + return Err(WouldBlock) + } + else { + return Ok(bytes_read) + } + } + + if bytes_read < buffer.len() { + buffer[bytes_read] = self.device.uartdr.read().data().bits(); + bytes_read += 1; + } + else { + break 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 offset = 0; + + while offset != data.len() { + offset += match self.write(&data[offset..]) { + Ok(written_bytes) => { + written_bytes + } + + 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(bytes_read) => { + bytes_read + } + + Err(WouldBlock) => continue, + + Err(_) => unreachable!() + }; + } + } + +} + +/// Baudrate configuration. Code loosely inspired from the C SDK. +fn configure_baudrate(device: &mut dyn UARTDevice, wanted_baudrate: &Baud, frequency: &Hertz) -> Baud { + + let frequency = *frequency.integer(); + + let baudrate_div = 8 * frequency / *wanted_baudrate.integer(); + + let (baud_ibrd, baud_fbrd) = match (baudrate_div >> 7, ((baudrate_div & 0x7F) + 1) / 2) { + + (0, _) => (1, 0), + + (ibrd, _) if ibrd >= 65535 => (65535, 0), + + (ibrd, fbrd) => (ibrd, fbrd) + }; + + // 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.write(|w| { + w + }); + + Baud((4 * frequency) / (64 * baud_ibrd + baud_fbrd)) +} + + +/// 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 +} From f9254fdffa29fc62ad1a576f58669ea532536dc2 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 20:00:56 +0200 Subject: [PATCH 02/19] Increment byte_written after write has happened. Co-authored-by: tdittr --- rp2040-hal/src/uart.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 2f59c00..4ede6d8 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -209,12 +209,12 @@ impl UARTPeripheral { } } - bytes_written += 1; - self.device.uartdr.write(|w| unsafe { w.data().bits(*c); w - }) + }); + + bytes_written += 1; } Ok(bytes_written) } From c50a5b60014292ab8d4d5dc0bf318d363dd4a08a Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 20:24:56 +0200 Subject: [PATCH 03/19] Cosmetics. --- rp2040-hal/src/uart.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 2f59c00..d04b054 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -7,19 +7,25 @@ use embedded_time::rate::Baud; use embedded_time::rate::Hertz; use embedded_time::fixed_point::FixedPoint; use nb::Error::WouldBlock; -use rp2040_pac::{ - uart0::uartlcr_h::W as UART_LCR_H_Writer -}; +use crate::pac::{ + uart0::{ + uartlcr_h::W as UART_LCR_H_Writer, + RegisterBlock + }, + UART0, + UART1 + +}; /// State of the UART Peripheral. pub trait State {} /// Trait to handle both underlying devices (UART0 & UART1) -pub trait UARTDevice: Deref {} +pub trait UARTDevice: Deref {} -impl UARTDevice for rp2040_pac::UART0 {} -impl UARTDevice for rp2040_pac::UART1 {} +impl UARTDevice for UART0 {} +impl UARTDevice for UART1 {} /// UART is enabled. pub struct Enabled; From aa3fe8fd2023e02a7c7ea22ea43533a49ccf23dc Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 25 Apr 2021 20:25:29 +0200 Subject: [PATCH 04/19] Disable the UART for real when disabling UART. --- rp2040-hal/src/uart.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index d04b054..f68ac21 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -184,6 +184,15 @@ 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) } From 4d949f7310cb6f3af1a69b0c182fcdc0b41dbad6 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Mon, 26 Apr 2021 09:14:32 +0200 Subject: [PATCH 05/19] Multiple changes addressing @tdittr 's comments. --- rp2040-hal/src/uart.rs | 78 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index f68ac21..cbf2cf5 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -18,6 +18,12 @@ use crate::pac::{ }; +/// Error type for UART operations. +pub enum Error { + /// Bad argument : when things overflow, ... + BadArgument +} + /// State of the UART Peripheral. pub trait State {} @@ -149,9 +155,9 @@ impl UARTPeripheral { impl UARTPeripheral { /// Enables the provided UART device with the given configuration. - pub fn enable(mut device: D, config: UARTConfig, frequency: Hertz) -> UARTPeripheral { + pub fn enable(mut device: D, config: UARTConfig, frequency: Hertz) -> Result, Error> { - let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency); + let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?; // Enable the UART, both TX and RX device.uartcr.write(|w| { @@ -174,9 +180,9 @@ impl UARTPeripheral { w }); - UARTPeripheral { + Ok(UARTPeripheral { device, config, effective_baudrate, _state: Enabled - } + }) } } @@ -209,7 +215,7 @@ impl UARTPeripheral { /// - 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(&self, data: &[u8]) -> nb::Result { + pub fn write<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { let mut bytes_written = 0; @@ -220,7 +226,7 @@ impl UARTPeripheral { return Err(WouldBlock) } else { - return Ok(bytes_written) + return Ok(&data[bytes_written..]) } } @@ -231,7 +237,7 @@ impl UARTPeripheral { w }) } - Ok(bytes_written) + return Ok(&data[bytes_written..]) } /// Reads bytes from the UART. @@ -239,7 +245,7 @@ impl UARTPeripheral { /// - 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(&self, buffer: &mut [u8]) -> nb::Result { + pub fn read<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], Infallible> { let mut bytes_read = 0; @@ -249,7 +255,7 @@ impl UARTPeripheral { return Err(WouldBlock) } else { - return Ok(bytes_read) + break &mut buffer[bytes_read..] } } @@ -258,7 +264,7 @@ impl UARTPeripheral { bytes_read += 1; } else { - break bytes_read; + break &mut buffer[bytes_read..] } }) } @@ -267,18 +273,14 @@ impl UARTPeripheral { /// This function blocks until the full buffer has been sent. pub fn write_full_blocking(&self, data: &[u8]) { - let mut offset = 0; - - while offset != data.len() { - offset += match self.write(&data[offset..]) { - Ok(written_bytes) => { - written_bytes - } + let mut temp = data; + while !temp.is_empty() { + temp = match self.write(temp) { + Ok(remaining) => remaining, Err(WouldBlock) => continue, - Err(_) => unreachable!() - }; + } } } @@ -289,34 +291,38 @@ impl UARTPeripheral { while offset != buffer.len() { offset += match self.read(&mut buffer[offset..]) { - Ok(bytes_read) => { - bytes_read - } - + Ok(remaining) => { remaining.len() }, Err(WouldBlock) => continue, - Err(_) => unreachable!() - }; + } } } - } -/// Baudrate configuration. Code loosely inspired from the C SDK. -fn configure_baudrate(device: &mut dyn UARTDevice, wanted_baudrate: &Baud, frequency: &Hertz) -> Baud { +/// Baudrate dividers calculation. Code inspired from the C SDK. +fn calculate_baudrate_dividers(wanted_baudrate: &Baud, frequency: &Hertz) -> Result<(u16, u16), Error> { - let frequency = *frequency.integer(); + // 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 = 8 * frequency / *wanted_baudrate.integer(); + let baudrate_div: u32 = *baudrate_div.integer(); - let (baud_ibrd, baud_fbrd) = match (baudrate_div >> 7, ((baudrate_div & 0x7F) + 1) / 2) { + Ok(match (baudrate_div >> 7, ((baudrate_div & 0x7F) + 1) / 2) { (0, _) => (1, 0), (ibrd, _) if ibrd >= 65535 => (65535, 0), - (ibrd, fbrd) => (ibrd, fbrd) - }; + (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 { @@ -330,11 +336,9 @@ fn configure_baudrate(device: &mut dyn UARTDevice, wanted_baudrate: &Baud, frequ // 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.write(|w| { - w - }); + device.uartlcr_h.modify(|_,w| { w }); - Baud((4 * frequency) / (64 * baud_ibrd + baud_fbrd)) + Ok(Baud((4 * *frequency.integer()) / (64 * baud_ibrd + baud_fbrd) as u32)) } From 50a428e2ad1262eefdfe02feb2bae0854d22616c Mon Sep 17 00:00:00 2001 From: Nic0w Date: Mon, 26 Apr 2021 21:25:52 +0200 Subject: [PATCH 06/19] Error needs to derive Debug if we want to unwrap. --- rp2040-hal/src/uart.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index d9c1759..a51c4d2 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -19,6 +19,7 @@ use crate::pac::{ }; /// Error type for UART operations. +#[derive(Debug)] pub enum Error { /// Bad argument : when things overflow, ... BadArgument @@ -234,7 +235,7 @@ impl UARTPeripheral { w.data().bits(*c); w }); - + bytes_written += 1; } return Ok(&data[bytes_written..]) From f3fba80a713b632bee7190db8105065864518028 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Mon, 26 Apr 2021 22:05:37 +0200 Subject: [PATCH 07/19] Implement embedded_hal::serial traits for the UART. --- rp2040-hal/src/lib.rs | 1 + rp2040-hal/src/serial.rs | 50 ++++++++++++++++++++++++++++++++++++++++ rp2040-hal/src/uart.rs | 16 +++++++++---- 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 rp2040-hal/src/serial.rs diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index e8d96e2..00be8ba 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -23,4 +23,5 @@ pub mod ssi; pub mod timer; pub mod uart; pub mod usb; +pub mod serial; pub mod watchdog; diff --git a/rp2040-hal/src/serial.rs b/rp2040-hal/src/serial.rs new file mode 100644 index 0000000..c7a3a2e --- /dev/null +++ b/rp2040-hal/src/serial.rs @@ -0,0 +1,50 @@ +//! Implementation for the embedded_hal::serial traits for the UART. +// See [embedded-hal](https://docs.rs/embedded-hal/0.2.4/embedded_hal/serial/index.html) for more details + +use core::convert::Infallible; + +use crate::uart::{ + UARTPeripheral, + UARTDevice, + Enabled +}; + +use embedded_hal::serial::{ + Read, + Write +}; + +use nb::Error::WouldBlock; + +impl Read for UARTPeripheral { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + + let byte: &mut [u8] = &mut [0; 1]; + + if let Err(_) = self.read_raw(byte) { + Err(WouldBlock) + } + else { + Ok(byte[0]) + } + } +} + +impl Write for UARTPeripheral { + type Error = Infallible; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + if let Err(_) = self.write_raw(&[word]) { + Err(WouldBlock) + } + else { + Ok(()) + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.transmit_flushed() + } +} diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index a51c4d2..8860c4f 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -203,6 +203,14 @@ impl UARTPeripheral { 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() } @@ -216,7 +224,7 @@ impl UARTPeripheral { /// - 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> { + pub fn write_raw <'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { let mut bytes_written = 0; @@ -246,7 +254,7 @@ impl UARTPeripheral { /// - 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> { + pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], Infallible> { let mut bytes_read = 0; @@ -277,7 +285,7 @@ impl UARTPeripheral { let mut temp = data; while !temp.is_empty() { - temp = match self.write(temp) { + temp = match self.write_raw(temp) { Ok(remaining) => remaining, Err(WouldBlock) => continue, Err(_) => unreachable!() @@ -291,7 +299,7 @@ impl UARTPeripheral { let mut offset = 0; while offset != buffer.len() { - offset += match self.read(&mut buffer[offset..]) { + offset += match self.read_raw(&mut buffer[offset..]) { Ok(remaining) => { remaining.len() }, Err(WouldBlock) => continue, Err(_) => unreachable!() From 835ad7a5c1e55b9ef850c5ac411246e45289f567 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 2 May 2021 08:27:29 +0200 Subject: [PATCH 08/19] Read errors. --- rp2040-hal/src/uart.rs | 57 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 8860c4f..e161cd8 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -6,7 +6,10 @@ 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 nb::Error::{ + WouldBlock, + Other +}; use crate::pac::{ uart0::{ @@ -25,6 +28,31 @@ pub enum Error { 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" +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 {} @@ -254,7 +282,7 @@ impl UARTPeripheral { /// - 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_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], Infallible> { + pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], ReadError<'b>> { let mut bytes_read = 0; @@ -269,6 +297,31 @@ impl UARTPeripheral { } if bytes_read < buffer.len() { + + let mut error: Option = None; + + if self.device.uartdr.read().oe().bit_is_set() { + error = Some(ReadErrorType::Overrun); + } + + if self.device.uartdr.read().be().bit_is_set() { + error = Some(ReadErrorType::Break); + } + + if self.device.uartdr.read().pe().bit_is_set() { + error = Some(ReadErrorType::Parity); + } + + if self.device.uartdr.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] = self.device.uartdr.read().data().bits(); bytes_read += 1; } From abf91a36873f61e2faa44fa85962de23952ea18f Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 2 May 2021 08:41:20 +0200 Subject: [PATCH 09/19] Move serial traits impl. back to uart.rs --- rp2040-hal/src/lib.rs | 1 - rp2040-hal/src/serial.rs | 50 ---------------------------------------- rp2040-hal/src/uart.rs | 39 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 51 deletions(-) delete mode 100644 rp2040-hal/src/serial.rs diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index 00be8ba..e8d96e2 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -23,5 +23,4 @@ pub mod ssi; pub mod timer; pub mod uart; pub mod usb; -pub mod serial; pub mod watchdog; diff --git a/rp2040-hal/src/serial.rs b/rp2040-hal/src/serial.rs deleted file mode 100644 index c7a3a2e..0000000 --- a/rp2040-hal/src/serial.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Implementation for the embedded_hal::serial traits for the UART. -// See [embedded-hal](https://docs.rs/embedded-hal/0.2.4/embedded_hal/serial/index.html) for more details - -use core::convert::Infallible; - -use crate::uart::{ - UARTPeripheral, - UARTDevice, - Enabled -}; - -use embedded_hal::serial::{ - Read, - Write -}; - -use nb::Error::WouldBlock; - -impl Read for UARTPeripheral { - type Error = Infallible; - - fn read(&mut self) -> nb::Result { - - let byte: &mut [u8] = &mut [0; 1]; - - if let Err(_) = self.read_raw(byte) { - Err(WouldBlock) - } - else { - Ok(byte[0]) - } - } -} - -impl Write for UARTPeripheral { - type Error = Infallible; - - fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { - if let Err(_) = self.write_raw(&[word]) { - Err(WouldBlock) - } - else { - Ok(()) - } - } - - fn flush(&mut self) -> nb::Result<(), Self::Error> { - self.transmit_flushed() - } -} diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index e161cd8..3f9f0ce 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -6,6 +6,12 @@ use core::ops::Deref; use embedded_time::rate::Baud; use embedded_time::rate::Hertz; use embedded_time::fixed_point::FixedPoint; + +use embedded_hal::serial::{ + Read, + Write +}; + use nb::Error::{ WouldBlock, Other @@ -435,3 +441,36 @@ fn set_format<'w>(w: &'w mut UART_LCR_H_Writer, data_bits: &DataBits, stop_bits: w } + +impl Read for UARTPeripheral { + type Error = Infallible; + + fn read(&mut self) -> nb::Result { + + let byte: &mut [u8] = &mut [0; 1]; + + if let Err(_) = self.read_raw(byte) { + Err(WouldBlock) + } + else { + Ok(byte[0]) + } + } +} + +impl Write for UARTPeripheral { + type Error = Infallible; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + if let Err(_) = self.write_raw(&[word]) { + Err(WouldBlock) + } + else { + Ok(()) + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.transmit_flushed() + } +} From 992bcdf47b576f538e407da327f9f7d5c51c84cd Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 2 May 2021 08:42:51 +0200 Subject: [PATCH 10/19] Cargo fmt --- rp2040-hal/src/uart.rs | 181 ++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 95 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 3f9f0ce..9dfc4bf 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -3,45 +3,33 @@ use core::convert::Infallible; use core::ops::Deref; +use embedded_time::fixed_point::FixedPoint; use embedded_time::rate::Baud; use embedded_time::rate::Hertz; -use embedded_time::fixed_point::FixedPoint; -use embedded_hal::serial::{ - Read, - Write -}; +use embedded_hal::serial::{Read, Write}; -use nb::Error::{ - WouldBlock, - Other -}; +use nb::Error::{Other, WouldBlock}; use crate::pac::{ - uart0::{ - uartlcr_h::W as UART_LCR_H_Writer, - RegisterBlock - }, - UART0, - UART1 - + uart0::{uartlcr_h::W as UART_LCR_H_Writer, RegisterBlock}, + UART0, UART1, }; /// Error type for UART operations. #[derive(Debug)] pub enum Error { /// Bad argument : when things overflow, ... - BadArgument + 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] + pub discared: &'err [u8], } /// Possible types of read errors. See Chapter 4, Section 2 §8 - Table 436: "UARTDR Register" @@ -56,7 +44,7 @@ pub enum ReadErrorType { Parity, /// Triggered when the received character didn't have a valid stop bit. - Framing + Framing, } /// State of the UART Peripheral. @@ -86,7 +74,7 @@ pub enum DataBits { /// 7 bits Seven, /// 8 bits - Eight + Eight, } /// Stop bits @@ -95,7 +83,7 @@ pub enum StopBits { One, /// 2 bits - Two + Two, } /// Parity @@ -105,21 +93,20 @@ pub enum Parity { Odd, /// Even parity - Even + Even, } - /// A struct holding the configuration for an UART device. pub struct UARTConfig { baudrate: Baud, data_bits: DataBits, stop_bits: StopBits, - parity: Option + parity: Option, } /// Common configurations for UART. pub mod common_configs { - use super::{ UARTConfig, DataBits, StopBits }; + use super::{DataBits, StopBits, UARTConfig}; use embedded_time::rate::Baud; /// 9600 baud, 8 data bits, no parity, 1 stop bit @@ -127,7 +114,7 @@ pub mod common_configs { baudrate: Baud(9600), data_bits: DataBits::Eight, stop_bits: StopBits::One, - parity: None + parity: None, }; /// 19200 baud, 8 data bits, no parity, 1 stop bit @@ -135,7 +122,7 @@ pub mod common_configs { baudrate: Baud(19200), data_bits: DataBits::Eight, stop_bits: StopBits::One, - parity: None + parity: None, }; /// 38400 baud, 8 data bits, no parity, 1 stop bit @@ -143,7 +130,7 @@ pub mod common_configs { baudrate: Baud(38400), data_bits: DataBits::Eight, stop_bits: StopBits::One, - parity: None + parity: None, }; /// 57600 baud, 8 data bits, no parity, 1 stop bit @@ -151,7 +138,7 @@ pub mod common_configs { baudrate: Baud(57600), data_bits: DataBits::Eight, stop_bits: StopBits::One, - parity: None + parity: None, }; /// 115200 baud, 8 data bits, no parity, 1 stop bit @@ -159,7 +146,7 @@ pub mod common_configs { baudrate: Baud(115200), data_bits: DataBits::Eight, stop_bits: StopBits::One, - parity: None + parity: None, }; } @@ -168,7 +155,7 @@ pub struct UARTPeripheral { device: D, _state: S, config: UARTConfig, - effective_baudrate: Baud + effective_baudrate: Baud, } impl UARTPeripheral { @@ -177,21 +164,23 @@ impl UARTPeripheral { device: self.device, config: self.config, effective_baudrate: self.effective_baudrate, - _state: state + _state: state, } } /// Releases the underlying device. - pub fn free(self) -> D{ + 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> { - + 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 @@ -216,16 +205,17 @@ impl UARTPeripheral { }); Ok(UARTPeripheral { - device, config, effective_baudrate, _state: Enabled + 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(); @@ -238,11 +228,11 @@ impl UARTPeripheral { } pub(crate) fn transmit_flushed(&self) -> nb::Result<(), Infallible> { - if self.device.uartfr.read().txfe().bit_is_set() { Ok(()) + } else { + Err(WouldBlock) } - else { Err(WouldBlock) } } fn uart_is_writable(&self) -> bool { @@ -258,18 +248,15 @@ impl UARTPeripheral { /// - 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_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; for c in data { - if !self.uart_is_writable() { if bytes_written == 0 { - return Err(WouldBlock) - } - else { - return Ok(&data[bytes_written..]) + return Err(WouldBlock); + } else { + return Ok(&data[bytes_written..]); } } @@ -280,7 +267,7 @@ impl UARTPeripheral { bytes_written += 1; } - return Ok(&data[bytes_written..]) + return Ok(&data[bytes_written..]); } /// Reads bytes from the UART. @@ -289,21 +276,18 @@ impl UARTPeripheral { /// - some bytes were read, it is deemed to be a success /// Upon success, the number of read bytes is returned. pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], ReadError<'b>> { - 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..] + return Err(WouldBlock); + } else { + break &mut buffer[bytes_read..]; } } if bytes_read < buffer.len() { - let mut error: Option = None; if self.device.uartdr.read().oe().bit_is_set() { @@ -324,15 +308,15 @@ impl UARTPeripheral { if let Some(err_type) = error { return Err(Other(ReadError { - err_type, discared: buffer + err_type, + discared: buffer, })); } buffer[bytes_read] = self.device.uartdr.read().data().bits(); bytes_read += 1; - } - else { - break &mut buffer[bytes_read..] + } else { + break &mut buffer[bytes_read..]; } }) } @@ -340,14 +324,13 @@ impl UARTPeripheral { /// 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_raw(temp) { Ok(remaining) => remaining, Err(WouldBlock) => continue, - Err(_) => unreachable!() + Err(_) => unreachable!(), } } } @@ -359,37 +342,42 @@ impl UARTPeripheral { while offset != buffer.len() { offset += match self.read_raw(&mut buffer[offset..]) { - Ok(remaining) => { remaining.len() }, + Ok(remaining) => remaining.len(), Err(WouldBlock) => continue, - Err(_) => unreachable!() + Err(_) => unreachable!(), } } } } /// Baudrate dividers calculation. Code inspired from the C SDK. -fn calculate_baudrate_dividers(wanted_baudrate: &Baud, frequency: &Hertz) -> Result<(u16, u16), Error> { - +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 = 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) + (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 { - +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 @@ -404,39 +392,45 @@ fn configure_baudrate(device: &mut dyn UARTDevice, wanted_baudrate: &Baud, frequ // 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 }); + device.uartlcr_h.modify(|_, w| w); - Ok(Baud((4 * *frequency.integer()) / (64 * baud_ibrd + baud_fbrd) as u32)) + 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 { - +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() + Parity::Even => w.eps().set_bit(), }; - }, - None => { w.pen().bit(false); } + } + None => { + w.pen().bit(false); + } }; - unsafe { w.wlen().bits( - match data_bits { - DataBits::Five => { 0b00 } - DataBits::Six => { 0b01 } - DataBits::Seven => { 0b10 } - DataBits::Eight => { 0b11 } - } - ) + 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() + StopBits::Two => w.stp2().set_bit(), }; w @@ -446,13 +440,11 @@ impl Read for UARTPeripheral { type Error = Infallible; fn read(&mut self) -> nb::Result { - let byte: &mut [u8] = &mut [0; 1]; if let Err(_) = self.read_raw(byte) { Err(WouldBlock) - } - else { + } else { Ok(byte[0]) } } @@ -464,8 +456,7 @@ impl Write for UARTPeripheral { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { if let Err(_) = self.write_raw(&[word]) { Err(WouldBlock) - } - else { + } else { Ok(()) } } From 8d29464ee309e8875df04fe48372e466e0c30c12 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 2 May 2021 09:04:05 +0200 Subject: [PATCH 11/19] Propagate read errors. --- rp2040-hal/src/uart.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 9dfc4bf..d0208f1 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -337,16 +337,20 @@ impl UARTPeripheral { /// Reads bytes from the UART. /// This function blocks until the full buffer has been received. - pub fn read_full_blocking(&self, buffer: &mut [u8]) { + pub fn read_full_blocking(&self, buffer: &mut [u8]) -> Result<(), ReadErrorType> { let mut offset = 0; while offset != buffer.len() { offset += match self.read_raw(&mut buffer[offset..]) { Ok(remaining) => remaining.len(), - Err(WouldBlock) => continue, - Err(_) => unreachable!(), + Err(e) => match e { + Other(inner) => return Err(inner.err_type), + WouldBlock => continue, + }, } } + + Ok(()) } } @@ -437,15 +441,17 @@ fn set_format<'w>( } impl Read for UARTPeripheral { - type Error = Infallible; + type Error = ReadErrorType; fn read(&mut self) -> nb::Result { let byte: &mut [u8] = &mut [0; 1]; - if let Err(_) = self.read_raw(byte) { - Err(WouldBlock) - } else { - Ok(byte[0]) + match self.read_raw(byte) { + Ok(_) => Ok(byte[0]), + Err(e) => match e { + Other(inner) => return Err(Other(inner.err_type)), + WouldBlock => return Err(WouldBlock), + }, } } } From d9b1b2b1ec77d8a26fb351be6add2cd981d362c3 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Tue, 4 May 2021 19:48:40 +0200 Subject: [PATCH 12/19] Fix comments on {read,write}_raw() functions --- rp2040-hal/src/uart.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index d0208f1..b6dbee9 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -247,7 +247,7 @@ impl UARTPeripheral { /// 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. + /// Upon success, the remaining slice is returned. pub fn write_raw<'d>(&self, data: &'d [u8]) -> nb::Result<&'d [u8], Infallible> { let mut bytes_written = 0; @@ -274,7 +274,7 @@ impl UARTPeripheral { /// 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. + /// Upon success, the remaining slice is returned. pub fn read_raw<'b>(&self, buffer: &'b mut [u8]) -> nb::Result<&'b mut [u8], ReadError<'b>> { let mut bytes_read = 0; From ac2af7582ee4503d7db4b96996bfa1b16cc99919 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Tue, 4 May 2021 19:54:15 +0200 Subject: [PATCH 13/19] Pulling the integer out of the frequency first. --- rp2040-hal/src/uart.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index b6dbee9..888cdb5 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -360,13 +360,11 @@ fn calculate_baudrate_dividers( 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())) + let baudrate_div = frequency.integer() + .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), From be78a5c792bb5c073aa7966a51ebb155461eeb90 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Tue, 4 May 2021 19:56:36 +0200 Subject: [PATCH 14/19] Consistency re. clear_bit/set_bit. --- rp2040-hal/src/uart.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 888cdb5..5acaca8 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -412,7 +412,7 @@ fn set_format<'w>( Some(p) => { w.pen().set_bit(); match p { - Parity::Odd => w.eps().bit(false), + Parity::Odd => w.eps().clear_bit(), Parity::Even => w.eps().set_bit(), }; } @@ -431,7 +431,7 @@ fn set_format<'w>( }; match stop_bits { - StopBits::One => w.stp2().bit(false), + StopBits::One => w.stp2().clear_bit(), StopBits::Two => w.stp2().set_bit(), }; From 8586f98c02bfe95893dc534f87d789f9ca2a9840 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Tue, 4 May 2021 22:16:04 +0200 Subject: [PATCH 15/19] Better comments and renamed variable names for more clarity. --- rp2040-hal/src/uart.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 5acaca8..7ffb553 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -354,7 +354,9 @@ impl UARTPeripheral { } } -/// Baudrate dividers calculation. Code inspired from the C SDK. +/// The PL011 (PrimeCell UART) supports a fractional baud rate divider +/// From the wanted baudrate, we calculate the divider's two parts: integer and fractional parts. +/// Code inspired from the C SDK. fn calculate_baudrate_dividers( wanted_baudrate: &Baud, frequency: &Hertz, @@ -368,9 +370,9 @@ fn calculate_baudrate_dividers( Ok(match (baudrate_div >> 7, ((baudrate_div & 0x7F) + 1) / 2) { (0, _) => (1, 0), - (ibrd, _) if ibrd >= 65535 => (65535, 0), + (int_part, _) if int_part >= 65535 => (65535, 0), - (ibrd, fbrd) => (ibrd as u16, fbrd as u16), + (int_part, frac_part) => (int_part as u16, frac_part as u16), }) } @@ -380,15 +382,17 @@ fn configure_baudrate( wanted_baudrate: &Baud, frequency: &Hertz, ) -> Result { - let (baud_ibrd, baud_fbrd) = calculate_baudrate_dividers(wanted_baudrate, frequency)?; + let (baud_div_int, baud_div_frac) = calculate_baudrate_dividers(wanted_baudrate, frequency)?; - // Load PL011's baud divisor registers + // First we load the integer part of the divider. device.uartibrd.write(|w| unsafe { - w.baud_divint().bits(baud_ibrd as u16); + w.baud_divint().bits(baud_div_int as u16); w }); + + // Then we load the fractional part of the divider. device.uartfbrd.write(|w| unsafe { - w.baud_divfrac().bits(baud_fbrd as u8); + w.baud_divfrac().bits(baud_div_frac as u8); w }); @@ -397,7 +401,7 @@ fn configure_baudrate( device.uartlcr_h.modify(|_, w| w); Ok(Baud( - (4 * *frequency.integer()) / (64 * baud_ibrd + baud_fbrd) as u32, + (4 * *frequency.integer()) / (64 * baud_div_int + baud_div_frac) as u32, )) } From 72127aa8e7b41e50f06e5a71c4ff2395fddd79ff Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Wed, 5 May 2021 12:48:40 +1000 Subject: [PATCH 16/19] Remove duplicate entry in Cargo.toml Remove accidental duplication of embedded-time dependency introduced when performing merge-conflict resolution --- rp2040-hal/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 0209b96..9fbe9cb 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -15,7 +15,6 @@ embedded-hal = { version = "0.2.4", features = ["unproven"] } embedded-time = "0.10.1" nb = "1.0.0" rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } -embedded-time = "0.10.1" [dev-dependencies] cortex-m-rt = "0.6.13" From c35358f475ea02428952079f6ad901cdd048d928 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Wed, 5 May 2021 08:02:53 +0200 Subject: [PATCH 17/19] Change comment on baudrate calculation --- rp2040-hal/src/uart.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 7ffb553..0de5dc5 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -361,7 +361,8 @@ fn calculate_baudrate_dividers( wanted_baudrate: &Baud, frequency: &Hertz, ) -> Result<(u16, u16), Error> { - // baudrate_div = frequency * 8 / wanted_baudrate + // See Chapter 4, Section 2 §7.1 from the datasheet for an explanation of how baudrate is + // calculated let baudrate_div = frequency.integer() .checked_mul(8) .and_then(|r| r.checked_div(*wanted_baudrate.integer())) From 020c9d9a3de9057ee2b79be40e00e24bcec4101d Mon Sep 17 00:00:00 2001 From: Nic0w Date: Wed, 5 May 2021 08:06:47 +0200 Subject: [PATCH 18/19] cargo clippy & fmt --- rp2040-hal/src/uart.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index 0de5dc5..ee44a04 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -267,7 +267,7 @@ impl UARTPeripheral { bytes_written += 1; } - return Ok(&data[bytes_written..]); + Ok(&data[bytes_written..]) } /// Reads bytes from the UART. @@ -363,7 +363,8 @@ fn calculate_baudrate_dividers( ) -> Result<(u16, u16), Error> { // See Chapter 4, Section 2 §7.1 from the datasheet for an explanation of how baudrate is // calculated - let baudrate_div = frequency.integer() + let baudrate_div = frequency + .integer() .checked_mul(8) .and_then(|r| r.checked_div(*wanted_baudrate.integer())) .ok_or(Error::BadArgument)?; @@ -452,8 +453,8 @@ impl Read for UARTPeripheral { match self.read_raw(byte) { Ok(_) => Ok(byte[0]), Err(e) => match e { - Other(inner) => return Err(Other(inner.err_type)), - WouldBlock => return Err(WouldBlock), + Other(inner) => Err(Other(inner.err_type)), + WouldBlock => Err(WouldBlock), }, } } @@ -463,7 +464,7 @@ impl Write for UARTPeripheral { type Error = Infallible; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { - if let Err(_) = self.write_raw(&[word]) { + if self.write_raw(&[word]).is_err() { Err(WouldBlock) } else { Ok(()) From 9b082b012d98bc6de4577f461eeb8fb33f04a9b0 Mon Sep 17 00:00:00 2001 From: Nic0w Date: Sun, 9 May 2021 09:53:22 +0200 Subject: [PATCH 19/19] Clippy, second pass for errors in CI. --- rp2040-hal/src/uart.rs | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/rp2040-hal/src/uart.rs b/rp2040-hal/src/uart.rs index ee44a04..868db57 100644 --- a/rp2040-hal/src/uart.rs +++ b/rp2040-hal/src/uart.rs @@ -51,10 +51,10 @@ pub enum ReadErrorType { pub trait State {} /// Trait to handle both underlying devices (UART0 & UART1) -pub trait UARTDevice: Deref {} +pub trait UartDevice: Deref {} -impl UARTDevice for UART0 {} -impl UARTDevice for UART1 {} +impl UartDevice for UART0 {} +impl UartDevice for UART1 {} /// UART is enabled. pub struct Enabled; @@ -97,7 +97,7 @@ pub enum Parity { } /// A struct holding the configuration for an UART device. -pub struct UARTConfig { +pub struct UartConfig { baudrate: Baud, data_bits: DataBits, stop_bits: StopBits, @@ -106,11 +106,11 @@ pub struct UARTConfig { /// Common configurations for UART. pub mod common_configs { - use super::{DataBits, StopBits, UARTConfig}; + 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 { + pub const _9600_8_N_1: UartConfig = UartConfig { baudrate: Baud(9600), data_bits: DataBits::Eight, stop_bits: StopBits::One, @@ -118,7 +118,7 @@ pub mod common_configs { }; /// 19200 baud, 8 data bits, no parity, 1 stop bit - pub const _19200_8_N_1: UARTConfig = UARTConfig { + pub const _19200_8_N_1: UartConfig = UartConfig { baudrate: Baud(19200), data_bits: DataBits::Eight, stop_bits: StopBits::One, @@ -126,7 +126,7 @@ pub mod common_configs { }; /// 38400 baud, 8 data bits, no parity, 1 stop bit - pub const _38400_8_N_1: UARTConfig = UARTConfig { + pub const _38400_8_N_1: UartConfig = UartConfig { baudrate: Baud(38400), data_bits: DataBits::Eight, stop_bits: StopBits::One, @@ -134,7 +134,7 @@ pub mod common_configs { }; /// 57600 baud, 8 data bits, no parity, 1 stop bit - pub const _57600_8_N_1: UARTConfig = UARTConfig { + pub const _57600_8_N_1: UartConfig = UartConfig { baudrate: Baud(57600), data_bits: DataBits::Eight, stop_bits: StopBits::One, @@ -142,7 +142,7 @@ pub mod common_configs { }; /// 115200 baud, 8 data bits, no parity, 1 stop bit - pub const _115200_8_N_1: UARTConfig = UARTConfig { + pub const _115200_8_N_1: UartConfig = UartConfig { baudrate: Baud(115200), data_bits: DataBits::Eight, stop_bits: StopBits::One, @@ -151,16 +151,16 @@ pub mod common_configs { } /// An UART Peripheral based on an underlying UART device. -pub struct UARTPeripheral { +pub struct UartPeripheral { device: D, _state: S, - config: UARTConfig, + config: UartConfig, effective_baudrate: Baud, } -impl UARTPeripheral { - fn transition(self, state: To) -> UARTPeripheral { - UARTPeripheral { +impl UartPeripheral { + fn transition(self, state: To) -> UartPeripheral { + UartPeripheral { device: self.device, config: self.config, effective_baudrate: self.effective_baudrate, @@ -174,13 +174,13 @@ impl UARTPeripheral { } } -impl UARTPeripheral { +impl UartPeripheral { /// Enables the provided UART device with the given configuration. pub fn enable( mut device: D, - config: UARTConfig, + config: UartConfig, frequency: Hertz, - ) -> Result, Error> { + ) -> Result, Error> { let effective_baudrate = configure_baudrate(&mut device, &config.baudrate, &frequency)?; // Enable the UART, both TX and RX @@ -204,7 +204,7 @@ impl UARTPeripheral { w }); - Ok(UARTPeripheral { + Ok(UartPeripheral { device, config, effective_baudrate, @@ -213,9 +213,9 @@ impl UARTPeripheral { } } -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(); @@ -380,7 +380,7 @@ fn calculate_baudrate_dividers( /// Baudrate configuration. Code loosely inspired from the C SDK. fn configure_baudrate( - device: &mut dyn UARTDevice, + device: &mut dyn UartDevice, wanted_baudrate: &Baud, frequency: &Hertz, ) -> Result { @@ -444,7 +444,7 @@ fn set_format<'w>( w } -impl Read for UARTPeripheral { +impl Read for UartPeripheral { type Error = ReadErrorType; fn read(&mut self) -> nb::Result { @@ -460,7 +460,7 @@ impl Read for UARTPeripheral { } } -impl Write for UARTPeripheral { +impl Write for UartPeripheral { type Error = Infallible; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {