Skip to content

Commit 8222f88

Browse files
committed
Merge branch 'fix/wrong_channel_gpio_num_on_p4_adc2' into 'master'
ADC: add continuous parse data API See merge request espressif/esp-idf!40243
2 parents 290e3d6 + 3c7e54c commit 8222f88

File tree

15 files changed

+326
-34
lines changed

15 files changed

+326
-34
lines changed

components/esp_adc/adc_continuous.c

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,17 +477,16 @@ esp_err_t adc_continuous_config(adc_continuous_handle_t handle, const adc_contin
477477
}
478478

479479
ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range");
480-
481480
#if CONFIG_IDF_TARGET_ESP32
482-
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
481+
handle->format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
483482
#elif CONFIG_IDF_TARGET_ESP32S2
484483
if (config->conv_mode == ADC_CONV_BOTH_UNIT || config->conv_mode == ADC_CONV_ALTER_UNIT) {
485-
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
484+
handle->format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
486485
} else if (config->conv_mode == ADC_CONV_SINGLE_UNIT_1 || config->conv_mode == ADC_CONV_SINGLE_UNIT_2) {
487-
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
486+
handle->format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
488487
}
489488
#else
490-
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
489+
handle->format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
491490
#endif
492491

493492
uint32_t clk_src_freq_hz = 0;
@@ -585,3 +584,88 @@ esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel
585584
{
586585
return adc_channel_to_io(unit_id, channel, io_num);
587586
}
587+
588+
esp_err_t adc_continuous_parse_data(adc_continuous_handle_t handle,
589+
const uint8_t *raw_data,
590+
uint32_t raw_data_size,
591+
adc_continuous_data_t *parsed_data,
592+
uint32_t *num_parsed_samples)
593+
{
594+
// Parameter validation
595+
ESP_RETURN_ON_FALSE(handle && raw_data && parsed_data && num_parsed_samples, ESP_ERR_INVALID_ARG, ADC_TAG, "invalid argument");
596+
597+
// Buffer size validation
598+
if (raw_data_size == 0 || raw_data_size % SOC_ADC_DIGI_RESULT_BYTES != 0) {
599+
*num_parsed_samples = 0;
600+
return ESP_ERR_INVALID_SIZE;
601+
}
602+
603+
// Calculate number of samples
604+
uint32_t samples_to_parse = raw_data_size / SOC_ADC_DIGI_RESULT_BYTES;
605+
606+
for (uint32_t i = 0; i < samples_to_parse; i++) {
607+
adc_digi_output_data_t *p = (adc_digi_output_data_t*)&raw_data[i * SOC_ADC_DIGI_RESULT_BYTES];
608+
#if CONFIG_IDF_TARGET_ESP32
609+
parsed_data[i].unit = ADC_UNIT_1;
610+
parsed_data[i].channel = p->type1.channel;
611+
parsed_data[i].raw_data = p->type1.data;
612+
parsed_data[i].valid = (parsed_data[i].channel < SOC_ADC_CHANNEL_NUM(parsed_data[i].unit));
613+
#elif CONFIG_IDF_TARGET_ESP32S2
614+
if (handle->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2) {
615+
parsed_data[i].unit = p->type2.unit ? ADC_UNIT_2 : ADC_UNIT_1;
616+
parsed_data[i].channel = p->type2.channel;
617+
parsed_data[i].raw_data = p->type2.data;
618+
parsed_data[i].valid = (parsed_data[i].channel < SOC_ADC_CHANNEL_NUM(parsed_data[i].unit));
619+
} else if (handle->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1) {
620+
parsed_data[i].unit = handle->use_adc1 ? ADC_UNIT_1 : ADC_UNIT_2;
621+
parsed_data[i].channel = p->type1.channel;
622+
parsed_data[i].raw_data = p->type1.data;
623+
parsed_data[i].valid = (parsed_data[i].channel < SOC_ADC_CHANNEL_NUM(parsed_data[i].unit));
624+
}
625+
#else
626+
#if CONFIG_SOC_ADC_PERIPH_NUM == 1
627+
parsed_data[i].unit = ADC_UNIT_1;
628+
#else
629+
parsed_data[i].unit = p->type2.unit ? ADC_UNIT_2 : ADC_UNIT_1;
630+
#endif
631+
parsed_data[i].channel = (parsed_data[i].unit == ADC_UNIT_2) ? p->type2.channel - ADC_LL_UNIT2_CHANNEL_SUBSTRATION : p->type2.channel;
632+
parsed_data[i].raw_data = p->type2.data;
633+
parsed_data[i].valid = (parsed_data[i].channel < SOC_ADC_CHANNEL_NUM(parsed_data[i].unit));
634+
#endif
635+
}
636+
637+
*num_parsed_samples = samples_to_parse;
638+
return ESP_OK;
639+
}
640+
641+
esp_err_t adc_continuous_read_parse(adc_continuous_handle_t handle,
642+
adc_continuous_data_t *parsed_data,
643+
uint32_t max_samples,
644+
uint32_t *num_samples,
645+
uint32_t timeout_ms)
646+
{
647+
// Parameter validation
648+
ESP_RETURN_ON_FALSE(handle && parsed_data && num_samples, ESP_ERR_INVALID_ARG, ADC_TAG, "invalid argument");
649+
650+
// Allocate raw data buffer based on max_samples
651+
uint32_t raw_buffer_size = max_samples * SOC_ADC_DIGI_RESULT_BYTES;
652+
uint8_t *raw_data = malloc(raw_buffer_size);
653+
if (raw_data == NULL) {
654+
*num_samples = 0;
655+
return ESP_ERR_NO_MEM;
656+
}
657+
658+
uint32_t out_length = 0;
659+
esp_err_t read_ret = adc_continuous_read(handle, raw_data, raw_buffer_size, &out_length, timeout_ms);
660+
if (read_ret != ESP_OK) {
661+
free(raw_data);
662+
*num_samples = 0;
663+
return read_ret;
664+
}
665+
666+
esp_err_t parse_ret = adc_continuous_parse_data(handle, raw_data, out_length, parsed_data, num_samples);
667+
668+
free(raw_data);
669+
670+
return parse_ret;
671+
}

components/esp_adc/adc_continuous_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ struct adc_continuous_ctx_t {
8787
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
8888
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
8989
adc_hal_digi_ctrlr_cfg_t hal_digi_ctrlr_cfg; //Hal digital controller configuration
90+
adc_digi_output_format_t format; //ADC DMA conversion output format
9091
adc_continuous_evt_cbs_t cbs; //Callbacks
9192
void *user_data; //User context
9293
#if CONFIG_PM_ENABLE

components/esp_adc/include/esp_adc/adc_continuous.h

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -65,7 +65,7 @@ typedef struct {
6565
adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used
6666
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Please refer to `soc/soc_caps.h` to know available sampling frequency range*/
6767
adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`.
68-
adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
68+
adc_digi_output_format_t format __attribute__((deprecated)); ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
6969
} adc_continuous_config_t;
7070

7171
/**
@@ -238,6 +238,66 @@ esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t * const unit_id, a
238238
*/
239239
esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int * const io_num);
240240

241+
/**
242+
* @brief Parsed ADC continuous mode data structure
243+
*/
244+
typedef struct {
245+
adc_unit_t unit; ///< ADC unit (ADC_UNIT_1 or ADC_UNIT_2)
246+
adc_channel_t channel; ///< ADC channel number (0-9)
247+
uint32_t raw_data; ///< ADC raw data value (0-4095, 12-bit resolution)
248+
bool valid; ///< Whether the data is valid
249+
} adc_continuous_data_t;
250+
251+
/**
252+
* @brief Parse ADC continuous mode raw data
253+
*
254+
* @param[in] handle ADC continuous mode driver handle
255+
* @param[in] raw_data Raw data buffer obtained from adc_continuous_read()
256+
* @param[in] raw_data_size Size of raw data buffer in bytes
257+
* @param[out] parsed_data Parsed data array
258+
* @param[out] num_parsed_samples Number of samples actually parsed and stored in parsed_data
259+
*
260+
* @note The function will parse all available samples from raw_data. User should ensure
261+
* parsed_data array is large enough to hold raw_data_size/SOC_ADC_DIGI_RESULT_BYTES samples.
262+
* The function includes comprehensive bounds checking to prevent buffer overflow and integer overflow.
263+
*
264+
* @return
265+
* - ESP_OK: Success
266+
* - ESP_ERR_INVALID_ARG: Invalid arguments
267+
* - ESP_ERR_INVALID_SIZE: raw_data_size is not aligned to SOC_ADC_DIGI_RESULT_BYTES,
268+
* integer overflow detected, or buffer overflow detected
269+
*/
270+
esp_err_t adc_continuous_parse_data(adc_continuous_handle_t handle,
271+
const uint8_t *raw_data,
272+
uint32_t raw_data_size,
273+
adc_continuous_data_t *parsed_data,
274+
uint32_t *num_parsed_samples);
275+
276+
/**
277+
* @brief Read and parse ADC continuous mode data in one call
278+
*
279+
* @param[in] handle ADC continuous mode driver handle
280+
* @param[out] parsed_data Parsed data array
281+
* @param[in] max_samples Maximum number of samples that can be stored in parsed_data array
282+
* @param[out] num_samples Number of samples actually parsed and stored in parsed_data
283+
* @param[in] timeout_ms Timeout in milliseconds
284+
*
285+
* @note This function automatically handles raw data buffer allocation and cleanup.
286+
* User only needs to provide parsed_data array and specify max_samples.
287+
*
288+
* @return
289+
* - ESP_OK: Success
290+
* - ESP_ERR_INVALID_ARG: Invalid arguments
291+
* - ESP_ERR_INVALID_SIZE: Buffer size issues or overflow detected
292+
* - ESP_ERR_TIMEOUT: Operation timed out
293+
* - ESP_ERR_NO_MEM: Memory allocation failed
294+
*/
295+
esp_err_t adc_continuous_read_parse(adc_continuous_handle_t handle,
296+
adc_continuous_data_t *parsed_data,
297+
uint32_t max_samples,
298+
uint32_t *num_samples,
299+
uint32_t timeout_ms);
300+
241301
#ifdef __cplusplus
242302
}
243303
#endif

components/hal/esp32/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ extern "C" {
2727

2828
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (0)
2929

30+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
31+
3032
/*---------------------------------------------------------------
3133
Oneshot
3234
---------------------------------------------------------------*/

components/hal/esp32c3/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ extern "C" {
4040

4141
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
4242

43+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
44+
4345
/*---------------------------------------------------------------
4446
Oneshot
4547
---------------------------------------------------------------*/

components/hal/esp32c5/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ extern "C" {
4141

4242
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
4343
#define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1)
44+
45+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
4446
/*---------------------------------------------------------------
4547
Oneshot
4648
---------------------------------------------------------------*/

components/hal/esp32c6/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ extern "C" {
4040

4141
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
4242
#define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1)
43+
44+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
4345
/*---------------------------------------------------------------
4446
Oneshot
4547
---------------------------------------------------------------*/

components/hal/esp32c61/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ extern "C" {
4141

4242
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
4343
#define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1)
44+
45+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
4446
/*---------------------------------------------------------------
4547
Oneshot
4648
---------------------------------------------------------------*/

components/hal/esp32h2/include/hal/adc_ll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ extern "C" {
4040

4141
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (1)
4242
#define ADC_LL_ADC_FE_ON_MODEM_DOMAIN (1)
43+
44+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 0
4345
/*---------------------------------------------------------------
4446
Oneshot
4547
---------------------------------------------------------------*/

components/hal/esp32p4/include/hal/adc_ll.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ extern "C" {
3434
#define LP_ADC_FORCE_XPD_SAR_PD 2 // Force power down
3535
#define LP_ADC_FORCE_XPD_SAR_PU 3 // Force power up
3636

37+
// ESP32P4 ADC2 channel is 2-7, so we need to subtract 2 to get the correct channel
38+
#define ADC_LL_UNIT2_CHANNEL_SUBSTRATION 2
39+
3740
#define ADC_LL_NEED_APB_PERIPH_CLAIM(ADC_UNIT) (((ADC_UNIT) == ADC_UNIT_1) ? 0 : 1)
3841

3942
/*---------------------------------------------------------------
@@ -359,13 +362,14 @@ static inline void adc_ll_digi_set_pattern_table(adc_unit_t adc_n, uint32_t patt
359362
uint8_t offset = (pattern_index % 4) * 6;
360363
adc_ll_digi_pattern_table_t pattern = {0};
361364

362-
pattern.val = (table.atten & 0x3) | ((table.channel & 0xF) << 2);
363365
if (table.unit == ADC_UNIT_1){
366+
pattern.val = (table.atten & 0x3) | ((table.channel & 0xF) << 2);
364367
tab = ADC.sar1_patt_tab[index].sar1_patt_tab; //Read old register value
365368
tab &= (~(0xFC0000 >> offset)); //Clear old data
366369
tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; //Fill in the new data
367370
ADC.sar1_patt_tab[index].sar1_patt_tab = tab; //Write back
368371
} else {
372+
pattern.val = (table.atten & 0x3) | (((table.channel + 2) & 0xF) << 2);
369373
tab = ADC.sar2_patt_tab[index].sar2_patt_tab; //Read old register value
370374
tab &= (~(0xFC0000 >> offset)); //clear old data
371375
tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; //Fill in the new data

0 commit comments

Comments
 (0)