Overhaul UART to support single wire transmitters/receivers (#164)

* overhaul UART to support single wire trasimitters/receivers

* add missing methods for uart transmitter/receiver

* fix `uart_config_t`'s `source_clk` being part of a union in `esp-idf v4.x`

* add `esp32c2`'s `PLL F40M` `APB` clock

* revert `uart_wait_tx_done` to timeout of 0

* fix incorrect order in `uart_driver_install`, `rx_buffer` shou always exceed `UART_FIFO_SIZE`

* Refactor `Owner` enum

* Fix double drop on `into_split`

* Add missing `count` methods for the UART drivers, change their return to be able to fit the maximum allowed value, don't run `drop` on temporary internal borrows, update example
This commit is contained in:
Ronen Ulanovsky 2022-11-19 15:10:43 +02:00 committed by GitHub
parent 01246762f1
commit 3f532d7224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 484 additions and 119 deletions

View File

@ -24,7 +24,7 @@ fn main() -> anyhow::Result<()> {
println!("Starting UART loopback test");
let config = config::Config::new().baudrate(Hertz(115_200));
let mut uart = UartDriver::new(
let uart = UartDriver::new(
peripherals.uart1,
tx,
rx,

View File

@ -38,7 +38,9 @@
//! - Address errata 3.17: UART fifo_cnt is inconsistent with FIFO pointer
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ptr;
use core::sync::atomic::{AtomicU8, Ordering};
use crate::delay::NON_BLOCK;
use crate::gpio::*;
@ -48,7 +50,7 @@ use esp_idf_sys::*;
use crate::peripheral::Peripheral;
const UART_FIFO_SIZE: i32 = 128;
const UART_FIFO_SIZE: i32 = SOC_UART_FIFO_LEN as i32;
pub type UartConfig = config::Config;
@ -189,6 +191,113 @@ pub mod config {
}
}
/// UART source clock
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum SourceClock {
/// UART source clock from `APB`
#[cfg(any(
esp_idf_soc_uart_support_apb_clk,
esp_idf_soc_uart_support_pll_f40m_clk,
esp_idf_version_major = "4",
))]
APB,
/// UART source clock from `RTC`
#[cfg(esp_idf_soc_uart_support_rtc_clk)]
RTC,
/// UART source clock from `XTAL`
#[cfg(esp_idf_soc_uart_support_xtal_clk)]
Crystal,
/// UART source clock from `REF_TICK`
#[cfg(esp_idf_soc_uart_support_ref_tick)]
RefTick,
}
impl SourceClock {
#[cfg(not(esp_idf_version_major = "4"))]
pub fn frequency(self) -> Result<Hertz, EspError> {
let mut frequency: u32 = 0;
esp_result! {
unsafe { uart_get_sclk_freq(self.into(), &mut frequency) },
Hertz(frequency)
}
}
}
#[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_apb_clk))]
const APB_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_APB;
#[cfg(all(
not(esp_idf_version_major = "4"),
not(esp_idf_soc_uart_support_apb_clk),
esp_idf_soc_uart_support_pll_f40m_clk,
))]
const APB_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_PLL_F40M;
#[cfg(esp_idf_version_major = "4")]
const APB_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_APB;
#[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_rtc_clk))]
const RTC_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_RTC;
#[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_rtc_clk))]
const RTC_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_RTC;
#[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_xtal_clk))]
const XTAL_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_XTAL;
#[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_xtal_clk))]
const XTAL_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_XTAL;
#[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_ref_tick))]
const REF_TICK_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_REF_TICK;
#[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_ref_tick))]
const REF_TICK_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_REF_TICK;
impl Default for SourceClock {
fn default() -> Self {
#[cfg(not(esp_idf_version_major = "4"))]
const DEFAULT: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_DEFAULT;
#[cfg(esp_idf_version_major = "4")]
const DEFAULT: uart_sclk_t = uart_sclk_t_UART_SCLK_APB;
Self::from(DEFAULT)
}
}
impl From<SourceClock> for uart_sclk_t {
fn from(source_clock: SourceClock) -> Self {
match source_clock {
#[cfg(any(
esp_idf_soc_uart_support_apb_clk,
esp_idf_soc_uart_support_pll_f40m_clk,
esp_idf_version_major = "4",
))]
SourceClock::APB => APB_SCLK,
#[cfg(esp_idf_soc_uart_support_rtc_clk)]
SourceClock::RTC => RTC_SCLK,
#[cfg(esp_idf_soc_uart_support_xtal_clk)]
SourceClock::Crystal => XTAL_SCLK,
#[cfg(esp_idf_soc_uart_support_ref_tick)]
SourceClock::RefTick => REF_TICK_SCLK,
}
}
}
impl From<uart_sclk_t> for SourceClock {
fn from(source_clock: uart_sclk_t) -> Self {
match source_clock {
#[cfg(any(
esp_idf_soc_uart_support_apb_clk,
esp_idf_soc_uart_support_pll_f40m_clk,
esp_idf_version_major = "4",
))]
APB_SCLK => SourceClock::APB,
#[cfg(esp_idf_soc_uart_support_rtc_clk)]
RTC_SCLK => SourceClock::RTC,
#[cfg(esp_idf_soc_uart_support_xtal_clk)]
XTAL_SCLK => SourceClock::Crystal,
#[cfg(esp_idf_soc_uart_support_ref_tick)]
REF_TICK_SCLK => SourceClock::RefTick,
_ => unreachable!(),
}
}
}
/// UART configuration
#[derive(Debug, Copy, Clone)]
pub struct Config {
@ -198,6 +307,7 @@ pub mod config {
pub stop_bits: StopBits,
pub flow_control: FlowControl,
pub flow_control_rts_threshold: u8,
pub source_clock: SourceClock,
}
impl Config {
@ -255,6 +365,12 @@ pub mod config {
self.flow_control_rts_threshold = flow_control_rts_threshold;
self
}
#[must_use]
pub fn source_clock(mut self, source_clock: SourceClock) -> Self {
self.source_clock = source_clock;
self
}
}
impl Default for Config {
@ -266,6 +382,7 @@ pub mod config {
stop_bits: StopBits::STOP1,
flow_control: FlowControl::None,
flow_control_rts_threshold: 122,
source_clock: SourceClock::default(),
}
}
}
@ -282,7 +399,6 @@ crate::embedded_hal_error!(
);
/// Serial abstraction
///
pub struct UartDriver<'d> {
port: u8,
_p: PhantomData<&'d mut ()>,
@ -291,62 +407,28 @@ pub struct UartDriver<'d> {
/// Serial receiver
pub struct UartRxDriver<'d> {
port: u8,
owner: Owner,
_p: PhantomData<&'d mut ()>,
}
/// Serial transmitter
pub struct UartTxDriver<'d> {
port: u8,
owner: Owner,
_p: PhantomData<&'d mut ()>,
}
impl<'d> UartDriver<'d> {
/// Create a new serial driver
pub fn new<UART: Uart>(
_uart: impl Peripheral<P = UART> + 'd,
uart: impl Peripheral<P = UART> + 'd,
tx: impl Peripheral<P = impl OutputPin> + 'd,
rx: impl Peripheral<P = impl InputPin> + 'd,
cts: Option<impl Peripheral<P = impl InputPin> + 'd>,
rts: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: &config::Config,
) -> Result<Self, EspError> {
crate::into_ref!(tx, rx);
let cts = cts.map(|cts| cts.into_ref());
let rts = rts.map(|rts| rts.into_ref());
let uart_config = uart_config_t {
baud_rate: config.baudrate.0 as i32,
data_bits: config.data_bits.into(),
parity: config.parity.into(),
stop_bits: config.stop_bits.into(),
flow_ctrl: config.flow_control.into(),
rx_flow_ctrl_thresh: config.flow_control_rts_threshold,
..Default::default()
};
esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?;
esp!(unsafe {
uart_set_pin(
UART::port(),
tx.pin(),
rx.pin(),
rts.as_ref().map_or(-1, |p| p.pin()),
cts.as_ref().map_or(-1, |p| p.pin()),
)
})?;
esp!(unsafe {
uart_driver_install(
UART::port(),
UART_FIFO_SIZE * 2,
UART_FIFO_SIZE * 2,
0,
ptr::null_mut(),
0,
)
})?;
new_common(uart, Some(tx), Some(rx), cts, rts, config)?;
Ok(Self {
port: UART::port() as _,
@ -355,51 +437,33 @@ impl<'d> UartDriver<'d> {
}
/// Change the number of stop bits
pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_stop_bits(self.port(), stop_bits.into()) },
self
)
pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> {
change_stop_bits(self.port(), stop_bits).map(|_| self)
}
/// Retruns the current number of stop bits
/// Returns the current number of stop bits
pub fn stop_bits(&self) -> Result<config::StopBits, EspError> {
let mut stop_bits: uart_stop_bits_t = 0;
esp_result!(
unsafe { uart_get_stop_bits(self.port(), &mut stop_bits) },
stop_bits.into()
)
stop_bits(self.port())
}
/// Change the number of data bits
pub fn change_data_bits(&mut self, data_bits: config::DataBits) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_word_length(self.port(), data_bits.into()) },
self
)
pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> {
change_data_bits(self.port(), data_bits).map(|_| self)
}
/// Return the current number of data bits
pub fn data_bits(&self) -> Result<config::DataBits, EspError> {
let mut data_bits: uart_word_length_t = 0;
esp_result!(
unsafe { uart_get_word_length(self.port(), &mut data_bits) },
data_bits.into()
)
data_bits(self.port())
}
/// Change the type of parity checking
pub fn change_parity(&mut self, parity: config::Parity) -> Result<&mut Self, EspError> {
esp_result!(unsafe { uart_set_parity(self.port(), parity.into()) }, self)
pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> {
change_parity(self.port(), parity).map(|_| self)
}
/// Returns the current type of parity checking
pub fn parity(&self) -> Result<config::Parity, EspError> {
let mut parity: uart_parity_t = 0;
esp_result!(
unsafe { uart_get_parity(self.port(), &mut parity) },
parity.into()
)
parity(self.port())
}
/// Change the baudrate.
@ -409,54 +473,67 @@ impl<'d> UartDriver<'d> {
/// However if one of the clock frequencies is below 10MHz or if the baudrate is above
/// the reference clock or if the baudrate cannot be set within 1.5%
/// then use the APB clock.
pub fn change_baudrate<T: Into<Hertz> + Copy>(
&mut self,
baudrate: T,
) -> Result<&mut Self, EspError> {
esp_result!(
unsafe { uart_set_baudrate(self.port(), baudrate.into().into()) },
self
)
pub fn change_baudrate<T: Into<Hertz> + Copy>(&self, baudrate: T) -> Result<&Self, EspError> {
change_baudrate(self.port(), baudrate).map(|_| self)
}
/// Returns the current baudrate
pub fn baudrate(&self) -> Result<Hertz, EspError> {
let mut baudrate: u32 = 0;
esp_result!(
unsafe { uart_get_baudrate(self.port(), &mut baudrate) },
baudrate.into()
)
baudrate(self.port())
}
/// Split the serial driver in separate TX and RX drivers
pub fn split(&mut self) -> (UartTxDriver<'_>, UartRxDriver<'_>) {
pub fn split(&self) -> (UartTxDriver<'_>, UartRxDriver<'_>) {
(
UartTxDriver {
port: self.port() as _,
port: self.port,
owner: Owner::Borrowed,
_p: PhantomData,
},
UartRxDriver {
port: self.port() as _,
port: self.port,
owner: Owner::Borrowed,
_p: PhantomData,
},
)
}
/// Split the serial driver in separate TX and RX drivers.
///
/// Unlike [`split`], the halves are owned and reference counted.
pub fn into_split(self) -> (UartTxDriver<'d>, UartRxDriver<'d>) {
let port = self.port;
let _ = ManuallyDrop::new(self);
REFS[port as usize].fetch_add(2, Ordering::SeqCst);
(
UartTxDriver {
port,
owner: Owner::Shared,
_p: PhantomData,
},
UartRxDriver {
port,
owner: Owner::Shared,
_p: PhantomData,
},
)
}
/// Read multiple bytes into a slice
pub fn read(&mut self, buf: &mut [u8], delay: TickType_t) -> Result<usize, EspError> {
pub fn read(&self, buf: &mut [u8], delay: TickType_t) -> Result<usize, EspError> {
self.rx().read(buf, delay)
}
/// Write multiple bytes from a slice
pub fn write(&mut self, buf: &[u8]) -> Result<usize, EspError> {
pub fn write(&self, buf: &[u8]) -> Result<usize, EspError> {
self.tx().write(buf)
}
pub fn flush_read(&mut self) -> Result<(), EspError> {
pub fn flush_read(&self) -> Result<(), EspError> {
self.rx().flush()
}
pub fn flush_write(&mut self) -> Result<(), EspError> {
pub fn flush_write(&self) -> Result<(), EspError> {
self.tx().flush()
}
@ -464,29 +541,39 @@ impl<'d> UartDriver<'d> {
self.port as _
}
fn rx(&mut self) -> UartRxDriver<'_> {
UartRxDriver {
port: self.port() as _,
_p: PhantomData,
}
/// Get count of remaining bytes in the receive ring buffer
pub fn remaining_read(&self) -> Result<u32, EspError> {
remaining_unread_bytes(self.port())
}
fn tx(&mut self) -> UartTxDriver<'_> {
UartTxDriver {
port: self.port() as _,
/// Get count of remaining capacity in the transmit ring buffer
pub fn remaining_write(&self) -> Result<u32, EspError> {
remaining_write_capacity(self.port())
}
fn rx(&self) -> ManuallyDrop<UartRxDriver<'_>> {
ManuallyDrop::new(UartRxDriver {
port: self.port,
owner: Owner::Borrowed,
_p: PhantomData,
}
})
}
fn tx(&self) -> ManuallyDrop<UartTxDriver<'_>> {
ManuallyDrop::new(UartTxDriver {
port: self.port,
owner: Owner::Borrowed,
_p: PhantomData,
})
}
}
impl<'d> Drop for UartDriver<'d> {
fn drop(&mut self) {
esp!(unsafe { uart_driver_delete(self.port()) }).unwrap();
delete_driver(self.port()).unwrap();
}
}
unsafe impl<'d> Send for UartDriver<'d> {}
impl<'d> embedded_hal::serial::ErrorType for UartDriver<'d> {
type Error = SerialError;
}
@ -495,13 +582,13 @@ impl<'d> embedded_hal_0_2::serial::Read<u8> for UartDriver<'d> {
type Error = SerialError;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
embedded_hal_0_2::serial::Read::read(&mut self.rx())
embedded_hal_0_2::serial::Read::read(&mut *self.rx())
}
}
impl<'d> embedded_hal_nb::serial::Read<u8> for UartDriver<'d> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
embedded_hal_nb::serial::Read::read(&mut self.rx())
embedded_hal_nb::serial::Read::read(&mut *self.rx())
}
}
@ -509,21 +596,21 @@ impl<'d> embedded_hal_0_2::serial::Write<u8> for UartDriver<'d> {
type Error = SerialError;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
embedded_hal_0_2::serial::Write::flush(&mut self.tx())
embedded_hal_0_2::serial::Write::flush(&mut *self.tx())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
embedded_hal_0_2::serial::Write::write(&mut self.tx(), byte)
embedded_hal_0_2::serial::Write::write(&mut *self.tx(), byte)
}
}
impl<'d> embedded_hal_nb::serial::Write<u8> for UartDriver<'d> {
fn flush(&mut self) -> nb::Result<(), Self::Error> {
embedded_hal_nb::serial::Write::flush(&mut self.tx())
embedded_hal_nb::serial::Write::flush(&mut *self.tx())
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
embedded_hal_nb::serial::Write::write(&mut self.tx(), byte)
embedded_hal_nb::serial::Write::write(&mut *self.tx(), byte)
}
}
@ -538,17 +625,71 @@ impl<'d> embedded_hal::serial::ErrorType for UartRxDriver<'d> {
}
impl<'d> UartRxDriver<'d> {
/// Get count of bytes in the receive FIFO
pub fn count(&self) -> Result<u8, EspError> {
let mut size = 0_u32;
esp_result!(
unsafe { uart_get_buffered_data_len(self.port(), &mut size) },
size as u8
)
/// Create a new serial receiver
pub fn new<UART: Uart>(
uart: impl Peripheral<P = UART> + 'd,
rx: impl Peripheral<P = impl InputPin> + 'd,
cts: Option<impl Peripheral<P = impl InputPin> + 'd>,
rts: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: &config::Config,
) -> Result<Self, EspError> {
new_common(uart, None::<AnyOutputPin>, Some(rx), cts, rts, config)?;
Ok(Self {
port: UART::port() as _,
owner: Owner::Owned,
_p: PhantomData,
})
}
/// Change the number of stop bits
pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> {
change_stop_bits(self.port(), stop_bits).map(|_| self)
}
/// Returns the current number of stop bits
pub fn stop_bits(&self) -> Result<config::StopBits, EspError> {
stop_bits(self.port())
}
/// Change the number of data bits
pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> {
change_data_bits(self.port(), data_bits).map(|_| self)
}
/// Return the current number of data bits
pub fn data_bits(&self) -> Result<config::DataBits, EspError> {
data_bits(self.port())
}
/// Change the type of parity checking
pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> {
change_parity(self.port(), parity).map(|_| self)
}
/// Returns the current type of parity checking
pub fn parity(&self) -> Result<config::Parity, EspError> {
parity(self.port())
}
/// Change the baudrate.
///
/// Will automatically select the clock source. When possible the reference clock (1MHz) will
/// be used, because this is constant when the clock source/frequency changes.
/// However if one of the clock frequencies is below 10MHz or if the baudrate is above
/// the reference clock or if the baudrate cannot be set within 1.5%
/// then use the APB clock.
pub fn change_baudrate<T: Into<Hertz> + Copy>(&self, baudrate: T) -> Result<&Self, EspError> {
change_baudrate(self.port(), baudrate).map(|_| self)
}
/// Returns the current baudrate
pub fn baudrate(&self) -> Result<Hertz, EspError> {
baudrate(self.port())
}
/// Read multiple bytes into a slice; block until specified timeout
pub fn read(&mut self, buf: &mut [u8], delay: TickType_t) -> Result<usize, EspError> {
pub fn read(&self, buf: &mut [u8], delay: TickType_t) -> Result<usize, EspError> {
// uart_read_bytes() returns error (-1) or how many bytes were read out
// 0 means timeout and nothing is yet read out
let len = unsafe {
@ -576,6 +717,17 @@ impl<'d> UartRxDriver<'d> {
pub fn port(&self) -> uart_port_t {
self.port as _
}
/// Get count of remaining bytes in the receive ring buffer
pub fn count(&self) -> Result<u32, EspError> {
remaining_unread_bytes(self.port())
}
}
impl<'d> Drop for UartRxDriver<'d> {
fn drop(&mut self) {
self.owner.drop_impl(self.port()).unwrap()
}
}
impl<'d> embedded_hal_0_2::serial::Read<u8> for UartRxDriver<'d> {
@ -584,7 +736,7 @@ impl<'d> embedded_hal_0_2::serial::Read<u8> for UartRxDriver<'d> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf = [0_u8];
let result = self.read(&mut buf, NON_BLOCK);
let result = UartRxDriver::read(self, &mut buf, NON_BLOCK);
check_nb(result, buf[0])
}
@ -594,13 +746,76 @@ impl<'d> embedded_hal_nb::serial::Read<u8> for UartRxDriver<'d> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
let mut buf = [0_u8];
let result = self.read(&mut buf, NON_BLOCK);
let result = UartRxDriver::read(self, &mut buf, NON_BLOCK);
check_nb(result, buf[0])
}
}
impl<'d> UartTxDriver<'d> {
/// Create a new serial transmitter
pub fn new<UART: Uart>(
uart: impl Peripheral<P = UART> + 'd,
tx: impl Peripheral<P = impl OutputPin> + 'd,
cts: Option<impl Peripheral<P = impl InputPin> + 'd>,
rts: Option<impl Peripheral<P = impl OutputPin> + 'd>,
config: &config::Config,
) -> Result<Self, EspError> {
new_common(uart, Some(tx), None::<AnyInputPin>, cts, rts, config)?;
Ok(Self {
port: UART::port() as _,
owner: Owner::Owned,
_p: PhantomData,
})
}
/// Change the number of stop bits
pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> {
change_stop_bits(self.port(), stop_bits).map(|_| self)
}
/// Returns the current number of stop bits
pub fn stop_bits(&self) -> Result<config::StopBits, EspError> {
stop_bits(self.port())
}
/// Change the number of data bits
pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> {
change_data_bits(self.port(), data_bits).map(|_| self)
}
/// Return the current number of data bits
pub fn data_bits(&self) -> Result<config::DataBits, EspError> {
data_bits(self.port())
}
/// Change the type of parity checking
pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> {
change_parity(self.port(), parity).map(|_| self)
}
/// Returns the current type of parity checking
pub fn parity(&self) -> Result<config::Parity, EspError> {
parity(self.port())
}
/// Change the baudrate.
///
/// Will automatically select the clock source. When possible the reference clock (1MHz) will
/// be used, because this is constant when the clock source/frequency changes.
/// However if one of the clock frequencies is below 10MHz or if the baudrate is above
/// the reference clock or if the baudrate cannot be set within 1.5%
/// then use the APB clock.
pub fn change_baudrate<T: Into<Hertz> + Copy>(&self, baudrate: T) -> Result<&Self, EspError> {
change_baudrate(self.port(), baudrate).map(|_| self)
}
/// Returns the current baudrate
pub fn baudrate(&self) -> Result<Hertz, EspError> {
baudrate(self.port())
}
/// Write multiple bytes from a slice
pub fn write(&mut self, bytes: &[u8]) -> Result<usize, EspError> {
// `uart_write_bytes()` returns error (-1) or how many bytes were written
@ -624,6 +839,17 @@ impl<'d> UartTxDriver<'d> {
pub fn port(&self) -> uart_port_t {
self.port as _
}
/// Get count of remaining capacity in the transmit ring buffer
pub fn count(&self) -> Result<u32, EspError> {
remaining_write_capacity(self.port())
}
}
impl<'d> Drop for UartTxDriver<'d> {
fn drop(&mut self) {
self.owner.drop_impl(self.port()).unwrap()
}
}
impl<'d> embedded_hal::serial::ErrorType for UartTxDriver<'d> {
@ -638,7 +864,7 @@ impl<'d> embedded_hal_0_2::serial::Write<u8> for UartTxDriver<'d> {
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
check_nb(self.write(&[byte]), ())
check_nb(UartTxDriver::write(self, &[byte]), ())
}
}
@ -648,7 +874,7 @@ impl<'d> embedded_hal_nb::serial::Write<u8> for UartTxDriver<'d> {
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
check_nb(self.write(&[byte]), ())
check_nb(UartTxDriver::write(self, &[byte]), ())
}
}
@ -665,6 +891,141 @@ impl<'d> core::fmt::Write for UartTxDriver<'d> {
}
}
fn new_common<UART: Uart>(
_uart: impl Peripheral<P = UART>,
tx: Option<impl Peripheral<P = impl OutputPin>>,
rx: Option<impl Peripheral<P = impl InputPin>>,
cts: Option<impl Peripheral<P = impl InputPin>>,
rts: Option<impl Peripheral<P = impl OutputPin>>,
config: &config::Config,
) -> Result<(), EspError> {
let tx = tx.map(|tx| tx.into_ref());
let rx = rx.map(|rx| rx.into_ref());
let cts = cts.map(|cts| cts.into_ref());
let rts = rts.map(|rts| rts.into_ref());
#[allow(clippy::needless_update)]
let uart_config = uart_config_t {
baud_rate: config.baudrate.0 as i32,
data_bits: config.data_bits.into(),
parity: config.parity.into(),
stop_bits: config.stop_bits.into(),
flow_ctrl: config.flow_control.into(),
rx_flow_ctrl_thresh: config.flow_control_rts_threshold,
#[cfg(not(esp_idf_version_major = "4"))]
source_clk: config.source_clock.into(),
#[cfg(esp_idf_version_major = "4")]
__bindgen_anon_1: uart_config_t__bindgen_ty_1 {
source_clk: config.source_clock.into(),
},
..Default::default()
};
esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?;
esp!(unsafe {
uart_set_pin(
UART::port(),
tx.as_ref().map_or(-1, |p| p.pin()),
rx.as_ref().map_or(-1, |p| p.pin()),
rts.as_ref().map_or(-1, |p| p.pin()),
cts.as_ref().map_or(-1, |p| p.pin()),
)
})?;
esp!(unsafe {
uart_driver_install(
UART::port(),
UART_FIFO_SIZE * 2,
if tx.is_some() { UART_FIFO_SIZE * 2 } else { 0 },
0,
ptr::null_mut(),
0,
)
})?;
Ok(())
}
fn stop_bits(port: uart_port_t) -> Result<config::StopBits, EspError> {
let mut stop_bits: uart_stop_bits_t = 0;
esp_result!(
unsafe { uart_get_stop_bits(port, &mut stop_bits) },
stop_bits.into()
)
}
fn change_stop_bits(port: uart_port_t, stop_bits: config::StopBits) -> Result<(), EspError> {
esp!(unsafe { uart_set_stop_bits(port, stop_bits.into()) })
}
fn data_bits(port: uart_port_t) -> Result<config::DataBits, EspError> {
let mut data_bits: uart_word_length_t = 0;
esp_result!(
unsafe { uart_get_word_length(port, &mut data_bits) },
data_bits.into()
)
}
fn change_data_bits(port: uart_port_t, data_bits: config::DataBits) -> Result<(), EspError> {
esp!(unsafe { uart_set_word_length(port, data_bits.into()) })
}
fn parity(port: uart_port_t) -> Result<config::Parity, EspError> {
let mut parity: uart_parity_t = 0;
esp_result!(unsafe { uart_get_parity(port, &mut parity) }, parity.into())
}
fn change_parity(port: uart_port_t, parity: config::Parity) -> Result<(), EspError> {
esp!(unsafe { uart_set_parity(port, parity.into()) })
}
fn baudrate(port: uart_port_t) -> Result<Hertz, EspError> {
let mut baudrate: u32 = 0;
esp_result!(
unsafe { uart_get_baudrate(port, &mut baudrate) },
baudrate.into()
)
}
fn change_baudrate<T: Into<Hertz> + Copy>(port: uart_port_t, baudrate: T) -> Result<(), EspError> {
esp!(unsafe { uart_set_baudrate(port, baudrate.into().into()) })
}
fn delete_driver(port: uart_port_t) -> Result<(), EspError> {
esp!(unsafe { uart_driver_delete(port) })
}
pub fn remaining_unread_bytes(port: uart_port_t) -> Result<u32, EspError> {
let mut size = 0_u32;
esp_result!(unsafe { uart_get_buffered_data_len(port, &mut size) }, size)
}
pub fn remaining_write_capacity(port: uart_port_t) -> Result<u32, EspError> {
let mut size = 0_u32;
esp_result!(
unsafe { uart_get_tx_buffer_free_size(port, &mut size) },
size
)
}
enum Owner {
Owned,
Borrowed,
Shared,
}
impl Owner {
fn drop_impl(&self, port: uart_port_t) -> Result<(), EspError> {
let needs_drop = match self {
Owner::Owned => true,
Owner::Borrowed => false,
Owner::Shared => REFS[port as usize].fetch_sub(1, Ordering::SeqCst) == 0,
};
needs_drop.then(|| delete_driver(port)).unwrap_or(Ok(()))
}
}
macro_rules! impl_uart {
($uart:ident: $port:expr) => {
crate::impl_peripheral!($uart);
@ -698,3 +1059,7 @@ impl_uart!(UART0: 0);
impl_uart!(UART1: 1);
#[cfg(any(esp32, esp32s3))]
impl_uart!(UART2: 2);
#[allow(clippy::declare_interior_mutable_const)]
const NO_REFS: AtomicU8 = AtomicU8::new(0);
static REFS: [AtomicU8; UART_NUM_MAX as usize] = [NO_REFS; UART_NUM_MAX as usize];