espressif / esp-idf

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

ESP32-S3 - ADC monitor interrupt not working (IDFGH-13988) #14814

Closed 3w3rt0n closed 2 weeks ago

3w3rt0n commented 4 weeks ago

Answers checklist.

IDF version.

v5.3

Operating System used.

Windows

How did you build your project?

Command line with Make

If you are using Windows, please specify command line type.

CMD

What is the expected behavior?

The adc_monitor interrupt is not being generated.

Captura de tela 2024-11-01 151115

With a threshold of 1500, interruption does not occur.

What is the actual behavior?

Continuous ADC reading works but threshold interrupt is not generated

Steps to reproduce.

The code is based on the continuous reading example and with the modifications indicated in the documentation: Example Continuous Read Analog to Digital Converter (ADC) Continuous Mode Driver - Monitor

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

#define EXAMPLE_ADC_UNIT                    ADC_UNIT_1
#define _EXAMPLE_ADC_UNIT_STR(unit)         #unit
#define EXAMPLE_ADC_UNIT_STR(unit)          _EXAMPLE_ADC_UNIT_STR(unit)
#define EXAMPLE_ADC_CONV_MODE               ADC_CONV_SINGLE_UNIT_1
#define EXAMPLE_ADC_ATTEN                   ADC_ATTEN_DB_0
#define EXAMPLE_ADC_BIT_WIDTH               SOC_ADC_DIGI_MAX_BITWIDTH

#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE1
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type1.channel)
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type1.data)
#else
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE2
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type2.channel)
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type2.data)
#endif

#define EXAMPLE_READ_LEN                    256

static adc_channel_t channel[1] = {ADC_CHANNEL_5};

static TaskHandle_t s_task_handle;
static const char *TAG = "EXAMPLE";
static bool threshold = false;

static bool IRAM_ATTR monitor_event(adc_monitor_handle_t monitor_handle, const adc_monitor_evt_data_t *event_data, void *user_data){
    threshold = true;
    return true;
}

static bool IRAM_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    BaseType_t mustYield = pdFALSE;
    vTaskNotifyGiveFromISR(s_task_handle, &mustYield);
    return (mustYield == pdTRUE);
}

void app_main(void)
{
    esp_err_t ret;
    uint32_t ret_num = 0;
    uint8_t result[EXAMPLE_READ_LEN] = {0};
    memset(result, 0xcc, EXAMPLE_READ_LEN);

    s_task_handle = xTaskGetCurrentTaskHandle();    

    adc_continuous_handle_t handle = NULL;
    adc_continuous_handle_cfg_t adc_config = {
    .max_store_buf_size = 1024,
    .conv_frame_size = 256,
    };
    ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, &handle));

    adc_continuous_config_t dig_cfg = {
        .sample_freq_hz = 20 * 1000,
        .conv_mode = EXAMPLE_ADC_CONV_MODE,
        .format = EXAMPLE_ADC_OUTPUT_TYPE,
    };

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0};
    dig_cfg.pattern_num = 1;
    adc_pattern[0].atten = EXAMPLE_ADC_ATTEN;
    adc_pattern[0].channel = channel[0] & 0x7;
    adc_pattern[0].unit = EXAMPLE_ADC_UNIT;
    adc_pattern[0].bit_width = EXAMPLE_ADC_BIT_WIDTH;

    ESP_LOGI(TAG, "adc_pattern[%d].atten is :%"PRIx8, 0, adc_pattern[0].atten);
    ESP_LOGI(TAG, "adc_pattern[%d].channel is :%"PRIx8, 0, adc_pattern[0].channel);
    ESP_LOGI(TAG, "adc_pattern[%d].unit is :%"PRIx8, 0, adc_pattern[0].unit);

    dig_cfg.adc_pattern = adc_pattern;
    ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg));

    adc_continuous_evt_cbs_t cbs = {
        .on_conv_done = s_conv_done_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(handle, &cbs, NULL));

    //START ADC_MONITOR
    adc_monitor_handle_t monitor_handle;
    adc_monitor_config_t monitor_config = {
    .adc_unit = ADC_UNIT_1,
        .channel = ADC_CHANNEL_5,
        .h_threshold = 1500,     
    .l_threshold = 1000,
    };

    adc_monitor_evt_cbs_t cbs_monitor = {
        .on_over_high_thresh = monitor_event,
        .on_below_low_thresh = monitor_event,
    };

    ESP_ERROR_CHECK(adc_new_continuous_monitor(handle, &monitor_config, &monitor_handle));
    ESP_ERROR_CHECK(adc_continuous_monitor_register_event_callbacks(monitor_handle, &cbs_monitor, NULL));
    ESP_ERROR_CHECK(adc_continuous_monitor_enable(monitor_handle));
    //END ADC_MONITOR

    ESP_ERROR_CHECK(adc_continuous_start(handle));

    while (1) {

        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        char unit[] = EXAMPLE_ADC_UNIT_STR(EXAMPLE_ADC_UNIT);

        while (1) {
            ret = adc_continuous_read(handle, result, EXAMPLE_READ_LEN, &ret_num, 0);
            if(threshold){              
                ESP_LOGI(TAG, ":: Threshold\n");  
                threshold = false;
            }
            if (ret == ESP_OK) {
                ESP_LOGI("TASK", "ret is %x, ret_num is %"PRIu32" bytes", ret, ret_num);
                for (int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) {
                    adc_digi_output_data_t *p = (adc_digi_output_data_t*)&result[i];
                    uint32_t chan_num = EXAMPLE_ADC_GET_CHANNEL(p);
                    uint32_t data = EXAMPLE_ADC_GET_DATA(p);
                    if (chan_num < SOC_ADC_CHANNEL_NUM(EXAMPLE_ADC_UNIT)) {
                        ESP_LOGI(TAG, "Unit: %s, Channel: %"PRIu32", Value: %d", unit, chan_num, (int)data);
                    } else {
                        ESP_LOGW(TAG, "Invalid data [%s_%"PRIu32"_%"PRIx32"]", unit, chan_num, data);
                    }
                }
                vTaskDelay(10);
            } else if (ret == ESP_ERR_TIMEOUT) {
                //We try to read `EXAMPLE_READ_LEN` until API returns timeout, which means there's no available data
                break;
            }
        }
    }

   // ESP_ERROR_CHECK(adc_continuous_stop(handle));
    //ESP_ERROR_CHECK(adc_continuous_deinit(handle));
}

Build or installation Logs.

The code does not present any errors or warnings during build or execution.

More Information.

No response

suda-morris commented 3 weeks ago

Same issue as https://github.com/espressif/esp-idf/issues/14769

The fix is on the way.

3w3rt0n commented 3 weeks ago

After applying the fix it resolved FIX

ESP-IDF5 3CMD-_C__Espressif_idf_cmd_init bat_esp-idf-a17d7b1518671c927cc6cd0b489a718c-python exe_C__Espressif_frameworks_esp-idf-v5 3_tools_idf py_-pCOM16flashmonitor2024-11-0510-09-59-ezgif com-crop

The serial print has a delay in this code, the threshold occurs exactly when I change the value of the potentiometer.

Thanks @suda-morris and I'm waiting for the merge into the official version, expected correction?