5#include "esp_adc/adc_cali_scheme.h"
6#include "esp_clk_tree.h"
7#include "esp_private/adc_private.h"
8#include "esp_private/adc_share_hw_ctrl.h"
9#include "esp_private/esp_clk_tree_common.h"
10#include "esp_private/gpio.h"
11#include "esp_private/sar_periph_ctrl.h"
12#include "hal/adc_hal_common.h"
13#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
14#define sens_dev_t sens_dev_s
15#include "hal/adc_oneshot_hal.h"
18#include "hal/adc_oneshot_hal.h"
21#if defined(CONFIG_IDF_TARGET_ESP32) && CONFIG_IDF_TARGET_ESP32 && \
22 defined(CONFIG_ESP_WIFI_ENABLED) && CONFIG_ESP_WIFI_ENABLED
26#ifndef ANALOG_CLOCK_ENABLE
27#define ANALOG_CLOCK_ENABLE() ((void)0)
29#ifndef ANALOG_CLOCK_DISABLE
30#define ANALOG_CLOCK_DISABLE() ((void)0)
33extern portMUX_TYPE rtc_spinlock;
41constexpr uint32_t kDefaultLineFittingVrefMv = 1100U;
45ESP32ADC::Channel::Channel() : parent_(nullptr), idx_(0), channel_num_(0) {}
47ESP32ADC::Channel::Channel(ESP32ADC* parent, uint8_t idx, uint8_t channel_num)
48 : parent_(parent), idx_(idx), channel_num_(channel_num)
52float ESP32ADC::Channel::Read() {
return parent_ ? parent_->ReadChannel(idx_) : 0.f; }
54ESP32ADC::ESP32ADC(adc_unit_t unit,
const adc_channel_t* channels, uint8_t num_channels,
55 uint32_t freq, adc_atten_t attenuation, adc_bitwidth_t bitwidth,
56 float reference_voltage,
size_t dma_buf_size)
58 num_channels_(num_channels),
59 attenuation_(attenuation),
60 bitwidth_(ResolveBitwidth(bitwidth)),
61 reference_voltage_(reference_voltage),
62 max_raw_((1U << static_cast<uint8_t>(bitwidth_)) - 1U)
64 ASSERT(channels !=
nullptr);
65 ASSERT(num_channels_ > 0U);
66 ASSERT(reference_voltage_ > 0.0f);
67 ASSERT(max_raw_ != 0U);
68 ASSERT(num_channels_ <= SOC_ADC_MAX_CHANNEL_NUM);
69 if ((channels ==
nullptr) || (num_channels_ == 0U) || (reference_voltage_ <= 0.0f) ||
70 (max_raw_ == 0U) || (num_channels_ > SOC_ADC_MAX_CHANNEL_NUM))
75 channels_ =
new (std::nothrow) Channel[num_channels_];
76 channel_ids_ =
new (std::nothrow) adc_channel_t[num_channels_];
77 channel_ready_ =
new (std::nothrow)
bool[num_channels_];
78 latest_values_ =
new (std::nothrow)
float[num_channels_];
79 latest_raw_ =
new (std::nothrow) uint16_t[num_channels_];
80 ASSERT(channels_ !=
nullptr);
81 ASSERT(channel_ids_ !=
nullptr);
82 ASSERT(channel_ready_ !=
nullptr);
83 ASSERT(latest_values_ !=
nullptr);
84 ASSERT(latest_raw_ !=
nullptr);
85 if ((channels_ ==
nullptr) || (channel_ids_ ==
nullptr) ||
86 (channel_ready_ ==
nullptr) || (latest_values_ ==
nullptr) ||
87 (latest_raw_ ==
nullptr))
93 for (uint8_t i = 0; i < SOC_ADC_MAX_CHANNEL_NUM; ++i)
95 channel_idx_map_[i] = kInvalidChannelIdx;
96 cali_handles_[i] =
nullptr;
99 for (uint8_t i = 0; i < num_channels_; ++i)
101 ASSERT(IsValidChannel(channels[i]));
102 const uint8_t ch =
static_cast<uint8_t
>(channels[i]);
103 ASSERT(channel_idx_map_[ch] == kInvalidChannelIdx);
104 if (!IsValidChannel(channels[i]) || (channel_idx_map_[ch] != kInvalidChannelIdx))
109 channels_[i] = Channel(
this, i, ch);
110 channel_ids_[i] = channels[i];
111 channel_idx_map_[ch] = i;
112 channel_ready_[i] =
false;
113 latest_values_[i] = 0.0f;
117#if defined(CONFIG_IDF_TARGET_ESP32) && CONFIG_IDF_TARGET_ESP32 && \
118 defined(CONFIG_ESP_WIFI_ENABLED) && CONFIG_ESP_WIFI_ENABLED
119 if (unit_ == ADC_UNIT_2)
121 wifi_mode_t wifi_mode = WIFI_MODE_NULL;
122 const esp_err_t wifi_mode_err = esp_wifi_get_mode(&wifi_mode);
123 const bool wifi_active = (wifi_mode_err == ESP_OK) && (wifi_mode != WIFI_MODE_NULL);
124 ASSERT(!wifi_active);
132 (void)InitCalibration();
134 const ContinuousInitResult cont_ans = InitContinuous(freq, dma_buf_size);
135 if (cont_ans == ContinuousInitResult::STARTED)
141 if (cont_ans == ContinuousInitResult::FAILED)
147 const bool oneshot_ok = InitOneshot();
157ESP32ADC::Channel& ESP32ADC::GetChannel(uint8_t idx)
159 ASSERT(idx < num_channels_);
160 return channels_[idx];
163float ESP32ADC::ReadChannel(uint8_t idx)
166 ASSERT(idx < num_channels_);
167 if (!valid_ || (idx >= num_channels_))
172 if (backend_ == Backend::CONTINUOUS_DMA)
174#if SOC_ADC_DIG_CTRL_SUPPORTED && SOC_ADC_DMA_SUPPORTED
175 if (!channel_ready_[idx])
177 DrainContinuousFrames(continuous_prime_timeout_ms_);
181 DrainContinuousFrames(0U);
184 ASSERT(channel_ready_[idx]);
185 return latest_values_[idx];
188 ASSERT(backend_ == Backend::ONESHOT);
189 ASSERT(oneshot_inited_ && (oneshot_hal_ !=
nullptr));
190 if (!oneshot_inited_ || (oneshot_hal_ ==
nullptr))
195 const esp_err_t lock_err = adc_lock_try_acquire(unit_);
196 ASSERT(lock_err == ESP_OK);
197 if (lock_err != ESP_OK)
203 bool converted =
false;
204 bool clk_src_enabled =
false;
206 portENTER_CRITICAL(&rtc_spinlock);
208#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
209 const esp_err_t clk_on =
210 esp_clk_tree_enable_src(
static_cast<soc_module_clk_t
>(oneshot_hal_->clk_src),
true);
211 ASSERT(clk_on == ESP_OK);
212 clk_src_enabled = (clk_on == ESP_OK);
214 clk_src_enabled =
true;
219 ANALOG_CLOCK_ENABLE();
220 adc_oneshot_hal_setup(oneshot_hal_, channel_ids_[idx]);
221#if SOC_ADC_CALIBRATION_V1_SUPPORTED
222 adc_set_hw_calibration_code(unit_, attenuation_);
224 converted = adc_oneshot_hal_convert(oneshot_hal_, &raw);
225 ANALOG_CLOCK_DISABLE();
228#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
231 const esp_err_t clk_off = esp_clk_tree_enable_src(
232 static_cast<soc_module_clk_t
>(oneshot_hal_->clk_src),
false);
233 ASSERT(clk_off == ESP_OK);
234 if (clk_off != ESP_OK)
241 portEXIT_CRITICAL(&rtc_spinlock);
243 const esp_err_t unlock_err = adc_lock_release(unit_);
244 ASSERT(unlock_err == ESP_OK);
245 if (unlock_err != ESP_OK)
256 latest_raw_[idx] =
static_cast<uint16_t
>(raw);
257 latest_values_[idx] = RawToVoltage(idx, latest_raw_[idx]);
258 channel_ready_[idx] =
true;
259 return latest_values_[idx];
262adc_bitwidth_t ESP32ADC::ResolveBitwidth(adc_bitwidth_t bitwidth)
264 if (bitwidth == ADC_BITWIDTH_DEFAULT)
266 return static_cast<adc_bitwidth_t
>(SOC_ADC_RTC_MAX_BITWIDTH);
271bool ESP32ADC::InitCalibration()
273#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
274 bool calibrated =
false;
276 for (uint8_t i = 0; i < num_channels_; ++i)
278 adc_cali_curve_fitting_config_t config = {};
279 config.unit_id = unit_;
280 config.chan = channel_ids_[i];
281 config.atten = attenuation_;
282 config.bitwidth = bitwidth_;
284 adc_cali_handle_t handle =
nullptr;
285 const esp_err_t err = adc_cali_create_scheme_curve_fitting(&config, &handle);
286 ASSERT((err == ESP_OK) || (err == ESP_ERR_NOT_SUPPORTED) ||
287 (err == ESP_ERR_INVALID_ARG) || (err == ESP_ERR_NO_MEM));
293 cali_handles_[i] = handle;
298#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
299 adc_cali_line_fitting_config_t config = {};
300 config.unit_id = unit_;
301 config.atten = attenuation_;
302 config.bitwidth = bitwidth_;
303#if CONFIG_IDF_TARGET_ESP32
304 config.default_vref = kDefaultLineFittingVrefMv;
307 adc_cali_handle_t handle =
nullptr;
308 const esp_err_t err = adc_cali_create_scheme_line_fitting(&config, &handle);
309 ASSERT((err == ESP_OK) || (err == ESP_ERR_NOT_SUPPORTED) ||
310 (err == ESP_ERR_INVALID_ARG) || (err == ESP_ERR_NO_MEM));
316 for (uint8_t i = 0; i < num_channels_; ++i)
318 cali_handles_[i] = handle;
327float ESP32ADC::RawToVoltage(uint8_t idx, uint16_t raw)
const
329 ASSERT(idx < num_channels_);
330 if (idx >= num_channels_)
335 if (cali_handles_[idx] !=
nullptr)
338 const esp_err_t err =
339 adc_cali_raw_to_voltage(cali_handles_[idx],
static_cast<int>(raw), &voltage_mv);
340 ASSERT(err == ESP_OK);
343 return static_cast<float>(voltage_mv) / 1000.0f;
347 return Normalize(
static_cast<float>(raw));
350float ESP32ADC::Normalize(
float raw)
const
352 return (raw /
static_cast<float>(max_raw_)) * reference_voltage_;
355uint32_t ESP32ADC::ClampSampleFreq(uint32_t freq)
357 if (freq < SOC_ADC_SAMPLE_FREQ_THRES_LOW)
359 return SOC_ADC_SAMPLE_FREQ_THRES_LOW;
361 if (freq > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)
363 return SOC_ADC_SAMPLE_FREQ_THRES_HIGH;
368uint32_t ESP32ADC::AlignUp(uint32_t value, uint32_t align)
374 return (value + align - 1U) / align * align;
377bool ESP32ADC::IsValidChannel(adc_channel_t channel)
const
379 const int channel_count = SOC_ADC_CHANNEL_NUM(
static_cast<int>(unit_));
380 const int channel_num =
static_cast<int>(channel);
381 return (channel_count > 0) && (channel_num >= 0) && (channel_num < channel_count);
384void ESP32ADC::ConfigureAnalogPad(adc_channel_t channel)
const
387 if ((adc_channel_to_io(unit_, channel, &io_num) == ESP_OK) && (io_num >= 0))
389 (void)gpio_config_as_analog(
static_cast<gpio_num_t
>(io_num));