From cc50c89a20ab4a70c58488260bc887f84774ebdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 1 Sep 2025 11:56:57 +0200 Subject: [PATCH] Enable UHCI on S3 and C3 (#4011) --- esp-hal/CHANGELOG.md | 2 +- esp-hal/src/system.rs | 23 +++++++++++++++++++++++ esp-hal/src/uart/mod.rs | 3 +-- esp-hal/src/uart/uhci.rs | 14 ++++++++++++++ hil-test/tests/uart_uhci.rs | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index ce9f0b994..3020413df 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `aes::{AesBackend, AesContext, dma::AesDmaBackend}`: Work-queue based AES driver (#3880, #3897) - `aes::cipher_modes`, `aes::CipherState` for constructing `AesContext`s (#3895) - `aes::dma::DmaCipherState` so that `AesDma` can properly support cipher modes that require state (IV, nonce, etc.) (#3897) -- `uart::Uhci`: for UART with DMA using the UHCI peripheral (#3871, #4008) +- `uart::Uhci`: for UART with DMA using the UHCI peripheral (#3871, #4008, #4011) - Align `I8080` driver pin configurations with latest guidelines (#3997) - Expose cache line configuration (#3946) - ESP32: Expose `psram_vaddr_mode` via `PsramConfig` (#3990) diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index 60750ceb9..73c7ba264 100755 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -120,6 +120,9 @@ pub enum Peripheral { /// Temperature sensor peripheral. #[cfg(soc_has_tsens)] Tsens, + /// UHCI0 + #[cfg(soc_has_uhci0)] + Uhci0, } impl Peripheral { @@ -207,6 +210,8 @@ impl Peripheral { Self::Systimer, #[cfg(soc_has_tsens)] Self::Tsens, + #[cfg(soc_has_uhci0)] + Self::Uhci0, ]; } @@ -475,6 +480,10 @@ impl PeripheralClockControl { Peripheral::Tsens => { perip_clk_en1.modify(|_, w| w.tsens_clk_en().bit(enable)); } + #[cfg(soc_has_uhci0)] + Peripheral::Uhci0 => { + perip_clk_en0.modify(|_, w| w.uhci0_clk_en().bit(enable)); + } } } @@ -652,6 +661,12 @@ impl PeripheralClockControl { w.tsens_clk_sel().bit(enable) }); } + #[cfg(soc_has_uhci0)] + Peripheral::Uhci0 => { + system + .uhci_conf() + .modify(|_, w| w.uhci_clk_en().bit(enable)); + } } } @@ -826,6 +841,10 @@ pub(crate) fn assert_peri_reset(peripheral: Peripheral, reset: bool) { } } } + #[cfg(soc_has_uhci0)] + Peripheral::Uhci0 => { + perip_rst_en0.modify(|_, w| w.uhci0_rst().bit(reset)); + } }); } @@ -958,6 +977,10 @@ fn assert_peri_reset(peripheral: Peripheral, reset: bool) { .tsens_clk_conf() .modify(|_, w| w.tsens_rst_en().bit(reset)); } + #[cfg(soc_has_uhci0)] + Peripheral::Uhci0 => { + system.uhci_conf().modify(|_, w| w.uhci_rst_en().bit(reset)); + } } } diff --git a/esp-hal/src/uart/mod.rs b/esp-hal/src/uart/mod.rs index ebb3df9da..9b559ebf9 100644 --- a/esp-hal/src/uart/mod.rs +++ b/esp-hal/src/uart/mod.rs @@ -42,9 +42,8 @@ //! [embedded-io-async]: embedded_io_async /// UHCI wrapper around UART -// TODO debug C3/S3 to remove the device cfgs // TODO add support for PDMA and multiple UHCI for 32/S2 support -#[cfg(all(soc_has_uhci0, gdma, any(esp32h2, esp32c6)))] +#[cfg(all(soc_has_uhci0, gdma))] #[cfg(feature = "unstable")] pub mod uhci; diff --git a/esp-hal/src/uart/uhci.rs b/esp-hal/src/uart/uhci.rs index 99ae8c86a..6172490f8 100644 --- a/esp-hal/src/uart/uhci.rs +++ b/esp-hal/src/uart/uhci.rs @@ -106,6 +106,7 @@ use crate::{ }, pac::uhci0, peripherals, + system::{GenericPeripheralGuard, Peripheral}, uart::{self, TxError, Uart, UartRx, UartTx, uhci::Error::AboveReadLimit}, }; @@ -235,6 +236,8 @@ where uart: Uart<'d, Dm>, uhci: AnyUhci<'static>, channel: Channel>>, + // TODO: devices with UHCI1 need the non-generic guard + _guard: GenericPeripheralGuard<{ Peripheral::Uhci0 as u8 }>, } impl<'d, Dm> Uhci<'d, Dm> @@ -345,11 +348,13 @@ where uhci: unsafe { self.uhci.clone_unchecked() }, uart_rx, channel_rx: self.channel.rx, + _guard: self._guard.clone(), }, UhciTx { uhci: self.uhci, uart_tx, channel_tx: self.channel.tx, + _guard: self._guard.clone(), }, ) } @@ -362,6 +367,8 @@ impl<'d> Uhci<'d, Blocking> { uhci: peripherals::UHCI0<'static>, channel: impl DmaChannelFor>, ) -> Self { + let guard = GenericPeripheralGuard::new(); + let channel = Channel::new(channel.degrade()); channel.runtime_ensure_compatible(&uhci); @@ -369,6 +376,7 @@ impl<'d> Uhci<'d, Blocking> { uart, uhci: uhci.into(), channel, + _guard: guard, }; uhci.init(); @@ -381,6 +389,7 @@ impl<'d> Uhci<'d, Blocking> { uart: self.uart.into_async(), uhci: self.uhci, channel: self.channel.into_async(), + _guard: self._guard, } } } @@ -392,6 +401,7 @@ impl<'d> Uhci<'d, Async> { uart: self.uart.into_blocking(), uhci: self.uhci, channel: self.channel.into_blocking(), + _guard: self._guard, } } } @@ -404,6 +414,8 @@ where uhci: AnyUhci<'static>, uart_tx: UartTx<'d, Dm>, channel_tx: ChannelTx>, + // TODO: devices with UHCI1 need the non-generic guard + _guard: GenericPeripheralGuard<{ Peripheral::Uhci0 as u8 }>, } impl<'d, Dm> UhciTx<'d, Dm> @@ -441,6 +453,8 @@ where #[allow(dead_code)] uart_rx: UartRx<'d, Dm>, channel_rx: ChannelRx>, + // TODO: devices with UHCI1 need the non-generic guard + _guard: GenericPeripheralGuard<{ Peripheral::Uhci0 as u8 }>, } impl<'d, Dm> UhciRx<'d, Dm> diff --git a/hil-test/tests/uart_uhci.rs b/hil-test/tests/uart_uhci.rs index 24e791afa..8159750a6 100644 --- a/hil-test/tests/uart_uhci.rs +++ b/hil-test/tests/uart_uhci.rs @@ -1,6 +1,6 @@ //! UART UHCI test, async -//% CHIPS: esp32c6 esp32h2 +//% CHIPS: esp32c3 esp32c6 esp32h2 esp32s3 //% FEATURES: unstable embassy #![no_std]