Enable async ADC for C2 and H2 (#3082)

* Enable async ADC for H2

* Enable for C2

* Prevent disabling interrupt if an async ADC is in use

* Introduce adc1/2 symbols
This commit is contained in:
Dániel Buga 2025-02-03 10:41:04 +01:00 committed by GitHub
parent 9a34d0e931
commit 17255ac0ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 66 additions and 34 deletions

View File

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- SPI: Added support for 3-wire SPI (#2919)
- UART: Add separate config for Rx and Tx (#2965)
- Added accessor methods to config structs (#3011)
- Async support for ADC oneshot reads for ESP32C2, ESP32C3, ESP32C6 and ESP32H2 (#2925, #3082)
### Changed
@ -106,7 +107,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ESP32-S2: Made Wi-Fi peripheral non virtual. (#2942)
- `UartRx::check_for_errors`, `Uart::check_for_rx_errors`, `{Uart, UartRx}::read_buffered_bytes` (#2935)
- Added `i2c` interrupt API (#2944)
- Async support for ADC oneshot reads for ESP32C3 and ESP32C6 (#2925)
### Changed

View File

@ -1,9 +1,12 @@
use core::marker::PhantomData;
#[cfg(esp32c3)]
use Interrupt::APB_ADC as InterruptSource;
#[cfg(esp32c6)]
use Interrupt::APB_SARADC as InterruptSource;
cfg_if::cfg_if! {
if #[cfg(esp32c6)] {
use Interrupt::APB_SARADC as InterruptSource;
} else {
use Interrupt::APB_ADC as InterruptSource;
}
}
#[cfg(not(esp32h2))]
pub use self::calibration::*;
@ -12,17 +15,13 @@ use super::{AdcCalSource, AdcConfig, Attenuation};
use crate::clock::clocks_ll::regi2c_write_mask;
#[cfg(any(esp32c2, esp32c3, esp32c6))]
use crate::efuse::Efuse;
#[cfg(any(esp32c3, esp32c6))]
use crate::{
analog::adc::asynch::AdcFuture,
interrupt::{InterruptConfigurable, InterruptHandler},
peripherals::Interrupt,
Async,
};
use crate::{
peripheral::PeripheralRef,
peripherals::APB_SARADC,
peripherals::{Interrupt, APB_SARADC},
system::{GenericPeripheralGuard, Peripheral},
Async,
Blocking,
};
@ -51,7 +50,7 @@ fn regi2c_write_mask(block: u8, host_id: u8, reg_add: u8, msb: u8, lsb: u8, data
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32h2/include/soc/regi2c_saradc.h
// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32h4/include/soc/regi2c_saradc.h
cfg_if::cfg_if! {
if #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))] {
if #[cfg(adc1)] {
const I2C_SAR_ADC: u8 = 0x69;
const I2C_SAR_ADC_HOSTID: u8 = 0;
@ -82,7 +81,7 @@ cfg_if::cfg_if! {
}
cfg_if::cfg_if! {
if #[cfg(esp32c3)] {
if #[cfg(adc2)] {
const ADC_SAR2_ENCAL_GND_ADDR: u8 = 0x7;
const ADC_SAR2_ENCAL_GND_ADDR_MSB: u8 = 7;
const ADC_SAR2_ENCAL_GND_ADDR_LSB: u8 = 7;
@ -194,6 +193,7 @@ pub trait RegisterAccess {
fn set_init_code(data: u16);
}
#[cfg(adc1)]
impl RegisterAccess for crate::peripherals::ADC1 {
fn config_onetime_sample(channel: u8, attenuation: u8) {
APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
@ -256,6 +256,7 @@ impl RegisterAccess for crate::peripherals::ADC1 {
}
}
#[cfg(adc1)]
impl super::CalibrationAccess for crate::peripherals::ADC1 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
@ -296,7 +297,7 @@ impl super::CalibrationAccess for crate::peripherals::ADC1 {
}
}
#[cfg(esp32c3)]
#[cfg(adc2)]
impl RegisterAccess for crate::peripherals::ADC2 {
fn config_onetime_sample(channel: u8, attenuation: u8) {
APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
@ -357,7 +358,7 @@ impl RegisterAccess for crate::peripherals::ADC2 {
}
}
#[cfg(esp32c3)]
#[cfg(adc2)]
impl super::CalibrationAccess for crate::peripherals::ADC2 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
@ -435,9 +436,9 @@ where
}
}
#[cfg(any(esp32c3, esp32c6))]
/// Reconfigures the ADC driver to operate in asynchronous mode.
pub fn into_async(mut self) -> Adc<'d, ADCI, Async> {
asynch::acquire_async_adc();
self.set_interrupt_handler(asynch::adc_interrupt_handler);
// Reset interrupt flags and disable oneshot reading to normalize state before
@ -531,7 +532,6 @@ where
impl<ADCI> crate::private::Sealed for Adc<'_, ADCI, Blocking> {}
#[cfg(any(esp32c3, esp32c6))]
impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
@ -545,7 +545,7 @@ impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
}
}
#[cfg(any(esp32c2, esp32c3, esp32c6))]
#[cfg(all(adc1, not(esp32h2)))]
impl super::AdcCalEfuse for crate::peripherals::ADC1 {
fn init_code(atten: Attenuation) -> Option<u16> {
Efuse::rtc_calib_init_code(1, atten)
@ -560,7 +560,7 @@ impl super::AdcCalEfuse for crate::peripherals::ADC1 {
}
}
#[cfg(esp32c3)]
#[cfg(adc2)]
impl super::AdcCalEfuse for crate::peripherals::ADC2 {
fn init_code(atten: Attenuation) -> Option<u16> {
Efuse::rtc_calib_init_code(2, atten)
@ -635,14 +635,18 @@ mod adc_implementation {
}
}
#[cfg(any(esp32c3, esp32c6))]
impl<'d, ADCI> Adc<'d, ADCI, Async>
where
ADCI: RegisterAccess + 'd,
{
/// Create a new instance in [crate::Blocking] mode.
pub fn into_blocking(self) -> Adc<'d, ADCI, Blocking> {
crate::interrupt::disable(crate::Cpu::current(), InterruptSource);
if asynch::release_async_adc() {
// Disable ADC interrupt on all cores if the last async ADC instance is disabled
for cpu in crate::Cpu::all() {
crate::interrupt::disable(cpu, InterruptSource);
}
}
Adc {
_adc: self._adc,
attenuations: self.attenuations,
@ -697,7 +701,6 @@ where
}
}
#[cfg(any(esp32c3, esp32c6))]
/// Async functionality
pub(crate) mod asynch {
use core::{
@ -706,20 +709,42 @@ pub(crate) mod asynch {
task::{Context, Poll},
};
// We only have to count on devices that have multiple ADCs sharing the same interrupt
#[cfg(all(adc1, adc2))]
use portable_atomic::{AtomicU32, Ordering};
use procmacros::handler;
use crate::{asynch::AtomicWaker, peripherals::APB_SARADC, Async};
#[cfg(all(adc1, adc2))]
static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
pub(super) fn acquire_async_adc() {
#[cfg(all(adc1, adc2))]
ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
}
pub(super) fn release_async_adc() -> bool {
cfg_if::cfg_if! {
if #[cfg(all(adc1, adc2))] {
ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
} else {
true
}
}
}
#[handler]
pub(crate) fn adc_interrupt_handler() {
let saradc = APB_SARADC::regs();
let interrupt_status = saradc.int_st().read();
#[cfg(adc1)]
if interrupt_status.adc1_done().bit_is_set() {
handle_async(crate::peripherals::ADC1)
}
#[cfg(esp32c3)]
#[cfg(adc2)]
if interrupt_status.adc2_done().bit_is_set() {
handle_async(crate::peripherals::ADC2)
}
@ -745,6 +770,7 @@ pub(crate) mod asynch {
fn waker() -> &'static AtomicWaker;
}
#[cfg(adc1)]
impl AsyncAccess for crate::peripherals::ADC1 {
fn enable_interrupt() {
APB_SARADC::regs()
@ -771,7 +797,7 @@ pub(crate) mod asynch {
}
}
#[cfg(esp32c3)]
#[cfg(adc2)]
impl AsyncAccess for crate::peripherals::ADC2 {
fn enable_interrupt() {
APB_SARADC::regs()

View File

@ -5,7 +5,7 @@
//! available on the device. For more information about a peripheral driver,
//! please refer to the relevant module documentation.
#[cfg(adc)]
#[cfg(any(adc1, adc2))]
pub mod adc;
#[cfg(dac)]
pub mod dac;

View File

@ -228,7 +228,7 @@ pub(crate) use unstable_module;
unstable_module! {
#[cfg(aes)]
pub mod aes;
#[cfg(any(adc, dac))]
#[cfg(any(adc1, adc2, dac))]
pub mod analog;
pub mod asynch;
#[cfg(assist_debug)]

View File

@ -52,7 +52,8 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"adc2",
"dac",
"pdma",
"phy",

View File

@ -34,7 +34,7 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"assist_debug_sp_monitor",
"gdma",
"phy",

View File

@ -45,7 +45,8 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"adc2",
"assist_debug_sp_monitor",
"assist_debug_region_monitor",
"gdma",

View File

@ -71,7 +71,7 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"assist_debug_sp_monitor",
"assist_debug_region_monitor",
"gdma",

View File

@ -63,7 +63,7 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"assist_debug_sp_monitor",
"assist_debug_region_monitor",
"gdma",

View File

@ -93,6 +93,8 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
# "adc1",
# "adc2",
"clic",
"very_large_intr_status",
"gpio_bank_1",

View File

@ -49,7 +49,8 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"adc2",
"dac",
"pdma",
"phy",

View File

@ -61,7 +61,8 @@ peripherals = [
symbols = [
# Additional peripherals defined by us (the developers):
"adc",
"adc1",
"adc2",
"assist_debug_region_monitor",
"gdma",
"phy",

View File

@ -1,6 +1,6 @@
//! This shows how to asynchronously read ADC data
//% CHIPS: esp32c6 esp32c3
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
#![no_std]
#![no_main]