Extract UART peripheral implementation, prelude into esp-hal-common

This commit is contained in:
Jesse Braham 2021-10-21 17:50:10 -07:00
parent dfab5d6c1b
commit 579c5ba71b
7 changed files with 21 additions and 202 deletions

View File

@ -7,6 +7,9 @@ pub use esp32c3 as pac;
#[cfg(feature = "esp32s2")]
pub use esp32s2 as pac;
pub mod prelude;
pub mod serial;
pub mod timer;
pub use serial::Serial;
pub use timer::Timer;

View File

@ -1,15 +1,8 @@
//! UART Functionality (UART)
//!
//! Reference: ESP32-C3 TRM v0.3 Section 20 (as TRM)
//!
//! The ESP32-C3 has two identical UART groups UART0 and UART1.
//!
//! TODO:
//! - Interrupt support
use embedded_hal::serial::{Read, Write};
use crate::pac::{uart0::RegisterBlock, UART0, UART1, UART2};
#[cfg(feature = "enable-esp32")]
use crate::pac::UART2;
use crate::pac::{uart0::RegisterBlock, UART0, UART1};
const UART_FIFO_SIZE: u16 = 128;
@ -96,12 +89,22 @@ pub trait Instance {
/// Check if the UART TX statemachine is is idle
fn is_tx_idle(&mut self) -> bool {
self.as_uart0().status.read().st_utx_out().bits() == 0x0u8
#[cfg(feature = "enable-esp32")]
let ret = self.as_uart0().status.read().st_utx_out().bits() == 0x0u8;
#[cfg(not(feature = "enable-esp32"))]
let ret = self.as_uart0().fsm_status.read().st_utx_out().bits() == 0x0u8;
ret
}
/// Check if the UART RX statemachine is is idle
fn is_rx_idle(&mut self) -> bool {
self.as_uart0().status.read().st_urx_out().bits() == 0x0u8
#[cfg(feature = "enable-esp32")]
let ret = self.as_uart0().status.read().st_urx_out().bits() == 0x0u8;
#[cfg(not(feature = "enable-esp32"))]
let ret = self.as_uart0().fsm_status.read().st_urx_out().bits() == 0x0u8;
ret
}
}
@ -171,6 +174,7 @@ impl Instance for UART1 {
}
}
#[cfg(feature = "enable-esp32")]
/// Specific instance implementation for the UART2 peripheral
impl Instance for UART2 {
#[inline(always)]

View File

@ -2,12 +2,7 @@
pub use embedded_hal as ehal;
pub use esp32 as pac;
pub use esp_hal_common::Timer;
pub mod prelude;
pub mod serial;
pub use serial::Serial;
pub use esp_hal_common::{prelude, Serial, Timer};
#[no_mangle]
extern "C" fn DefaultHandler(_level: u32, _interrupt: pac::Interrupt) {}

View File

@ -2,11 +2,8 @@
pub use embedded_hal as ehal;
pub use esp32c3 as pac;
pub use esp_hal_common::Timer;
pub use esp_hal_common::{prelude, Serial, Timer};
pub mod prelude;
pub mod rtc_cntl;
pub mod serial;
pub use rtc_cntl::RtcCntl;
pub use serial::Serial;

View File

@ -1,9 +0,0 @@
pub use embedded_hal::{
digital::v2::{
InputPin as _,
OutputPin as _,
StatefulOutputPin as _,
ToggleableOutputPin as _,
},
prelude::*,
};

View File

@ -1,171 +0,0 @@
//! UART Functionality (UART)
//!
//! Reference: ESP32-C3 TRM v0.3 Section 20 (as TRM)
//!
//! The ESP32-C3 has two identical UART groups UART0 and UART1.
//!
//! TODO:
//! - Interrupt support
use embedded_hal::serial::{Read, Write};
use crate::pac::{uart0::RegisterBlock, UART0, UART1};
const UART_FIFO_SIZE: u16 = 128;
/// UART-specific errors
#[derive(Debug)]
pub enum Error {}
/// UART peripheral (UART)
pub struct Serial<T> {
uart: T,
}
impl<T: Instance> Serial<T> {
pub fn new(uart: T) -> Result<Self, Error> {
let mut serial = Serial { uart };
serial.uart.disable_rx_interrupts();
serial.uart.disable_tx_interrupts();
Ok(serial)
}
}
pub trait Instance {
/// Return registerblock of uart instance as if it were UART0
fn as_uart0(&self) -> &RegisterBlock;
/// Clear and disable all tx-related interrupts
fn disable_tx_interrupts(&mut self) {
// Disable UART TX interrupts
self.as_uart0().int_clr.write(|w| {
w.txfifo_empty_int_clr()
.set_bit()
.tx_brk_done_int_clr()
.set_bit()
.tx_brk_idle_done_int_clr()
.set_bit()
.tx_done_int_clr()
.set_bit()
});
self.as_uart0().int_ena.write(|w| {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_brk_done_int_ena()
.clear_bit()
.tx_brk_idle_done_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
}
/// Clear and disable all rx-related interrupts
fn disable_rx_interrupts(&mut self) {
// Disable UART RX interrupts
self.as_uart0().int_clr.write(|w| {
w.rxfifo_full_int_clr()
.set_bit()
.rxfifo_ovf_int_clr()
.set_bit()
.rxfifo_tout_int_clr()
.set_bit()
});
self.as_uart0().int_ena.write(|w| {
w.rxfifo_full_int_ena()
.clear_bit()
.rxfifo_ovf_int_ena()
.clear_bit()
.rxfifo_tout_int_ena()
.clear_bit()
});
}
/// Get the number of occupied entries in the tx fifo buffer
fn get_tx_fifo_count(&mut self) -> u16 {
self.as_uart0().status.read().txfifo_cnt().bits()
}
/// Get the number of occupied entries in the rx fifo buffer
fn get_rx_fifo_count(&mut self) -> u16 {
self.as_uart0().status.read().rxfifo_cnt().bits()
}
/// Check if the UART TX statemachine is is idle
fn is_tx_idle(&mut self) -> bool {
self.as_uart0().fsm_status.read().st_utx_out().bits() == 0x0u8
}
/// Check if the UART RX statemachine is is idle
fn is_rx_idle(&mut self) -> bool {
self.as_uart0().fsm_status.read().st_urx_out().bits() == 0x0u8
}
}
/// Write half of a serial interface
impl<T: Instance> Write<u8> for Serial<T> {
type Error = Error;
/// Writes a single word to the serial interface
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
if self.uart.get_tx_fifo_count() >= UART_FIFO_SIZE {
Err(nb::Error::WouldBlock)
} else {
self.uart
.as_uart0()
.fifo
.write(|w| unsafe { w.rxfifo_rd_byte().bits(word) });
Ok(())
}
}
/// Ensures that none of the previously written words are still buffered
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.uart.is_tx_idle() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
/// Write half of a serial interface
impl<T: Instance> Read<u8> for Serial<T> {
type Error = Error;
/// Reads a single word from the serial interface
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if self.uart.get_rx_fifo_count() > 0 {
Ok(self.uart.as_uart0().fifo.read().rxfifo_rd_byte().bits())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<T: Instance> core::fmt::Write for Serial<T> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
s.as_bytes()
.iter()
.try_for_each(|c| nb::block!(self.write(*c)))
.map_err(|_| core::fmt::Error)
}
}
/// Specific instance implementation for the UART0 peripheral
impl Instance for UART0 {
#[inline(always)]
fn as_uart0(&self) -> &RegisterBlock {
self
}
}
/// Specific instance implementation for the UART1 peripheral
impl Instance for UART1 {
#[inline(always)]
fn as_uart0(&self) -> &RegisterBlock {
self
}
}