crate::unstable_driver! {
#[cfg(uhci_driver_supported)]
pub mod uhci;
}
use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll};
use enumset::{EnumSet, EnumSetType};
use portable_atomic::AtomicBool;
use crate::{
Async,
Blocking,
DriverMode,
asynch::AtomicWaker,
gpio::{
InputConfig,
InputSignal,
OutputConfig,
OutputSignal,
PinGuard,
Pull,
interconnect::{PeripheralInput, PeripheralOutput},
},
handler,
interrupt::InterruptHandler,
pac::uart0::RegisterBlock,
private::DropGuard,
ram,
soc::clocks::{self, ClockTree},
system::PeripheralGuard,
};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum RxError {
FifoOverflowed,
GlitchOccurred,
FrameFormatViolated,
ParityMismatch,
}
impl core::error::Error for RxError {}
impl core::fmt::Display for RxError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
RxError::FifoOverflowed => write!(f, "The RX FIFO overflowed"),
RxError::GlitchOccurred => write!(f, "A glitch was detected on the RX line"),
RxError::FrameFormatViolated => {
write!(f, "A framing error was detected on the RX line")
}
RxError::ParityMismatch => write!(f, "A parity error was detected on the RX line"),
}
}
}
#[instability::unstable]
impl embedded_io_06::Error for RxError {
fn kind(&self) -> embedded_io_06::ErrorKind {
embedded_io_06::ErrorKind::Other
}
}
#[instability::unstable]
impl embedded_io_07::Error for RxError {
fn kind(&self) -> embedded_io_07::ErrorKind {
embedded_io_07::ErrorKind::Other
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum TxError {}
impl core::fmt::Display for TxError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Tx error")
}
}
impl core::error::Error for TxError {}
#[instability::unstable]
impl embedded_io_06::Error for TxError {
fn kind(&self) -> embedded_io_06::ErrorKind {
embedded_io_06::ErrorKind::Other
}
}
#[instability::unstable]
impl embedded_io_07::Error for TxError {
fn kind(&self) -> embedded_io_07::ErrorKind {
embedded_io_07::ErrorKind::Other
}
}
#[instability::unstable]
pub use crate::soc::clocks::UartFunctionClockSclk as ClockSource;
use crate::soc::clocks::{
UartBaudRateGeneratorConfig as BaudRateConfig,
UartFunctionClockConfig as ClockConfig,
};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DataBits {
_5,
_6,
_7,
#[default]
_8,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Parity {
#[default]
None,
Even,
Odd,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum StopBits {
#[default]
_1,
_1p5,
_2,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum SwFlowControl {
#[default]
Disabled,
Enabled {
xon_char: u8,
xoff_char: u8,
xon_threshold: u8,
xoff_threshold: u8,
},
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum CtsConfig {
Enabled,
#[default]
Disabled,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum RtsConfig {
Enabled(u8),
#[default]
Disabled,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub struct HwFlowControl {
pub cts: CtsConfig,
pub rts: RtsConfig,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum BaudrateTolerance {
#[default]
Closest,
Exact,
ErrorPercent(u8),
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct Config {
baudrate: u32,
#[builder_lite(unstable)]
baudrate_tolerance: BaudrateTolerance,
data_bits: DataBits,
parity: Parity,
stop_bits: StopBits,
#[builder_lite(unstable)]
sw_flow_ctrl: SwFlowControl,
#[builder_lite(unstable)]
hw_flow_ctrl: HwFlowControl,
#[builder_lite(unstable)]
clock_source: ClockSource,
rx: RxConfig,
tx: TxConfig,
}
impl Default for Config {
fn default() -> Config {
Config {
rx: RxConfig::default(),
tx: TxConfig::default(),
baudrate: 115_200,
baudrate_tolerance: BaudrateTolerance::default(),
data_bits: Default::default(),
parity: Default::default(),
stop_bits: Default::default(),
sw_flow_ctrl: Default::default(),
hw_flow_ctrl: Default::default(),
clock_source: Default::default(),
}
}
}
impl Config {
fn validate(&self) -> Result<(), ConfigError> {
if let BaudrateTolerance::ErrorPercent(percentage) = self.baudrate_tolerance {
assert!(percentage > 0 && percentage <= 100);
}
if self.baudrate == 0 || self.baudrate > 5_000_000 {
return Err(ConfigError::BaudrateNotSupported);
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct RxConfig {
fifo_full_threshold: u16,
timeout: Option<u8>,
}
impl Default for RxConfig {
fn default() -> RxConfig {
RxConfig {
fifo_full_threshold: 120,
timeout: Some(10),
}
}
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TxConfig {
fifo_empty_threshold: u16,
}
impl Default for TxConfig {
fn default() -> TxConfig {
TxConfig {
fifo_empty_threshold: 10,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
#[non_exhaustive]
pub struct AtCmdConfig {
pre_idle_count: Option<u16>,
post_idle_count: Option<u16>,
gap_timeout: Option<u16>,
cmd_char: u8,
char_num: u8,
}
impl Default for AtCmdConfig {
fn default() -> Self {
Self {
pre_idle_count: None,
post_idle_count: None,
gap_timeout: None,
cmd_char: b'+',
char_num: 1,
}
}
}
struct UartBuilder<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
}
impl<'d, Dm> UartBuilder<'d, Dm>
where
Dm: DriverMode,
{
fn new(uart: impl Instance + 'd) -> Self {
let uart = uart.degrade();
uart.info().rx_signal.connect_to(&crate::gpio::Level::High);
uart.info().cts_signal.connect_to(&crate::gpio::Level::Low);
Self {
uart,
phantom: PhantomData,
}
}
fn init(self, config: Config) -> Result<Uart<'d, Dm>, ConfigError> {
let rx_guard = PeripheralGuard::new(self.uart.info().peripheral);
let tx_guard = PeripheralGuard::new(self.uart.info().peripheral);
let peri_clock_guard = UartClockGuard::new(unsafe { self.uart.clone_unchecked() });
let rts_pin = PinGuard::new_unconnected();
let tx_pin = PinGuard::new_unconnected();
let mut serial = Uart {
rx: UartRx {
uart: unsafe { self.uart.clone_unchecked() },
phantom: PhantomData,
guard: rx_guard,
peri_clock_guard: peri_clock_guard.clone(),
},
tx: UartTx {
uart: self.uart,
phantom: PhantomData,
guard: tx_guard,
peri_clock_guard,
rts_pin,
tx_pin,
baudrate: config.baudrate,
},
};
serial.init(config)?;
Ok(serial)
}
}
#[procmacros::doc_replace]
pub struct Uart<'d, Dm: DriverMode> {
rx: UartRx<'d, Dm>,
tx: UartTx<'d, Dm>,
}
#[instability::unstable]
pub struct UartTx<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
guard: PeripheralGuard,
peri_clock_guard: UartClockGuard<'d>,
rts_pin: PinGuard,
tx_pin: PinGuard,
baudrate: u32,
}
#[instability::unstable]
pub struct UartRx<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
guard: PeripheralGuard,
peri_clock_guard: UartClockGuard<'d>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum ConfigError {
#[cfg(feature = "unstable")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
BaudrateNotAchievable,
BaudrateNotSupported,
#[cfg_attr(esp32, doc = "127")]
#[cfg_attr(not(esp32), doc = "1023")]
TimeoutTooLong,
RxFifoThresholdNotSupported,
TxFifoThresholdNotSupported,
}
impl core::error::Error for ConfigError {}
impl core::fmt::Display for ConfigError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
#[cfg(feature = "unstable")]
ConfigError::BaudrateNotAchievable => {
write!(f, "The requested baud rate is not achievable")
}
ConfigError::BaudrateNotSupported => {
write!(f, "The requested baud rate is not supported")
}
ConfigError::TimeoutTooLong => write!(f, "The requested timeout is not supported"),
ConfigError::RxFifoThresholdNotSupported => {
write!(f, "The requested RX FIFO threshold is not supported")
}
ConfigError::TxFifoThresholdNotSupported => {
write!(f, "The requested TX FIFO threshold is not supported")
}
}
}
}
#[instability::unstable]
impl<Dm> embassy_embedded_hal::SetConfig for Uart<'_, Dm>
where
Dm: DriverMode,
{
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.apply_config(config)
}
}
#[instability::unstable]
impl<Dm> embassy_embedded_hal::SetConfig for UartRx<'_, Dm>
where
Dm: DriverMode,
{
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.apply_config(config)
}
}
#[instability::unstable]
impl<Dm> embassy_embedded_hal::SetConfig for UartTx<'_, Dm>
where
Dm: DriverMode,
{
type Config = Config;
type ConfigError = ConfigError;
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
self.baudrate = config.baudrate;
self.apply_config(config)
}
}
impl<'d> UartTx<'d, Blocking> {
#[procmacros::doc_replace]
#[instability::unstable]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
let (_, uart_tx) = UartBuilder::new(uart).init(config)?.split();
Ok(uart_tx)
}
#[instability::unstable]
pub fn into_async(self) -> UartTx<'d, Async> {
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_tx_async.store(true, Ordering::Release);
UartTx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
rts_pin: self.rts_pin,
tx_pin: self.tx_pin,
baudrate: self.baudrate,
}
}
}
impl<'d> UartTx<'d, Async> {
#[instability::unstable]
pub fn into_blocking(self) -> UartTx<'d, Blocking> {
self.uart
.state()
.is_tx_async
.store(false, Ordering::Release);
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart.disable_peri_interrupt_on_all_cores();
}
UartTx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
rts_pin: self.rts_pin,
tx_pin: self.tx_pin,
baudrate: self.baudrate,
}
}
pub async fn write_async(&mut self, bytes: &[u8]) -> Result<usize, TxError> {
let space = loop {
let tx_fifo_count = self.uart.info().tx_fifo_count();
let space = Info::UART_FIFO_SIZE - tx_fifo_count;
if space != 0 {
break space;
}
UartTxFuture::new(self.uart.reborrow(), TxEvent::FiFoEmpty).await;
};
let free = (space as usize).min(bytes.len());
for &byte in &bytes[..free] {
self.uart
.info()
.regs()
.fifo()
.write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) });
}
Ok(free)
}
pub async fn flush_async(&mut self) -> Result<(), TxError> {
while self.uart.info().tx_fifo_count() > 0 {
UartTxFuture::new(self.uart.reborrow(), TxEvent::Done).await;
}
self.flush_last_byte();
Ok(())
}
}
impl<'d, Dm> UartTx<'d, Dm>
where
Dm: DriverMode,
{
#[instability::unstable]
pub fn with_rts(mut self, rts: impl PeripheralOutput<'d>) -> Self {
let rts = rts.into();
rts.apply_output_config(&OutputConfig::default());
rts.set_output_enable(true);
self.rts_pin = rts.connect_with_guard(self.uart.info().rts_signal);
self
}
#[instability::unstable]
pub fn with_tx(mut self, tx: impl PeripheralOutput<'d>) -> Self {
let tx = tx.into();
tx.set_output_high(true);
tx.apply_output_config(&OutputConfig::default());
tx.set_output_enable(true);
self.tx_pin = tx.connect_with_guard(self.uart.info().tx_signal);
self
}
#[instability::unstable]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.uart
.info()
.set_tx_fifo_empty_threshold(config.tx.fifo_empty_threshold)?;
self.uart.info().txfifo_reset();
Ok(())
}
#[instability::unstable]
pub fn write_ready(&self) -> bool {
self.uart.info().tx_fifo_count() < Info::UART_FIFO_SIZE
}
#[instability::unstable]
pub fn write(&mut self, data: &[u8]) -> Result<usize, TxError> {
self.uart.info().write(data)
}
fn write_all(&mut self, mut data: &[u8]) -> Result<(), TxError> {
while !data.is_empty() {
let bytes_written = self.write(data)?;
data = &data[bytes_written..];
}
Ok(())
}
#[instability::unstable]
pub fn flush(&mut self) -> Result<(), TxError> {
while self.uart.info().tx_fifo_count() > 0 {}
self.flush_last_byte();
Ok(())
}
fn flush_last_byte(&mut self) {
crate::rom::ets_delay_us(10);
while !self.is_tx_idle() {}
}
#[instability::unstable]
pub fn send_break(&mut self, bits: u32) {
let original_conf0 = self.uart.info().regs().conf0().read();
let original_txd_inv = original_conf0.txd_inv().bit();
self.uart
.info()
.regs()
.conf0()
.modify(|_, w| w.txd_inv().bit(!original_txd_inv));
sync_regs(self.uart.info().regs());
let total_delay_us = (bits as u64 * 1_000_000) / self.baudrate as u64;
let delay_us = (total_delay_us as u32).max(1);
crate::rom::ets_delay_us(delay_us);
self.uart
.info()
.regs()
.conf0()
.write(|w| unsafe { w.bits(original_conf0.bits()) });
sync_regs(self.uart.info().regs());
}
fn is_tx_idle(&self) -> bool {
#[cfg(esp32)]
let status = self.regs().status();
#[cfg(not(esp32))]
let status = self.regs().fsm_status();
status.read().st_utx_out().bits() == 0x0
}
fn disable_tx_interrupts(&self) {
self.regs().int_clr().write(|w| {
w.txfifo_empty().clear_bit_by_one();
w.tx_brk_done().clear_bit_by_one();
w.tx_brk_idle_done().clear_bit_by_one();
w.tx_done().clear_bit_by_one()
});
self.regs().int_ena().write(|w| {
w.txfifo_empty().clear_bit();
w.tx_brk_done().clear_bit();
w.tx_brk_idle_done().clear_bit();
w.tx_done().clear_bit()
});
}
fn regs(&self) -> &RegisterBlock {
self.uart.info().regs()
}
}
#[inline(always)]
fn sync_regs(_register_block: &RegisterBlock) {
#[cfg(not(any(esp32, esp32s2)))]
{
cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3, esp32s3))] {
let update_reg = _register_block.id();
} else {
let update_reg = _register_block.reg_update();
}
}
update_reg.modify(|_, w| w.reg_update().set_bit());
while update_reg.read().reg_update().bit_is_set() {
core::hint::spin_loop();
}
}
}
impl<'d> UartRx<'d, Blocking> {
#[procmacros::doc_replace]
#[instability::unstable]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
let (uart_rx, _) = UartBuilder::new(uart).init(config)?.split();
Ok(uart_rx)
}
#[instability::unstable]
pub fn wait_for_break(&mut self) {
self.enable_break_detection();
while !self.regs().int_raw().read().brk_det().bit_is_set() {
}
self.regs()
.int_clr()
.write(|w| w.brk_det().clear_bit_by_one());
}
#[instability::unstable]
pub fn wait_for_break_with_timeout(&mut self, timeout: crate::time::Duration) -> bool {
self.enable_break_detection();
let start = crate::time::Instant::now();
while !self.regs().int_raw().read().brk_det().bit_is_set() {
if crate::time::Instant::now() - start >= timeout {
return false;
}
}
self.regs()
.int_clr()
.write(|w| w.brk_det().clear_bit_by_one());
true
}
#[instability::unstable]
pub fn into_async(self) -> UartRx<'d, Async> {
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_rx_async.store(true, Ordering::Release);
UartRx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
}
}
}
impl<'d> UartRx<'d, Async> {
#[instability::unstable]
pub fn into_blocking(self) -> UartRx<'d, Blocking> {
self.uart
.state()
.is_rx_async
.store(false, Ordering::Release);
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart.disable_peri_interrupt_on_all_cores();
}
UartRx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
}
}
async fn wait_for_buffered_data(
&mut self,
minimum: usize,
max_threshold: usize,
listen_for_timeout: bool,
) -> Result<(), RxError> {
let current_threshold = self.uart.info().rx_fifo_full_threshold();
let max_threshold = max_threshold.min(current_threshold as usize) as u16;
let minimum = minimum.min(Info::RX_FIFO_MAX_THRHD as usize) as u16;
let minimum = minimum.min(max_threshold);
if self.uart.info().rx_fifo_count() < minimum {
let info = self.uart.info();
unwrap!(info.set_rx_fifo_full_threshold(max_threshold));
let _guard = DropGuard::new((), |_| {
unwrap!(info.set_rx_fifo_full_threshold(current_threshold));
});
let mut events = RxEvent::FifoFull
| RxEvent::FifoOvf
| RxEvent::FrameError
| RxEvent::GlitchDetected
| RxEvent::ParityError;
if self.regs().at_cmd_char().read().char_num().bits() > 0 {
events |= RxEvent::CmdCharDetected;
}
cfg_if::cfg_if! {
if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
let reg_en = self.regs().tout_conf();
} else {
let reg_en = self.regs().conf1();
}
};
if listen_for_timeout && reg_en.read().rx_tout_en().bit_is_set() {
events |= RxEvent::FifoTout;
}
let events = UartRxFuture::new(self.uart.reborrow(), events).await;
let result = rx_event_check_for_error(events);
if let Err(error) = result {
if error == RxError::FifoOverflowed {
self.uart.info().rxfifo_reset();
}
return Err(error);
}
}
Ok(())
}
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
if buf.is_empty() {
return Ok(0);
}
self.wait_for_buffered_data(1, buf.len(), true).await?;
self.read_buffered(buf)
}
pub async fn read_exact_async(&mut self, mut buf: &mut [u8]) -> Result<(), RxError> {
if buf.is_empty() {
return Ok(());
}
let read = self.uart.info().read_buffered(buf)?;
buf = &mut buf[read..];
while !buf.is_empty() {
self.wait_for_buffered_data(buf.len(), buf.len(), false)
.await?;
let read = self.uart.info().read_buffered(buf)?;
buf = &mut buf[read..];
}
Ok(())
}
#[instability::unstable]
pub async fn wait_for_break_async(&mut self) {
UartRxFuture::new(self.uart.reborrow(), RxEvent::BreakDetected).await;
self.regs()
.int_clr()
.write(|w| w.brk_det().clear_bit_by_one());
}
}
impl<'d, Dm> UartRx<'d, Dm>
where
Dm: DriverMode,
{
fn regs(&self) -> &RegisterBlock {
self.uart.info().regs()
}
#[instability::unstable]
pub fn with_cts(self, cts: impl PeripheralInput<'d>) -> Self {
let cts = cts.into();
cts.apply_input_config(&InputConfig::default());
cts.set_input_enable(true);
self.uart.info().cts_signal.connect_to(&cts);
self
}
#[instability::unstable]
pub fn with_rx(self, rx: impl PeripheralInput<'d>) -> Self {
let rx = rx.into();
rx.apply_input_config(&InputConfig::default().with_pull(Pull::Up));
rx.set_input_enable(true);
self.uart.info().rx_signal.connect_to(&rx);
self
}
#[instability::unstable]
pub fn enable_break_detection(&mut self) {
self.uart
.info()
.enable_listen_rx(RxEvent::BreakDetected.into(), true);
sync_regs(self.regs());
}
#[instability::unstable]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.uart
.info()
.set_rx_fifo_full_threshold(config.rx.fifo_full_threshold)?;
self.uart
.info()
.set_rx_timeout(config.rx.timeout, self.uart.info().current_symbol_length())?;
self.uart.info().rxfifo_reset();
Ok(())
}
#[instability::unstable]
pub fn check_for_errors(&mut self) -> Result<(), RxError> {
self.uart.info().check_for_errors()
}
#[instability::unstable]
pub fn read_ready(&self) -> bool {
self.uart.info().rx_fifo_count() > 0
}
#[instability::unstable]
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.uart.info().read(buf)
}
#[instability::unstable]
pub fn read_buffered(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.uart.info().read_buffered(buf)
}
fn disable_rx_interrupts(&self) {
self.regs().int_clr().write(|w| {
w.rxfifo_full().clear_bit_by_one();
w.rxfifo_ovf().clear_bit_by_one();
w.rxfifo_tout().clear_bit_by_one();
w.at_cmd_char_det().clear_bit_by_one()
});
self.regs().int_ena().write(|w| {
w.rxfifo_full().clear_bit();
w.rxfifo_ovf().clear_bit();
w.rxfifo_tout().clear_bit();
w.at_cmd_char_det().clear_bit()
});
}
}
impl<'d> Uart<'d, Blocking> {
#[procmacros::doc_replace]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
UartBuilder::new(uart).init(config)
}
pub fn into_async(self) -> Uart<'d, Async> {
Uart {
rx: self.rx.into_async(),
tx: self.tx.into_async(),
}
}
#[cfg_attr(
not(multi_core),
doc = "Registers an interrupt handler for the peripheral."
)]
#[cfg_attr(
multi_core,
doc = "Registers an interrupt handler for the peripheral on the current core."
)]
#[doc = ""]
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.tx.uart.set_interrupt_handler(handler);
}
#[procmacros::doc_replace]
#[instability::unstable]
pub fn listen(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.tx.uart.info().enable_listen(interrupts.into(), true)
}
#[instability::unstable]
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.tx.uart.info().enable_listen(interrupts.into(), false)
}
#[instability::unstable]
pub fn interrupts(&mut self) -> EnumSet<UartInterrupt> {
self.tx.uart.info().interrupts()
}
#[instability::unstable]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<UartInterrupt>) {
self.tx.uart.info().clear_interrupts(interrupts)
}
#[instability::unstable]
pub fn wait_for_break(&mut self) {
self.rx.wait_for_break()
}
#[instability::unstable]
pub fn wait_for_break_with_timeout(&mut self, timeout: crate::time::Duration) -> bool {
self.rx.wait_for_break_with_timeout(timeout)
}
}
impl<'d> Uart<'d, Async> {
pub fn into_blocking(self) -> Uart<'d, Blocking> {
Uart {
rx: self.rx.into_blocking(),
tx: self.tx.into_blocking(),
}
}
#[procmacros::doc_replace]
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, TxError> {
self.tx.write_async(words).await
}
#[procmacros::doc_replace]
pub async fn flush_async(&mut self) -> Result<(), TxError> {
self.tx.flush_async().await
}
#[procmacros::doc_replace]
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read_async(buf).await
}
#[instability::unstable]
pub async fn read_exact_async(&mut self, buf: &mut [u8]) -> Result<(), RxError> {
self.rx.read_exact_async(buf).await
}
#[instability::unstable]
pub async fn wait_for_break_async(&mut self) {
self.rx.wait_for_break_async().await
}
}
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum UartInterrupt {
AtCmd,
TxDone,
RxBreakDetected,
RxFifoFull,
RxTimeout,
}
impl<'d, Dm> Uart<'d, Dm>
where
Dm: DriverMode,
{
#[procmacros::doc_replace]
pub fn with_rx(mut self, rx: impl PeripheralInput<'d>) -> Self {
self.rx = self.rx.with_rx(rx);
self
}
#[procmacros::doc_replace]
pub fn with_tx(mut self, tx: impl PeripheralOutput<'d>) -> Self {
self.tx = self.tx.with_tx(tx);
self
}
#[procmacros::doc_replace]
pub fn with_cts(mut self, cts: impl PeripheralInput<'d>) -> Self {
self.rx = self.rx.with_cts(cts);
self
}
#[procmacros::doc_replace]
pub fn with_rts(mut self, rts: impl PeripheralOutput<'d>) -> Self {
self.tx = self.tx.with_rts(rts);
self
}
fn regs(&self) -> &RegisterBlock {
self.tx.uart.info().regs()
}
#[procmacros::doc_replace]
pub fn write_ready(&self) -> bool {
self.tx.write_ready()
}
#[procmacros::doc_replace]
pub fn write(&mut self, data: &[u8]) -> Result<usize, TxError> {
self.tx.write(data)
}
#[procmacros::doc_replace]
pub fn flush(&mut self) -> Result<(), TxError> {
self.tx.flush()
}
#[instability::unstable]
pub fn send_break(&mut self, bits: u32) {
self.tx.send_break(bits)
}
#[procmacros::doc_replace]
pub fn read_ready(&self) -> bool {
self.rx.read_ready()
}
#[procmacros::doc_replace]
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read(buf)
}
#[procmacros::doc_replace]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.rx.uart.info().apply_config(config)?;
self.rx.apply_config(config)?;
self.tx.apply_config(config)?;
Ok(())
}
#[procmacros::doc_replace]
#[instability::unstable]
pub fn split(self) -> (UartRx<'d, Dm>, UartTx<'d, Dm>) {
(self.rx, self.tx)
}
#[instability::unstable]
pub fn check_for_rx_errors(&mut self) -> Result<(), RxError> {
self.rx.check_for_errors()
}
#[instability::unstable]
pub fn read_buffered(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read_buffered(buf)
}
#[instability::unstable]
pub fn set_at_cmd(&mut self, config: AtCmdConfig) {
#[cfg(not(any(esp32, esp32s2)))]
self.regs()
.clk_conf()
.modify(|_, w| w.sclk_en().clear_bit());
self.regs().at_cmd_char().write(|w| unsafe {
w.at_cmd_char().bits(config.cmd_char);
w.char_num().bits(config.char_num)
});
if let Some(pre_idle_count) = config.pre_idle_count {
self.regs()
.at_cmd_precnt()
.write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count as _) });
}
if let Some(post_idle_count) = config.post_idle_count {
self.regs()
.at_cmd_postcnt()
.write(|w| unsafe { w.post_idle_num().bits(post_idle_count as _) });
}
if let Some(gap_timeout) = config.gap_timeout {
self.regs()
.at_cmd_gaptout()
.write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout as _) });
}
#[cfg(not(any(esp32, esp32s2)))]
self.regs().clk_conf().modify(|_, w| w.sclk_en().set_bit());
sync_regs(self.regs());
}
#[inline(always)]
fn init(&mut self, config: Config) -> Result<(), ConfigError> {
self.rx.disable_rx_interrupts();
self.tx.disable_tx_interrupts();
self.rx.uart.info().rxfifo_reset();
self.rx.uart.info().txfifo_reset();
self.apply_config(&config)?;
self.regs()
.idle_conf()
.modify(|_, w| unsafe { w.tx_idle_num().bits(0) });
self.regs().conf0().modify(|_, w| w.err_wr_mask().set_bit());
crate::rom::ets_delay_us(15);
self.regs().int_clr().write(|w| unsafe { w.bits(u32::MAX) });
Ok(())
}
}
impl crate::private::Sealed for Uart<'_, Blocking> {}
#[instability::unstable]
impl crate::interrupt::InterruptConfigurable for Uart<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.tx.uart.set_interrupt_handler(handler);
}
}
#[instability::unstable]
impl<Dm> ufmt_write::uWrite for Uart<'_, Dm>
where
Dm: DriverMode,
{
type Error = TxError;
#[inline]
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.tx.write_str(s)
}
#[inline]
fn write_char(&mut self, ch: char) -> Result<(), Self::Error> {
self.tx.write_char(ch)
}
}
#[instability::unstable]
impl<Dm> ufmt_write::uWrite for UartTx<'_, Dm>
where
Dm: DriverMode,
{
type Error = TxError;
#[inline]
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.write_all(s.as_bytes())
}
}
impl<Dm> core::fmt::Write for Uart<'_, Dm>
where
Dm: DriverMode,
{
#[inline]
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.tx.write_str(s)
}
}
impl<Dm> core::fmt::Write for UartTx<'_, Dm>
where
Dm: DriverMode,
{
#[inline]
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.write_all(s.as_bytes()).map_err(|_| core::fmt::Error)
}
}
#[instability::unstable]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum IoError {
Tx(TxError),
Rx(RxError),
}
#[instability::unstable]
impl core::error::Error for IoError {}
#[instability::unstable]
impl core::fmt::Display for IoError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
IoError::Tx(e) => e.fmt(f),
IoError::Rx(e) => e.fmt(f),
}
}
}
#[instability::unstable]
impl embedded_io_06::Error for IoError {
fn kind(&self) -> embedded_io_06::ErrorKind {
embedded_io_06::ErrorKind::Other
}
}
#[instability::unstable]
impl embedded_io_07::Error for IoError {
fn kind(&self) -> embedded_io_07::ErrorKind {
embedded_io_07::ErrorKind::Other
}
}
#[instability::unstable]
impl From<RxError> for IoError {
fn from(e: RxError) -> Self {
IoError::Rx(e)
}
}
#[instability::unstable]
impl From<TxError> for IoError {
fn from(e: TxError) -> Self {
IoError::Tx(e)
}
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_06::ErrorType for Uart<'_, Dm> {
type Error = IoError;
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_06::ErrorType for UartTx<'_, Dm> {
type Error = TxError;
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_06::ErrorType for UartRx<'_, Dm> {
type Error = RxError;
}
#[instability::unstable]
impl<Dm> embedded_io_06::Read for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.read(buf).map_err(IoError::Rx)
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::Read for UartRx<'_, Dm>
where
Dm: DriverMode,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read(buf)
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::ReadReady for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.rx.read_ready())
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::ReadReady for UartRx<'_, Dm>
where
Dm: DriverMode,
{
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Ok(UartRx::read_ready(self))
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::Write for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.write(buf).map_err(IoError::Tx)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.tx.flush().map_err(IoError::Tx)
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::Write for UartTx<'_, Dm>
where
Dm: DriverMode,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.flush()
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::WriteReady for UartTx<'_, Dm>
where
Dm: DriverMode,
{
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(UartTx::write_ready(self))
}
}
#[instability::unstable]
impl<Dm> embedded_io_06::WriteReady for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.tx.write_ready())
}
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_07::ErrorType for Uart<'_, Dm> {
type Error = IoError;
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_07::ErrorType for UartTx<'_, Dm> {
type Error = TxError;
}
#[instability::unstable]
impl<Dm: DriverMode> embedded_io_07::ErrorType for UartRx<'_, Dm> {
type Error = RxError;
}
#[instability::unstable]
impl<Dm> embedded_io_07::Read for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.rx.read(buf).map_err(IoError::Rx)
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::Read for UartRx<'_, Dm>
where
Dm: DriverMode,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read(buf)
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::ReadReady for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.rx.read_ready())
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::ReadReady for UartRx<'_, Dm>
where
Dm: DriverMode,
{
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Ok(UartRx::read_ready(self))
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::Write for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.tx.write(buf).map_err(IoError::Tx)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.tx.flush().map_err(IoError::Tx)
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::Write for UartTx<'_, Dm>
where
Dm: DriverMode,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.flush()
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::WriteReady for UartTx<'_, Dm>
where
Dm: DriverMode,
{
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(UartTx::write_ready(self))
}
}
#[instability::unstable]
impl<Dm> embedded_io_07::WriteReady for Uart<'_, Dm>
where
Dm: DriverMode,
{
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.tx.write_ready())
}
}
#[derive(Debug, EnumSetType)]
pub(crate) enum TxEvent {
Done,
FiFoEmpty,
}
#[derive(Debug, EnumSetType)]
pub(crate) enum RxEvent {
FifoFull,
CmdCharDetected,
FifoOvf,
FifoTout,
GlitchDetected,
FrameError,
ParityError,
BreakDetected,
}
fn rx_event_check_for_error(events: EnumSet<RxEvent>) -> Result<(), RxError> {
for event in events {
match event {
RxEvent::FifoOvf => return Err(RxError::FifoOverflowed),
RxEvent::GlitchDetected => return Err(RxError::GlitchOccurred),
RxEvent::FrameError => return Err(RxError::FrameFormatViolated),
RxEvent::ParityError => return Err(RxError::ParityMismatch),
RxEvent::FifoFull
| RxEvent::CmdCharDetected
| RxEvent::FifoTout
| RxEvent::BreakDetected => continue,
}
}
Ok(())
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct UartRxFuture {
events: EnumSet<RxEvent>,
uart: &'static Info,
state: &'static State,
registered: bool,
}
impl UartRxFuture {
fn new(uart: impl Instance, events: impl Into<EnumSet<RxEvent>>) -> Self {
Self {
events: events.into(),
uart: uart.info(),
state: uart.state(),
registered: false,
}
}
}
impl core::future::Future for UartRxFuture {
type Output = EnumSet<RxEvent>;
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let events = self.uart.rx_events().intersection(self.events);
if !events.is_empty() {
self.uart.clear_rx_events(events);
Poll::Ready(events)
} else {
self.state.rx_waker.register(cx.waker());
if !self.registered {
self.uart.enable_listen_rx(self.events, true);
self.registered = true;
}
Poll::Pending
}
}
}
impl Drop for UartRxFuture {
fn drop(&mut self) {
self.uart.enable_listen_rx(self.events, false);
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct UartTxFuture {
events: EnumSet<TxEvent>,
uart: &'static Info,
state: &'static State,
registered: bool,
}
impl UartTxFuture {
fn new(uart: impl Instance, events: impl Into<EnumSet<TxEvent>>) -> Self {
Self {
events: events.into(),
uart: uart.info(),
state: uart.state(),
registered: false,
}
}
}
impl core::future::Future for UartTxFuture {
type Output = ();
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let events = self.uart.tx_events().intersection(self.events);
if !events.is_empty() {
self.uart.clear_tx_events(events);
Poll::Ready(())
} else {
self.state.tx_waker.register(cx.waker());
if !self.registered {
self.uart.enable_listen_tx(self.events, true);
self.registered = true;
}
Poll::Pending
}
}
}
impl Drop for UartTxFuture {
fn drop(&mut self) {
self.uart.enable_listen_tx(self.events, false);
}
}
#[instability::unstable]
impl embedded_io_async_06::Read for Uart<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await.map_err(IoError::Rx)
}
async fn read_exact(
&mut self,
buf: &mut [u8],
) -> Result<(), embedded_io_06::ReadExactError<Self::Error>> {
self.read_exact_async(buf)
.await
.map_err(|e| embedded_io_06::ReadExactError::Other(IoError::Rx(e)))
}
}
#[instability::unstable]
impl embedded_io_async_06::Read for UartRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await
}
async fn read_exact(
&mut self,
buf: &mut [u8],
) -> Result<(), embedded_io_06::ReadExactError<Self::Error>> {
self.read_exact_async(buf)
.await
.map_err(embedded_io_06::ReadExactError::Other)
}
}
#[instability::unstable]
impl embedded_io_async_06::Write for Uart<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await.map_err(IoError::Tx)
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await.map_err(IoError::Tx)
}
}
#[instability::unstable]
impl embedded_io_async_06::Write for UartTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await
}
}
#[instability::unstable]
impl embedded_io_async_07::Read for Uart<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await.map_err(IoError::Rx)
}
async fn read_exact(
&mut self,
buf: &mut [u8],
) -> Result<(), embedded_io_07::ReadExactError<Self::Error>> {
self.read_exact_async(buf)
.await
.map_err(|e| embedded_io_07::ReadExactError::Other(IoError::Rx(e)))
}
}
#[instability::unstable]
impl embedded_io_async_07::Read for UartRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await
}
async fn read_exact(
&mut self,
buf: &mut [u8],
) -> Result<(), embedded_io_07::ReadExactError<Self::Error>> {
self.read_exact_async(buf)
.await
.map_err(embedded_io_07::ReadExactError::Other)
}
}
#[instability::unstable]
impl embedded_io_async_07::Write for Uart<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await.map_err(IoError::Tx)
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await.map_err(IoError::Tx)
}
}
#[instability::unstable]
impl embedded_io_async_07::Write for UartTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await
}
}
#[ram]
pub(super) fn intr_handler(uart: &Info, state: &State) {
let interrupts = uart.regs().int_st().read();
let interrupt_bits = interrupts.bits(); let rx_wake = interrupts.rxfifo_full().bit_is_set()
| interrupts.rxfifo_ovf().bit_is_set()
| interrupts.rxfifo_tout().bit_is_set()
| interrupts.at_cmd_char_det().bit_is_set()
| interrupts.glitch_det().bit_is_set()
| interrupts.frm_err().bit_is_set()
| interrupts.parity_err().bit_is_set();
let tx_wake = interrupts.tx_done().bit_is_set() | interrupts.txfifo_empty().bit_is_set();
uart.regs()
.int_ena()
.modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) });
if tx_wake {
state.tx_waker.wake();
}
if rx_wake {
state.rx_waker.wake();
}
}
#[cfg(lp_uart_driver_supported)]
#[instability::unstable]
pub mod lp_uart {
use crate::{
gpio::lp_io::{LowPowerInput, LowPowerOutput},
peripherals::{LP_AON, LP_CLKRST, LP_IO, LP_UART, LPWR},
soc::clocks::ClockTree,
uart::{DataBits, Parity, StopBits},
};
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct Config {
baudrate: u32,
data_bits: DataBits,
parity: Parity,
stop_bits: StopBits,
#[builder_lite(unstable)]
clock_source: ClockSource,
}
impl Default for Config {
fn default() -> Config {
Config {
baudrate: 115_200,
data_bits: Default::default(),
parity: Default::default(),
stop_bits: Default::default(),
clock_source: Default::default(),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum ClockSource {
RcFast,
#[default]
Xtal,
}
pub struct LpUart {
uart: LP_UART<'static>,
}
impl LpUart {
pub fn new(
uart: LP_UART<'static>,
config: Config,
_tx: LowPowerOutput<'_, 5>,
_rx: LowPowerInput<'_, 4>,
) -> Self {
LP_AON::regs()
.gpio_mux()
.modify(|r, w| unsafe { w.sel().bits(r.sel().bits() | (1 << 4) | (1 << 5)) });
LP_IO::regs()
.gpio(4)
.modify(|_, w| unsafe { w.mcu_sel().bits(1) });
LP_IO::regs()
.gpio(5)
.modify(|_, w| unsafe { w.mcu_sel().bits(1) });
let mut me = Self { uart };
let uart = me.uart.register_block();
uart.conf0().modify(|_, w| unsafe {
w.parity().clear_bit();
w.parity_en().clear_bit();
w.bit_num().bits(0x3);
w.stop_bit_num().bits(0x1)
});
uart.idle_conf()
.modify(|_, w| unsafe { w.tx_idle_num().bits(0) });
uart.hwfc_conf().modify(|_, w| w.rx_flow_en().clear_bit());
LPWR::regs()
.lpperi()
.modify(|_, w| w.lp_uart_clk_sel().clear_bit());
me.change_baud_internal(&config);
me.change_parity(config.parity);
me.change_data_bits(config.data_bits);
me.change_stop_bits(config.stop_bits);
me.change_tx_idle(0);
me.rxfifo_reset();
me.txfifo_reset();
me
}
fn rxfifo_reset(&mut self) {
self.uart
.register_block()
.conf0()
.modify(|_, w| w.rxfifo_rst().set_bit());
self.update();
self.uart
.register_block()
.conf0()
.modify(|_, w| w.rxfifo_rst().clear_bit());
self.update();
}
fn txfifo_reset(&mut self) {
self.uart
.register_block()
.conf0()
.modify(|_, w| w.txfifo_rst().set_bit());
self.update();
self.uart
.register_block()
.conf0()
.modify(|_, w| w.txfifo_rst().clear_bit());
self.update();
}
fn update(&mut self) {
let register_block = self.uart.register_block();
register_block
.reg_update()
.modify(|_, w| w.reg_update().set_bit());
while register_block.reg_update().read().reg_update().bit_is_set() {
}
}
fn change_baud_internal(&mut self, config: &Config) {
let clk = ClockTree::with(|clocks| match config.clock_source {
ClockSource::RcFast => crate::soc::clocks::rc_fast_clk_frequency(clocks),
ClockSource::Xtal => crate::soc::clocks::xtal_d2_clk_frequency(clocks),
});
LP_CLKRST::regs().lpperi().modify(|_, w| {
w.lp_uart_clk_sel().bit(match config.clock_source {
ClockSource::RcFast => false,
ClockSource::Xtal => true,
})
});
self.uart.register_block().clk_conf().modify(|_, w| {
w.rx_sclk_en().set_bit();
w.tx_sclk_en().set_bit()
});
let divider = clk / config.baudrate;
let divider = divider as u16;
self.uart
.register_block()
.clkdiv()
.write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) });
self.update();
}
pub fn change_baud(&mut self, config: &Config) {
self.change_baud_internal(config);
self.txfifo_reset();
self.rxfifo_reset();
}
fn change_parity(&mut self, parity: Parity) -> &mut Self {
if parity != Parity::None {
self.uart
.register_block()
.conf0()
.modify(|_, w| w.parity().bit((parity as u8 & 0x1) != 0));
}
self.uart
.register_block()
.conf0()
.modify(|_, w| match parity {
Parity::None => w.parity_en().clear_bit(),
Parity::Even => w.parity_en().set_bit().parity().clear_bit(),
Parity::Odd => w.parity_en().set_bit().parity().set_bit(),
});
self
}
fn change_data_bits(&mut self, data_bits: DataBits) -> &mut Self {
self.uart
.register_block()
.conf0()
.modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) });
self.update();
self
}
fn change_stop_bits(&mut self, stop_bits: StopBits) -> &mut Self {
self.uart
.register_block()
.conf0()
.modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8 + 1) });
self.update();
self
}
fn change_tx_idle(&mut self, idle_num: u16) -> &mut Self {
self.uart
.register_block()
.idle_conf()
.modify(|_, w| unsafe { w.tx_idle_num().bits(idle_num) });
self.update();
self
}
}
}
pub trait Instance: crate::private::Sealed + any::Degrade {
#[doc(hidden)]
fn parts(&self) -> (&'static Info, &'static State);
#[inline(always)]
#[doc(hidden)]
fn info(&self) -> &'static Info {
self.parts().0
}
#[inline(always)]
#[doc(hidden)]
fn state(&self) -> &'static State {
self.parts().1
}
}
#[doc(hidden)]
#[non_exhaustive]
#[allow(private_interfaces, reason = "Unstable details")]
pub struct Info {
pub register_block: *const RegisterBlock,
pub peripheral: crate::system::Peripheral,
pub clock_instance: clocks::UartInstance,
pub async_handler: InterruptHandler,
pub tx_signal: OutputSignal,
pub rx_signal: InputSignal,
pub cts_signal: InputSignal,
pub rts_signal: OutputSignal,
}
#[doc(hidden)]
#[non_exhaustive]
pub struct State {
pub rx_waker: AtomicWaker,
pub tx_waker: AtomicWaker,
pub is_rx_async: AtomicBool,
pub is_tx_async: AtomicBool,
}
impl Info {
const UART_FIFO_SIZE: u16 = property!("uart.ram_size");
const RX_FIFO_MAX_THRHD: u16 = Self::UART_FIFO_SIZE - 1;
const TX_FIFO_MAX_THRHD: u16 = Self::RX_FIFO_MAX_THRHD;
pub fn regs(&self) -> &RegisterBlock {
unsafe { &*self.register_block }
}
fn enable_listen(&self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
let reg_block = self.regs();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
UartInterrupt::TxDone => w.tx_done().bit(enable),
UartInterrupt::RxBreakDetected => w.brk_det().bit(enable),
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
UartInterrupt::RxTimeout => w.rxfifo_tout().bit(enable),
};
}
w
});
}
fn interrupts(&self) -> EnumSet<UartInterrupt> {
let mut res = EnumSet::new();
let reg_block = self.regs();
let ints = reg_block.int_raw().read();
if ints.at_cmd_char_det().bit_is_set() {
res.insert(UartInterrupt::AtCmd);
}
if ints.tx_done().bit_is_set() {
res.insert(UartInterrupt::TxDone);
}
if ints.brk_det().bit_is_set() {
res.insert(UartInterrupt::RxBreakDetected);
}
if ints.rxfifo_full().bit_is_set() {
res.insert(UartInterrupt::RxFifoFull);
}
if ints.rxfifo_tout().bit_is_set() {
res.insert(UartInterrupt::RxTimeout);
}
res
}
fn clear_interrupts(&self, interrupts: EnumSet<UartInterrupt>) {
let reg_block = self.regs();
reg_block.int_clr().write(|w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
UartInterrupt::RxBreakDetected => w.brk_det().clear_bit_by_one(),
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
UartInterrupt::RxTimeout => w.rxfifo_tout().clear_bit_by_one(),
};
}
w
});
}
fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
config.validate()?;
self.change_baud(config)?;
self.change_data_bits(config.data_bits);
self.change_parity(config.parity);
self.change_stop_bits(config.stop_bits);
self.change_flow_control(config.sw_flow_ctrl, config.hw_flow_ctrl);
self.regs().int_clr().write(|w| unsafe { w.bits(u32::MAX) });
Ok(())
}
fn enable_listen_tx(&self, events: EnumSet<TxEvent>, enable: bool) {
self.regs().int_ena().modify(|_, w| {
for event in events {
match event {
TxEvent::Done => w.tx_done().bit(enable),
TxEvent::FiFoEmpty => w.txfifo_empty().bit(enable),
};
}
w
});
}
fn tx_events(&self) -> EnumSet<TxEvent> {
let pending_interrupts = self.regs().int_raw().read();
let mut active_events = EnumSet::new();
if pending_interrupts.tx_done().bit_is_set() {
active_events |= TxEvent::Done;
}
if pending_interrupts.txfifo_empty().bit_is_set() {
active_events |= TxEvent::FiFoEmpty;
}
active_events
}
fn clear_tx_events(&self, events: impl Into<EnumSet<TxEvent>>) {
let events = events.into();
self.regs().int_clr().write(|w| {
for event in events {
match event {
TxEvent::FiFoEmpty => w.txfifo_empty().clear_bit_by_one(),
TxEvent::Done => w.tx_done().clear_bit_by_one(),
};
}
w
});
}
fn enable_listen_rx(&self, events: EnumSet<RxEvent>, enable: bool) {
self.regs().int_ena().modify(|_, w| {
for event in events {
match event {
RxEvent::FifoFull => w.rxfifo_full().bit(enable),
RxEvent::BreakDetected => w.brk_det().bit(enable),
RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable),
RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable),
RxEvent::FifoTout => w.rxfifo_tout().bit(enable),
RxEvent::GlitchDetected => w.glitch_det().bit(enable),
RxEvent::FrameError => w.frm_err().bit(enable),
RxEvent::ParityError => w.parity_err().bit(enable),
};
}
w
});
}
fn rx_events(&self) -> EnumSet<RxEvent> {
let pending_interrupts = self.regs().int_raw().read();
let mut active_events = EnumSet::new();
if pending_interrupts.rxfifo_full().bit_is_set() {
active_events |= RxEvent::FifoFull;
}
if pending_interrupts.brk_det().bit_is_set() {
active_events |= RxEvent::BreakDetected;
}
if pending_interrupts.at_cmd_char_det().bit_is_set() {
active_events |= RxEvent::CmdCharDetected;
}
if pending_interrupts.rxfifo_ovf().bit_is_set() {
active_events |= RxEvent::FifoOvf;
}
if pending_interrupts.rxfifo_tout().bit_is_set() {
active_events |= RxEvent::FifoTout;
}
if pending_interrupts.glitch_det().bit_is_set() {
active_events |= RxEvent::GlitchDetected;
}
if pending_interrupts.frm_err().bit_is_set() {
active_events |= RxEvent::FrameError;
}
if pending_interrupts.parity_err().bit_is_set() {
active_events |= RxEvent::ParityError;
}
active_events
}
fn clear_rx_events(&self, events: impl Into<EnumSet<RxEvent>>) {
let events = events.into();
self.regs().int_clr().write(|w| {
for event in events {
match event {
RxEvent::FifoFull => w.rxfifo_full().clear_bit_by_one(),
RxEvent::BreakDetected => w.brk_det().clear_bit_by_one(),
RxEvent::CmdCharDetected => w.at_cmd_char_det().clear_bit_by_one(),
RxEvent::FifoOvf => w.rxfifo_ovf().clear_bit_by_one(),
RxEvent::FifoTout => w.rxfifo_tout().clear_bit_by_one(),
RxEvent::GlitchDetected => w.glitch_det().clear_bit_by_one(),
RxEvent::FrameError => w.frm_err().clear_bit_by_one(),
RxEvent::ParityError => w.parity_err().clear_bit_by_one(),
};
}
w
});
}
fn set_rx_fifo_full_threshold(&self, threshold: u16) -> Result<(), ConfigError> {
if threshold > Self::RX_FIFO_MAX_THRHD {
return Err(ConfigError::RxFifoThresholdNotSupported);
}
self.regs()
.conf1()
.modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold as _) });
Ok(())
}
#[allow(clippy::useless_conversion)]
fn rx_fifo_full_threshold(&self) -> u16 {
self.regs().conf1().read().rxfifo_full_thrhd().bits().into()
}
fn set_tx_fifo_empty_threshold(&self, threshold: u16) -> Result<(), ConfigError> {
if threshold > Self::TX_FIFO_MAX_THRHD {
return Err(ConfigError::TxFifoThresholdNotSupported);
}
self.regs()
.conf1()
.modify(|_, w| unsafe { w.txfifo_empty_thrhd().bits(threshold as _) });
Ok(())
}
fn set_rx_timeout(&self, timeout: Option<u8>, _symbol_len: u8) -> Result<(), ConfigError> {
cfg_if::cfg_if! {
if #[cfg(esp32)] {
const MAX_THRHD: u8 = 0x7F; } else {
const MAX_THRHD: u16 = 0x3FF; }
}
let register_block = self.regs();
if let Some(timeout) = timeout {
#[cfg(esp32)]
let timeout_reg = timeout;
#[cfg(not(esp32))]
let timeout_reg = timeout as u16 * _symbol_len as u16;
if timeout_reg > MAX_THRHD {
return Err(ConfigError::TimeoutTooLong);
}
cfg_if::cfg_if! {
if #[cfg(esp32)] {
let reg_thrhd = register_block.conf1();
} else if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
let reg_thrhd = register_block.tout_conf();
} else {
let reg_thrhd = register_block.mem_conf();
}
}
reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) });
}
cfg_if::cfg_if! {
if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
let reg_en = register_block.tout_conf();
} else {
let reg_en = register_block.conf1();
}
}
reg_en.modify(|_, w| w.rx_tout_en().bit(timeout.is_some()));
self.sync_regs();
Ok(())
}
fn sync_regs(&self) {
sync_regs(self.regs());
}
fn change_baud(&self, config: &Config) -> Result<(), ConfigError> {
ClockTree::with(|clocks| {
let clock = self.clock_instance;
let source_config = ClockConfig::new(
config.clock_source,
#[cfg(any(uart_has_sclk_divider, soc_has_pcr))]
0,
);
let clk = clock.function_clock_config_frequency(clocks, source_config);
const FRAC_BITS: u32 = const {
let largest_divider: u32 =
property!("clock_tree.uart.baud_rate_generator.fractional").1;
::core::assert!((largest_divider + 1).is_power_of_two());
largest_divider.count_ones()
};
const FRAC_MASK: u32 = (1 << FRAC_BITS) - 1;
cfg_if::cfg_if! {
if #[cfg(any(uart_has_sclk_divider, soc_has_pcr))] {
const MAX_DIV: u32 = property!("clock_tree.uart.baud_rate_generator.integral").1;
let clk_div = clk.div_ceil(MAX_DIV).div_ceil(config.baudrate);
debug!("SCLK: {} divider: {}", clk, clk_div);
let conf = ClockConfig::new(config.clock_source, clk_div - 1);
let divider = (clk << FRAC_BITS) / (config.baudrate * clk_div);
} else {
debug!("SCLK: {}", clk);
let conf = ClockConfig::new(config.clock_source);
let divider = (clk << FRAC_BITS) / config.baudrate;
}
}
let divider_integer = divider >> FRAC_BITS;
let divider_frag = divider & FRAC_MASK;
debug!(
"UART CLK divider: {} + {}/16",
divider_integer, divider_frag
);
clock.configure_function_clock(clocks, conf);
clock.configure_baud_rate_generator(
clocks,
BaudRateConfig::new(divider_frag, divider_integer),
);
self.sync_regs();
#[cfg(feature = "unstable")]
{
let deviation_limit = match config.baudrate_tolerance {
BaudrateTolerance::Exact => 1, BaudrateTolerance::ErrorPercent(percent) => percent as u32,
_ => return Ok(()),
};
let actual_baud = clock.baud_rate_generator_frequency(clocks);
if actual_baud == 0 {
return Err(ConfigError::BaudrateNotAchievable);
}
let deviation = (config.baudrate.abs_diff(actual_baud) * 100) / actual_baud;
debug!(
"Nominal baud: {}, actual: {}, deviation: {}%",
config.baudrate, actual_baud, deviation
);
if deviation > deviation_limit {
return Err(ConfigError::BaudrateNotAchievable);
}
}
Ok(())
})
}
fn change_data_bits(&self, data_bits: DataBits) {
self.regs()
.conf0()
.modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) });
}
fn change_parity(&self, parity: Parity) {
self.regs().conf0().modify(|_, w| match parity {
Parity::None => w.parity_en().clear_bit(),
Parity::Even => w.parity_en().set_bit().parity().clear_bit(),
Parity::Odd => w.parity_en().set_bit().parity().set_bit(),
});
}
fn change_stop_bits(&self, stop_bits: StopBits) {
#[cfg(esp32)]
{
if stop_bits == StopBits::_2 {
self.regs()
.rs485_conf()
.modify(|_, w| w.dl1_en().bit(stop_bits == StopBits::_2));
self.regs()
.conf0()
.modify(|_, w| unsafe { w.stop_bit_num().bits(1) });
}
}
#[cfg(not(esp32))]
self.regs()
.conf0()
.modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8 + 1) });
}
fn change_flow_control(&self, sw_flow_ctrl: SwFlowControl, hw_flow_ctrl: HwFlowControl) {
match sw_flow_ctrl {
SwFlowControl::Enabled {
xon_char,
xoff_char,
xon_threshold,
xoff_threshold,
} => {
cfg_if::cfg_if! {
if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
self.regs().swfc_conf0().modify(|_, w| w.xonoff_del().set_bit().sw_flow_con_en().set_bit());
self.regs().swfc_conf1().modify(|_, w| unsafe { w.xon_threshold().bits(xon_threshold).xoff_threshold().bits(xoff_threshold)});
self.regs().swfc_conf0().modify(|_, w| unsafe { w.xon_char().bits(xon_char).xoff_char().bits(xoff_char) });
} else if #[cfg(esp32)]{
self.regs().flow_conf().modify(|_, w| w.xonoff_del().set_bit().sw_flow_con_en().set_bit());
self.regs().swfc_conf().modify(|_, w| unsafe { w.xon_threshold().bits(xon_threshold).xoff_threshold().bits(xoff_threshold) });
self.regs().swfc_conf().modify(|_, w| unsafe { w.xon_char().bits(xon_char).xoff_char().bits(xoff_char) });
} else {
self.regs().flow_conf().modify(|_, w| w.xonoff_del().set_bit().sw_flow_con_en().set_bit());
self.regs().swfc_conf1().modify(|_, w| unsafe { w.xon_threshold().bits(xon_threshold as u16) });
self.regs().swfc_conf0().modify(|_, w| unsafe { w.xoff_threshold().bits(xoff_threshold as u16) });
self.regs().swfc_conf1().modify(|_, w| unsafe { w.xon_char().bits(xon_char) });
self.regs().swfc_conf0().modify(|_, w| unsafe { w.xoff_char().bits(xoff_char) });
}
}
}
SwFlowControl::Disabled => {
cfg_if::cfg_if! {
if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
let reg = self.regs().swfc_conf0();
} else {
let reg = self.regs().flow_conf();
}
}
reg.modify(|_, w| w.sw_flow_con_en().clear_bit());
reg.modify(|_, w| w.xonoff_del().clear_bit());
}
}
self.regs().conf0().modify(|_, w| {
w.tx_flow_en()
.bit(matches!(hw_flow_ctrl.cts, CtsConfig::Enabled))
});
match hw_flow_ctrl.rts {
RtsConfig::Enabled(threshold) => self.configure_rts_flow_ctrl(true, Some(threshold)),
RtsConfig::Disabled => self.configure_rts_flow_ctrl(false, None),
}
sync_regs(self.regs());
}
fn configure_rts_flow_ctrl(&self, enable: bool, threshold: Option<u8>) {
if let Some(threshold) = threshold {
cfg_if::cfg_if! {
if #[cfg(esp32)] {
self.regs().conf1().modify(|_, w| unsafe { w.rx_flow_thrhd().bits(threshold) });
} else if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
self.regs().hwfc_conf().modify(|_, w| unsafe { w.rx_flow_thrhd().bits(threshold) });
} else {
self.regs().mem_conf().modify(|_, w| unsafe { w.rx_flow_thrhd().bits(threshold as u16) });
}
}
}
cfg_if::cfg_if! {
if #[cfg(any(esp32c5, esp32c6, esp32c61, esp32h2))] {
self.regs().hwfc_conf().modify(|_, w| {
w.rx_flow_en().bit(enable)
});
} else {
self.regs().conf1().modify(|_, w| {
w.rx_flow_en().bit(enable)
});
}
}
}
fn rxfifo_reset(&self) {
fn rxfifo_rst(reg_block: &RegisterBlock, enable: bool) {
reg_block.conf0().modify(|_, w| w.rxfifo_rst().bit(enable));
sync_regs(reg_block);
}
rxfifo_rst(self.regs(), true);
rxfifo_rst(self.regs(), false);
}
fn txfifo_reset(&self) {
fn txfifo_rst(reg_block: &RegisterBlock, enable: bool) {
reg_block.conf0().modify(|_, w| w.txfifo_rst().bit(enable));
sync_regs(reg_block);
}
txfifo_rst(self.regs(), true);
txfifo_rst(self.regs(), false);
}
fn current_symbol_length(&self) -> u8 {
let conf0 = self.regs().conf0().read();
let data_bits = conf0.bit_num().bits() + 5; let parity = conf0.parity_en().bit() as u8;
let mut stop_bits = conf0.stop_bit_num().bits();
match stop_bits {
1 => {
#[cfg(esp32)]
if self.regs().rs485_conf().read().dl1_en().bit_is_set() {
stop_bits = 2;
}
}
_ => stop_bits = 2,
}
1 + data_bits + parity + stop_bits
}
fn read_next_from_fifo(&self) -> u8 {
fn access_fifo_register<R>(f: impl Fn() -> R) -> R {
cfg_if::cfg_if! {
if #[cfg(esp32)] {
crate::interrupt::free(f)
} else {
f()
}
}
}
let fifo_reg = self.regs().fifo();
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
let fifo_reg = unsafe {
&*fifo_reg.as_ptr().cast::<u8>().add(0x20C00000).cast::<crate::pac::uart0::FIFO>()
};
}
}
access_fifo_register(|| fifo_reg.read().rxfifo_rd_byte().bits())
}
#[allow(clippy::useless_conversion)]
fn tx_fifo_count(&self) -> u16 {
u16::from(self.regs().status().read().txfifo_cnt().bits())
}
fn write_byte(&self, byte: u8) {
self.regs()
.fifo()
.write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) });
}
fn check_for_errors(&self) -> Result<(), RxError> {
let errors = RxEvent::FifoOvf
| RxEvent::FifoTout
| RxEvent::GlitchDetected
| RxEvent::FrameError
| RxEvent::ParityError;
let events = self.rx_events().intersection(errors);
let result = rx_event_check_for_error(events);
if result.is_err() {
self.clear_rx_events(errors);
if events.contains(RxEvent::FifoOvf) {
self.rxfifo_reset();
}
}
result
}
#[cfg(not(esp32))]
#[allow(clippy::unnecessary_cast)]
fn rx_fifo_count(&self) -> u16 {
self.regs().status().read().rxfifo_cnt().bits() as u16
}
#[cfg(esp32)]
fn rx_fifo_count(&self) -> u16 {
let fifo_cnt = self.regs().status().read().rxfifo_cnt().bits();
let status = self.regs().mem_rx_status().read();
let rd_addr: u16 = status.mem_rx_rd_addr().bits();
let wr_addr: u16 = status.mem_rx_wr_addr().bits();
if wr_addr > rd_addr {
wr_addr - rd_addr
} else if wr_addr < rd_addr {
(wr_addr + Info::UART_FIFO_SIZE) - rd_addr
} else if fifo_cnt > 0 {
Info::UART_FIFO_SIZE
} else {
0
}
}
fn write(&self, data: &[u8]) -> Result<usize, TxError> {
if data.is_empty() {
return Ok(0);
}
while self.tx_fifo_count() >= Info::UART_FIFO_SIZE {}
let space = (Info::UART_FIFO_SIZE - self.tx_fifo_count()) as usize;
let to_write = space.min(data.len());
for &byte in &data[..to_write] {
self.write_byte(byte);
}
Ok(to_write)
}
fn read(&self, buf: &mut [u8]) -> Result<usize, RxError> {
if buf.is_empty() {
return Ok(0);
}
while self.rx_fifo_count() == 0 {
self.check_for_errors()?;
}
self.read_buffered(buf)
}
fn read_buffered(&self, buf: &mut [u8]) -> Result<usize, RxError> {
let to_read = (self.rx_fifo_count() as usize).min(buf.len());
self.check_for_errors()?;
for byte_into in buf[..to_read].iter_mut() {
*byte_into = self.read_next_from_fifo();
}
self.clear_rx_events(RxEvent::FifoFull);
Ok(to_read)
}
}
impl PartialEq for Info {
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.register_block, other.register_block)
}
}
unsafe impl Sync for Info {}
for_each_uart! {
($id:literal, $inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident) => {
impl Instance for crate::peripherals::$inst<'_> {
fn parts(&self) -> (&'static Info, &'static State) {
#[handler]
#[ram]
pub(super) fn irq_handler() {
intr_handler(&PERIPHERAL, &STATE);
}
static STATE: State = State {
tx_waker: AtomicWaker::new(),
rx_waker: AtomicWaker::new(),
is_rx_async: AtomicBool::new(false),
is_tx_async: AtomicBool::new(false),
};
static PERIPHERAL: Info = Info {
register_block: crate::peripherals::$inst::ptr(),
peripheral: crate::system::Peripheral::$peri,
clock_instance: clocks::UartInstance::$peri,
async_handler: irq_handler,
tx_signal: OutputSignal::$txd,
rx_signal: InputSignal::$rxd,
cts_signal: InputSignal::$cts,
rts_signal: OutputSignal::$rts,
};
(&PERIPHERAL, &STATE)
}
}
};
}
crate::any_peripheral! {
pub peripheral AnyUart<'d> {
#[cfg(soc_has_uart0)]
Uart0(crate::peripherals::UART0<'d>),
#[cfg(soc_has_uart1)]
Uart1(crate::peripherals::UART1<'d>),
#[cfg(soc_has_uart2)]
Uart2(crate::peripherals::UART2<'d>),
}
}
impl Instance for AnyUart<'_> {
#[inline]
fn parts(&self) -> (&'static Info, &'static State) {
any::delegate!(self, uart => { uart.parts() })
}
}
impl AnyUart<'_> {
fn bind_peri_interrupt(&self, handler: InterruptHandler) {
any::delegate!(self, uart => { uart.bind_peri_interrupt(handler) })
}
fn disable_peri_interrupt_on_all_cores(&self) {
any::delegate!(self, uart => { uart.disable_peri_interrupt_on_all_cores() })
}
fn set_interrupt_handler(&self, handler: InterruptHandler) {
self.disable_peri_interrupt_on_all_cores();
self.info().enable_listen(EnumSet::all(), false);
self.info().clear_interrupts(EnumSet::all());
self.bind_peri_interrupt(handler);
}
}
struct UartClockGuard<'t> {
uart: AnyUart<'t>,
}
impl<'t> UartClockGuard<'t> {
fn new(uart: AnyUart<'t>) -> Self {
ClockTree::with(|clocks| {
let clock = uart.info().clock_instance;
let sclk_config = ClockConfig::new(
Default::default(),
#[cfg(any(uart_has_sclk_divider, soc_has_pcr))]
0,
);
clock.configure_function_clock(clocks, sclk_config);
clock.request_function_clock(clocks);
clock.request_baud_rate_generator(clocks);
#[cfg(soc_has_clock_node_uart_mem_clock)]
clock.request_mem_clock(clocks);
});
Self { uart }
}
}
impl Clone for UartClockGuard<'_> {
fn clone(&self) -> Self {
Self::new(unsafe { self.uart.clone_unchecked() })
}
}
impl Drop for UartClockGuard<'_> {
fn drop(&mut self) {
ClockTree::with(|clocks| {
let clock = self.uart.info().clock_instance;
#[cfg(soc_has_clock_node_uart_mem_clock)]
clock.release_mem_clock(clocks);
clock.release_baud_rate_generator(clocks);
clock.release_function_clock(clocks);
});
}
}