espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.33k stars 7.2k forks source link

ESP32s3 Interrupt ADC1_DONE_INT in Continuous ADC mode have fixed frequency regardless on the sample rate of the ADC (Is it a hardware bug ?)) (IDFGH-10365) #11623

Open 5ami opened 1 year ago

5ami commented 1 year ago

Answers checklist.

General issue report

I am working with the ADC_continous Example from ESP-IDF 5.0 with some modification.

I saw many issues with Continuous ADC sample rate #11604 , #10612

I tried to to test myself the sample rate of the ADC and The issue I am facing is that changing .sample_freq_hz doesn't have an effect on the ADC1_DONE_INT Interrupt (check ESP32s3 TRM Register 39.72. APB_SARADC_INT_ENA_REG (0x005C) .

I am checking the sampling rate by toggling a GPIO15 at APB_ADC_INT interrupt. but the Interrupt frequency does not seem to change when I change .sample_freq_hz

This is what I get. the GPIO is toggled inside the interrupt, so the expected behavior's is that the GPIO is toggled at the same frequency I set for the ADC sample rate. But it is always fixed at around 1.4MHZ

Here is my source code and the picture from the scope.

/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_adc/adc_continuous.h"

#include "soc/gpio_periph.h"
#include "soc/soc_caps.h"
#include "hal/gpio_ll.h"
#include "hal/gpio_types.h"
#include "soc/soc.h"    
#include "soc/gpio_sig_map.h"

#include "soc/soc.h"
#include "soc/apb_saradc_reg.h"
#include "rom/ets_sys.h"
#include "xtensa/xtensa_api.h"

#define EXAMPLE_READ_LEN   8
#define GET_UNIT(x)        ((x>>3) & 0x1)

#define ADC_CONV_MODE       ADC_CONV_BOTH_UNIT
#define ADC_OUTPUT_TYPE     ADC_DIGI_OUTPUT_FORMAT_TYPE2

static adc_channel_t channel[2] = {ADC_CHANNEL_2, (ADC_CHANNEL_0 | 1 << 3)};

uint32_t cb_num = 0; 
static const char *TAG = "EXAMPLE";

void IRAM_ATTR my_int(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    //TOGGLE GPIO
    (&GPIO)->out_w1ts = (1 << 15);
    (&GPIO)->out_w1tc = (1 << 15);
    cb_num++; 
}

static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num, adc_continuous_handle_t *out_handle)
{
    adc_continuous_handle_t handle = NULL;

    adc_continuous_handle_cfg_t adc_config = {
        .max_store_buf_size = 32,
        .conv_frame_size = EXAMPLE_READ_LEN,
    };
    adc_continuous_new_handle(&adc_config, &handle);

    adc_continuous_config_t dig_cfg = {
        .sample_freq_hz = 10 * 1000,
        .conv_mode = ADC_CONV_BOTH_UNIT,
        .format = ADC_DIGI_OUTPUT_FORMAT_TYPE2,
    };

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
    dig_cfg.pattern_num = channel_num;
    for (int i = 0; i < channel_num; i++) {
        uint8_t unit = GET_UNIT(channel[i]);
        uint8_t ch = channel[i] & 0x7;
        adc_pattern[i].atten = ADC_ATTEN_DB_11;
        adc_pattern[i].channel = ch;
        adc_pattern[i].unit = unit;
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
    }
    dig_cfg.adc_pattern = adc_pattern;

    adc_continuous_config(handle, &dig_cfg);

    *out_handle = handle;
}

static bool check_valid_data(const adc_digi_output_data_t *data)
{
    const unsigned int unit = data->type2.unit;
    if (unit > 2) return false;
    if (data->type2.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false;

    return true;
}

void app_main(void)
{
    //Set GPIO as OUTPUT
    (&GPIO)->enable_w1ts = (0x1 << 15);
    esp_err_t ret;
    uint32_t ret_num = 0;
    uint8_t result[EXAMPLE_READ_LEN] = {0};
    memset(result, 0xcc, EXAMPLE_READ_LEN);

    adc_continuous_handle_t handle = NULL;
    continuous_adc_init(channel, sizeof(channel) / sizeof(adc_channel_t), &handle);

    /*Setting up the Interrupt*/
    /*APB_SARADC_ADC1_DONE_INT: Triggered when SAR ADC1 completes one data conversion.*/
    REG_SET_BIT(APB_SARADC_INT_ENA_REG, APB_SARADC_ADC1_DONE_INT_ENA); 
    xt_ints_off(1<<13);
    intr_matrix_set(0, 65, 13);
    xt_ints_on(1<<13);
    xt_set_interrupt_handler(13,  my_int, NULL); 

    ESP_ERROR_CHECK(adc_continuous_start(handle));

    while(1) {
        while (1) {
            ret = adc_continuous_read(handle, result, EXAMPLE_READ_LEN, &ret_num, 0);

            if (ret == ESP_OK) {
                ESP_LOGI("TASK", "ret is %d, ret_num is %"PRIu32, ret, ret_num);
                ESP_LOGI("TASK", "cb_num %ld" , cb_num);
                for (int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) {
                    adc_digi_output_data_t *p = (void*)&result[i];
                    if (ADC_CONV_MODE == ADC_CONV_BOTH_UNIT || ADC_CONV_MODE == ADC_CONV_ALTER_UNIT) {
                        if (check_valid_data(p)) {
                            ESP_LOGI(TAG, "Unit: %d,_Channel: %d, Value: %d", p->type2.unit+1, p->type2.channel, p->type2.data);
                        } else {
                            ESP_LOGI(TAG, "Invalid data [%d_%d_%x]", p->type2.unit+1, p->type2.channel, p->type2.data);
                        }
                    }
                }
                vTaskDelay(1);
            } 
        }
    }  
}

Continous ADC INT DONE

lukasfischer83 commented 1 month ago

Hi 5ami, did you try to reset the interrupt flag in your ISR? REG_SET_BIT(APB_SARADC_INT_CLR_REG, APB_SARADC_ADC1_DONE_INT_CLR); BR, Lukas