libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
esp_adc.cpp
1#include "esp_adc.hpp"
2
3#include "esp_adc/adc_cali_scheme.h"
4#include "esp_clk_tree.h"
5#include "esp_private/adc_private.h"
6#include "esp_private/adc_share_hw_ctrl.h"
7#include "esp_private/esp_clk_tree_common.h"
8#include "esp_private/gpio.h"
9#include "esp_private/sar_periph_ctrl.h"
10#include "hal/adc_hal_common.h"
11#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
12#define sens_dev_t sens_dev_s
13#include "hal/adc_oneshot_hal.h"
14#undef sens_dev_t
15#else
16#include "hal/adc_oneshot_hal.h"
17#endif
18
19#if defined(CONFIG_IDF_TARGET_ESP32) && CONFIG_IDF_TARGET_ESP32 && \
20 defined(CONFIG_ESP_WIFI_ENABLED) && CONFIG_ESP_WIFI_ENABLED
21#include "esp_wifi.h"
22#endif
23
24#ifndef ANALOG_CLOCK_ENABLE
25#define ANALOG_CLOCK_ENABLE() ((void)0)
26#endif
27#ifndef ANALOG_CLOCK_DISABLE
28#define ANALOG_CLOCK_DISABLE() ((void)0)
29#endif
30
31extern portMUX_TYPE rtc_spinlock;
32
33namespace LibXR
34{
35
36namespace
37{
38
39constexpr uint32_t DEFAULT_LINE_FITTING_VREF_MV = 1100U;
40
41} // namespace
42
43ESP32ADC::Channel::Channel() : parent_(nullptr), idx_(0), channel_num_(0) {}
44
45ESP32ADC::Channel::Channel(ESP32ADC* parent, uint8_t idx, uint8_t channel_num)
46 : parent_(parent), idx_(idx), channel_num_(channel_num)
47{
48}
49
50float ESP32ADC::Channel::Read() { return parent_ ? parent_->ReadChannel(idx_) : 0.f; }
51
52ESP32ADC::ESP32ADC(adc_unit_t unit, const adc_channel_t* channels, uint8_t num_channels,
53 uint32_t freq, adc_atten_t attenuation, adc_bitwidth_t bitwidth,
54 float reference_voltage, size_t dma_buf_size)
55 : unit_(unit),
56 num_channels_(num_channels),
57 attenuation_(attenuation),
58 bitwidth_(ResolveBitwidth(bitwidth)),
59 reference_voltage_(reference_voltage),
60 max_raw_((1U << static_cast<uint8_t>(bitwidth_)) - 1U)
61{
62 ASSERT(channels != nullptr);
63 ASSERT(num_channels_ > 0U);
64 ASSERT(reference_voltage_ > 0.0f);
65 ASSERT(max_raw_ != 0U);
66 ASSERT(num_channels_ <= SOC_ADC_MAX_CHANNEL_NUM);
67 if ((channels == nullptr) || (num_channels_ == 0U) || (reference_voltage_ <= 0.0f) ||
68 (max_raw_ == 0U) || (num_channels_ > SOC_ADC_MAX_CHANNEL_NUM))
69 {
70 return;
71 }
72
73 channels_ = new Channel[num_channels_];
74 channel_ids_ = new adc_channel_t[num_channels_];
75 channel_ready_ = new bool[num_channels_];
76 latest_values_ = new float[num_channels_];
77 latest_raw_ = new uint16_t[num_channels_];
78
79 for (uint8_t i = 0; i < SOC_ADC_MAX_CHANNEL_NUM; ++i)
80 {
81 channel_idx_map_[i] = INVALID_CHANNEL_IDX;
82 cali_handles_[i] = nullptr;
83 }
84
85 for (uint8_t i = 0; i < num_channels_; ++i)
86 {
87 ASSERT(IsValidChannel(channels[i]));
88 const uint8_t ch = static_cast<uint8_t>(channels[i]);
89 ASSERT(channel_idx_map_[ch] == INVALID_CHANNEL_IDX);
90 if (!IsValidChannel(channels[i]) || (channel_idx_map_[ch] != INVALID_CHANNEL_IDX))
91 {
92 return;
93 }
94
95 channels_[i] = Channel(this, i, ch);
96 channel_ids_[i] = channels[i];
97 channel_idx_map_[ch] = i;
98 channel_ready_[i] = false;
99 latest_values_[i] = 0.0f;
100 latest_raw_[i] = 0U;
101 }
102
103#if defined(CONFIG_IDF_TARGET_ESP32) && CONFIG_IDF_TARGET_ESP32 && \
104 defined(CONFIG_ESP_WIFI_ENABLED) && CONFIG_ESP_WIFI_ENABLED
105 if (unit_ == ADC_UNIT_2)
106 {
107 wifi_mode_t wifi_mode = WIFI_MODE_NULL;
108 const esp_err_t wifi_mode_err = esp_wifi_get_mode(&wifi_mode);
109 const bool wifi_active = (wifi_mode_err == ESP_OK) && (wifi_mode != WIFI_MODE_NULL);
110 ASSERT(!wifi_active);
111 if (wifi_active)
112 {
113 return;
114 }
115 }
116#endif
117
118 (void)InitCalibration();
119
120 const ContinuousInitResult cont_ans = InitContinuous(freq, dma_buf_size);
121 if (cont_ans == ContinuousInitResult::STARTED)
122 {
123 valid_ = true;
124 return;
125 }
126
127 if (cont_ans == ContinuousInitResult::FAILED)
128 {
129 ASSERT(false);
130 return;
131 }
132
133 const bool oneshot_ok = InitOneshot();
134 ASSERT(oneshot_ok);
135 if (!oneshot_ok)
136 {
137 return;
138 }
139
140 valid_ = true;
141}
142
143ESP32ADC::Channel& ESP32ADC::GetChannel(uint8_t idx)
144{
145 ASSERT(idx < num_channels_);
146 return channels_[idx];
147}
148
149float ESP32ADC::ReadChannel(uint8_t idx)
150{
151 ASSERT(valid_);
152 ASSERT(idx < num_channels_);
153 if (!valid_ || (idx >= num_channels_))
154 {
155 return 0.f;
156 }
157
158 if (backend_ == Backend::CONTINUOUS_DMA)
159 {
160#if SOC_ADC_DIG_CTRL_SUPPORTED && SOC_ADC_DMA_SUPPORTED
161 if (!channel_ready_[idx])
162 {
163 DrainContinuousFrames(continuous_prime_timeout_ms_);
164 }
165 else
166 {
167 DrainContinuousFrames(0U);
168 }
169#endif
170 ASSERT(channel_ready_[idx]);
171 return latest_values_[idx];
172 }
173
174 ASSERT(backend_ == Backend::ONESHOT);
175 ASSERT(oneshot_inited_ && (oneshot_hal_ != nullptr));
176 if (!oneshot_inited_ || (oneshot_hal_ == nullptr))
177 {
178 return 0.f;
179 }
180
181 const esp_err_t lock_err = adc_lock_try_acquire(unit_);
182 ASSERT(lock_err == ESP_OK);
183 if (lock_err != ESP_OK)
184 {
185 return 0.f;
186 }
187
188 int raw = 0;
189 bool converted = false;
190 bool clk_src_enabled = false;
191
192 portENTER_CRITICAL(&rtc_spinlock);
193
194#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
195 const esp_err_t clk_on =
196 esp_clk_tree_enable_src(static_cast<soc_module_clk_t>(oneshot_hal_->clk_src), true);
197 ASSERT(clk_on == ESP_OK);
198 clk_src_enabled = (clk_on == ESP_OK);
199#else
200 clk_src_enabled = true;
201#endif
202
203 if (clk_src_enabled)
204 {
205 ANALOG_CLOCK_ENABLE();
206 adc_oneshot_hal_setup(oneshot_hal_, channel_ids_[idx]);
207#if SOC_ADC_CALIBRATION_V1_SUPPORTED
208 adc_set_hw_calibration_code(unit_, attenuation_);
209#endif
210 converted = adc_oneshot_hal_convert(oneshot_hal_, &raw);
211 ANALOG_CLOCK_DISABLE();
212 }
213
214#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
215 if (clk_src_enabled)
216 {
217 const esp_err_t clk_off = esp_clk_tree_enable_src(
218 static_cast<soc_module_clk_t>(oneshot_hal_->clk_src), false);
219 ASSERT(clk_off == ESP_OK);
220 if (clk_off != ESP_OK)
221 {
222 converted = false;
223 }
224 }
225#endif
226
227 portEXIT_CRITICAL(&rtc_spinlock);
228
229 const esp_err_t unlock_err = adc_lock_release(unit_);
230 ASSERT(unlock_err == ESP_OK);
231 if (unlock_err != ESP_OK)
232 {
233 return 0.f;
234 }
235
236 ASSERT(converted);
237 if (!converted)
238 {
239 return 0.f;
240 }
241
242 latest_raw_[idx] = static_cast<uint16_t>(raw);
243 latest_values_[idx] = RawToVoltage(idx, latest_raw_[idx]);
244 channel_ready_[idx] = true;
245 return latest_values_[idx];
246}
247
248adc_bitwidth_t ESP32ADC::ResolveBitwidth(adc_bitwidth_t bitwidth)
249{
250 if (bitwidth == ADC_BITWIDTH_DEFAULT)
251 {
252 return static_cast<adc_bitwidth_t>(SOC_ADC_RTC_MAX_BITWIDTH);
253 }
254 return bitwidth;
255}
256
257bool ESP32ADC::InitCalibration()
258{
259#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
260 bool calibrated = false;
261
262 for (uint8_t i = 0; i < num_channels_; ++i)
263 {
264 adc_cali_curve_fitting_config_t config = {};
265 config.unit_id = unit_;
266 config.chan = channel_ids_[i];
267 config.atten = attenuation_;
268 config.bitwidth = bitwidth_;
269
270 adc_cali_handle_t handle = nullptr;
271 const esp_err_t err = adc_cali_create_scheme_curve_fitting(&config, &handle);
272 ASSERT((err == ESP_OK) || (err == ESP_ERR_NOT_SUPPORTED) ||
273 (err == ESP_ERR_INVALID_ARG) || (err == ESP_ERR_NO_MEM));
274 if (err != ESP_OK)
275 {
276 continue;
277 }
278
279 cali_handles_[i] = handle;
280 calibrated = true;
281 }
282
283 return calibrated;
284#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
285 adc_cali_line_fitting_config_t config = {};
286 config.unit_id = unit_;
287 config.atten = attenuation_;
288 config.bitwidth = bitwidth_;
289#if CONFIG_IDF_TARGET_ESP32
290 config.default_vref = DEFAULT_LINE_FITTING_VREF_MV;
291#endif
292
293 adc_cali_handle_t handle = nullptr;
294 const esp_err_t err = adc_cali_create_scheme_line_fitting(&config, &handle);
295 ASSERT((err == ESP_OK) || (err == ESP_ERR_NOT_SUPPORTED) ||
296 (err == ESP_ERR_INVALID_ARG) || (err == ESP_ERR_NO_MEM));
297 if (err != ESP_OK)
298 {
299 return false;
300 }
301
302 for (uint8_t i = 0; i < num_channels_; ++i)
303 {
304 cali_handles_[i] = handle;
305 }
306
307 return true;
308#else
309 return false;
310#endif
311}
312
313float ESP32ADC::RawToVoltage(uint8_t idx, uint16_t raw) const
314{
315 ASSERT(idx < num_channels_);
316 if (idx >= num_channels_)
317 {
318 return 0.f;
319 }
320
321 if (cali_handles_[idx] != nullptr)
322 {
323 int voltage_mv = 0;
324 const esp_err_t err =
325 adc_cali_raw_to_voltage(cali_handles_[idx], static_cast<int>(raw), &voltage_mv);
326 ASSERT(err == ESP_OK);
327 if (err == ESP_OK)
328 {
329 return static_cast<float>(voltage_mv) / 1000.0f;
330 }
331 }
332
333 return Normalize(static_cast<float>(raw));
334}
335
336float ESP32ADC::Normalize(float raw) const
337{
338 return (raw / static_cast<float>(max_raw_)) * reference_voltage_;
339}
340
341uint32_t ESP32ADC::ClampSampleFreq(uint32_t freq)
342{
343 if (freq < SOC_ADC_SAMPLE_FREQ_THRES_LOW)
344 {
345 return SOC_ADC_SAMPLE_FREQ_THRES_LOW;
346 }
347 if (freq > SOC_ADC_SAMPLE_FREQ_THRES_HIGH)
348 {
349 return SOC_ADC_SAMPLE_FREQ_THRES_HIGH;
350 }
351 return freq;
352}
353
354uint32_t ESP32ADC::AlignUp(uint32_t value, uint32_t align)
355{
356 if (align == 0U)
357 {
358 return value;
359 }
360 return (value + align - 1U) / align * align;
361}
362
363bool ESP32ADC::IsValidChannel(adc_channel_t channel) const
364{
365 const int channel_count = SOC_ADC_CHANNEL_NUM(static_cast<int>(unit_));
366 const int channel_num = static_cast<int>(channel);
367 return (channel_count > 0) && (channel_num >= 0) && (channel_num < channel_count);
368}
369
370void ESP32ADC::ConfigureAnalogPad(adc_channel_t channel) const
371{
372 int io_num = -1;
373 if ((adc_channel_to_io(unit_, channel, &io_num) == ESP_OK) && (io_num >= 0))
374 {
375 (void)gpio_config_as_analog(static_cast<gpio_num_t>(io_num));
376 }
377}
378
379} // namespace LibXR
LibXR 命名空间
Definition ch32_can.hpp:14