Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADC in continous mode STOPS when using FATFS (IDFGH-14463) #15237

Open
3 tasks done
FrankBJensen opened this issue Jan 20, 2025 · 56 comments
Open
3 tasks done

ADC in continous mode STOPS when using FATFS (IDFGH-14463) #15237

FrankBJensen opened this issue Jan 20, 2025 · 56 comments
Assignees
Labels
Status: Opened Issue is new Type: Bug bugs in IDF

Comments

@FrankBJensen
Copy link

FrankBJensen commented Jan 20, 2025

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

5.3.0

Espressif SoC revision.

ESP32-S3-N16R8V

Operating System used.

Windows

How did you build your project?

VS Code IDE

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

None

Development Kit.

Custom board

Power Supply used.

External 3.3V

What is the expected behavior?

That the ADC keeps sampling continously

What is the actual behavior?

The ADC stops sampling with an TIMEOUT error, when I use FatFS to store a file.

Steps to reproduce.

  1. I have this task running, sampling from 4 inputs in continous mode. I never stops the task, it is free running, and I just grab data, when I need it.
MyADs::MyADs() {

    setStamData(STAT_ADS, "", 0);
    setTaskInfo(TASK_ADS, ADS_TASK, ADS_CORE);

    uint16_t vars = sizeof(reglist_ads)/sizeof(regStruct_ads);
        GVs->ZNZ        = (MBUS*)heap_caps_malloc(sizeof(MBUS[vars]), MALLOC_CAP_SPIRAM);
    if (GVs->ZNZ != NULL) ESP_LOGW("MEM", "ZNZ initialized OK, size: %i, len: %i", heap_caps_get_allocated_size(GVs->ZNZ), sizeof(MBUS[vars]));

    std::fill(GVs->ZNZ, GVs->ZNZ + vars, MBUS());

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();
    adc_progress = xEventGroupCreate();

    begin();
}

MyADs::~MyADs() {

    if (taskHandle != NULL) {

        // Signal the task to stop
        xEventGroupSetBits(adc_event_group, ADC_TASK_STOP_BIT);
        xEventGroupSetBits(adc_progress, BIT15);

        // Wait a bit for the task to terminate
        vTaskDelay(pdMS_TO_TICKS(1000)); 

        if (adc_cali_handle != NULL) {
            esp_err_t ret = adc_cali_delete_scheme_curve_fitting(adc_cali_handle);
            if (ret != ESP_OK) {
                ESP_LOGE(TAG, "Failed to delete ADC calibration scheme: %d", ret);
            }

            adc_cali_handle = NULL; // Clear the handle after deletion
        }

        // Pause, disable, and deinitialize the timer
        timer_pause(TIMER_GROUP_0, TIMER_0);
        timer_disable_intr(TIMER_GROUP_0, TIMER_0);
        timer_deinit(TIMER_GROUP_0, TIMER_0);

        // Delete the task now that it has stopped
//        vTaskDelete(taskHandle);
        taskHandle = NULL; // Clear the task handle after deletion

        ESP_LOGE(TAG, "All free !!!!!!");
        stopTask(TASK_ADS);
//        stopStat(STAT_ADS); Er lige fjernet, for at kunne sidste besked i statestik manager
    }

    if (GVs->ZNZ != NULL) heap_caps_free(GVs->ZNZ);
    GVs->ZNZ = NULL;
    if (result != NULL) heap_caps_free(result);
    result = NULL;
}

void MyADs::begin() {

    gpio_config_t io_conf;
    io_conf.intr_type = GPIO_INTR_POSEDGE; // GPIO_INTR_ANYEDGE ;
    io_conf.pin_bit_mask = 1ULL << IO_PW;
    io_conf.mode = GPIO_MODE_INPUT;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    gpio_config(&io_conf);

    timer_config_t config = {
        .alarm_en = TIMER_ALARM_DIS,
        .counter_en = TIMER_PAUSE,
        .counter_dir = TIMER_COUNT_UP,
        .auto_reload = TIMER_AUTORELOAD_EN,
        .divider = 80  // 1us per tick
    };

    timer_init(TIMER_GROUP_0, TIMER_0, &config);
    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL);

    gpio_install_isr_service(0);
    gpio_isr_handler_add(IO_PW, gpio_isr_handler, (void *)IO_PW);

    xTaskCreatePinnedToCore(
        this->_task_adc,            /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        ADS_TASK,                   /* Priority of the task. */
        &taskHandle,                /* Task handle. */
        ADS_CORE);
}

// =============== Conversion Done Callback: ========================================================
static bool IRAM_ATTR adc_conversion_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

//    ESP_EARLY_LOGE(TAG, "Conversion done");

//    BaseType_t must_yield = pdFALSE;

    // Notify "store" task that a frame has finished.
//    vTaskNotifyGiveFromISR(l_store_task_handle, &must_yield);

    return (false);
}


// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    // OVERFLOW! We don't expect this to happen, so generate exception.
//    assert(false);

//    ESP_EARLY_LOGE(TAG, "Overflow");

    return false; // Ssouldn't get to here.
}

void MyADs::_task_adc(void* parameter)
{

ESP_LOGE(TAG, "Boot");
vTaskDelay(2000/portTICK_PERIOD_MS);
ESP_LOGE(TAG, "before ADC, waiting for HZ");

    uint32_t samplefreq = 40000;
    while (pulse_data.hz < 45) {
        vTaskDelay(pdMS_TO_TICKS(1000)); 
    }
    if (pulse_data.hz > 55) samplefreq = 48000;

    if (samplefreq == 40000) ESP_LOGW(TAG, "50 Hz detected");
    if (samplefreq == 48000) ESP_LOGW(TAG, "60 Hz detected");

// Init calibration

//    adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

    int voltage = 0;
    uint16_t baseline = 1360;
    uint64_t baselinesum = 0;
    uint16_t baselinecount = 0;

// Configure AD for multiplex

    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
//    adc_continuous_handle_t handle{nullptr};

    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = samplefreq;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
//        .on_conv_done = adc_conversion_done_cb,
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    uint8_t adc_index = 0;
    uint8_t  adc_mask[12] = { 1, 0, 2, 0, 0, 0, 0, 0, 6, 0, 0, 0 };

    bool bHasBeenNegative = false;

    uint16_t countHigh = 0;
    uint16_t countLow = 0;
    uint16_t grafCount = 0;
    uint16_t sampleCount = 0;
    uint16_t periodCount = 0;

    curve_data_t* curve_data;
    point_data_t* cpoint;
    for (int n=0; n<7; n++) {
        curve_data = &GVs->SessionData->curve_data[n];
        for(int nCh=0; nCh<SCOP_BUF; nCh++) {
            cpoint = &curve_data->cp[nCh];
            cpoint->count = 0;
            cpoint->graf_average = 0;
            cpoint->sample_sum = 0;
        }
        curve_data->baseline = 0;
    }

    EventBits_t bits = xEventGroupWaitBits(adc_event_group, ADC_TASK_STOP_BIT, pdFALSE, pdTRUE, 0);

    UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
    ESP_LOGW(TAG, "--------------------- Highwatermark MyADs: %u ---------------------", uxHighWaterMark);

    xEventGroupSetBits(adc_progress, BIT0);

    for(;;) {

        uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
        if (uxHighWaterMark < 500) {
            ESP_LOGW(TAG, "--------------------- Highwatermark MyADs: %u  ---------------------", uxHighWaterMark);
        };

//        memset(result, 0xcc, ADC_BUFFER_SIZE);
        uint32_t ret_num = 0;

        while (1) {

            EventBits_t bits = xEventGroupGetBits(adc_event_group);
            if (bits & ADC_TASK_OVERFLOW_BIT) {
                ESP_LOGE(TAG, "ADC buffer overflow detected!");
                xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
            }

            bits = xEventGroupGetBits(adc_progress);
            if (bits & BIT10) { // TIMEOUT
                ESP_LOGE(TAG, "TIMEOUT, LOGGING STOPPED!");
                esp_log_level_set("*", ESP_LOG_NONE); // Disable all logging
            }

            xEventGroupClearBits(adc_progress, 0x7FFE); // pånær stop og start bit
            xEventGroupSetBits(adc_progress, BIT1);

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 1000);

            xEventGroupSetBits(adc_progress, BIT2);

            if (ret_adc == ESP_OK) {

                xEventGroupSetBits(adc_progress, BIT3);

                if (ret_adc != 0 || ret_num > ADC_FRAME_SIZE) ESP_LOGE(TAG, "ret is %x, ret_num is %"PRIu32" bytes", ret_adc, 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];

                    xEventGroupSetBits(adc_progress, BIT4);

                    ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle, p->type2.data, &voltage));
//                  ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, ADC_CHANNEL_8, voltage);

                    // Check the channel number validation, the data is invalid if the channel num exceed the maximum channel 
                    if (p->type2.channel < SOC_ADC_CHANNEL_NUM(EXAMPLE_ADC_UNIT)) {

                        xEventGroupSetBits(adc_progress, BIT5);

                        if (p->type2.channel == ADC_CHANNEL_8) {

                            xEventGroupSetBits(adc_progress, BIT6);

                            if (voltage >= baseline || (countHigh > 0 && countHigh < 140)) {

                                xEventGroupSetBits(adc_progress, BIT7);

                                countHigh++;

                                if (bHasBeenNegative) {

                                    if (countLow > 0) { // Sp gar den lige været i low
                                        countLow = 0;

                                        grafCount += sampleCount;
                                        sampleCount = 0;

                                        periodCount++;

                                        if (baselinecount > 0) {

                                            baseline = uint16_t(baselinesum/baselinecount);
                                            baselinesum = 0;
                                            baselinecount = 0;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                countLow++;
                                if (countLow > 10) {
                                    bHasBeenNegative = true;
                                    countHigh = 0;
                                }
                            }
                        
                            baselinesum += voltage;
                            baselinecount++;

                            // Hvis den af en eller anden grund ikke nulstilles, så tag average a 1000 målinger (1 sec. målingeer)
                            if (baselinecount > 10000) {
                                baseline = uint16_t(baselinesum/baselinecount);
                                baselinesum = 0;
                                baselinecount = 0;

                                if (baseline < 1300) baseline = 1360;
                                if (baseline > 1420) baseline = 1360;

                                ESP_LOGE(TAG, "------------------------------------- baseling initialization --------------------------------");
                            }
                        }

                        adc_index = adc_mask[p->type2.channel];
                        if (periodCount > 0 && adc_index < 7) {

                            xEventGroupSetBits(adc_progress, BIT8);

                            curve_data_t* cdata = &GVs->SessionData->curve_data[adc_index];
                            point_data_t* cpoint = &cdata->cp[sampleCount];

                            if (cpoint->count < SCOP_BUF) {
                                cpoint->sample_sum += voltage;
                                cpoint->count++;
                            }
                            if (sampleCount < SCOP_BUF && p->type2.channel == ADC_CHANNEL_8) sampleCount++;

                            if (periodCount >= NUM_SAMPLES) { // 100 samples = 2 sec

                                xEventGroupSetBits(adc_progress, BIT9);

                                uint16_t nSamples = grafCount/(periodCount-1);

                                ESP_LOGW(TAG, "------------------------------------- calc --------------------------------, grafCount: %u, samples: %u, periodcount: %u, baseline: %u", grafCount, nSamples, periodCount, baseline);

                                setTaskStart(TASK_ADS);
                                char buf[40] = "";
                                sprintf(buf, "%u, %u, %u, %u", grafCount, nSamples, periodCount, baseline);
                                setMessage(STAT_ADS, buf);
                                calculateRMS(nSamples, baseline);
                                setTaskEnd(TASK_ADS, ADS_STACK, uxHighWaterMark);

                                bHasBeenNegative = false;
                                grafCount = 0;
                                periodCount = 0;
                                sampleCount = 0;
                                countHigh = 0;
                                countLow = 0;
                            }
                        }
                    }
                }
//                vTaskDelay(1);

            } else if (ret_adc == ESP_ERR_TIMEOUT) {
                //We try to read `EXAMPLE_READ_LEN` until API returns timeout, which means there's no available data
//                setMessage(STAT_ADS, "Error ESP_ERR_TIMEOUT");
                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_progress, BIT10);
                break; // stop med at hente data fra ADC
            }

            bits = xEventGroupWaitBits(adc_event_group, ADC_TASK_STOP_BIT, pdFALSE, pdTRUE, 0);
            if (bits & ADC_TASK_STOP_BIT) {
                break;  // Exit the loop and terminate task
            }
        }
//        vTaskDelay(1);

        if (bits & ADC_TASK_STOP_BIT) {
            setMessage(STAT_ADS, "Error ADC_TASK_STOP_BIT");
            ESP_LOGE(TAG, "Error ADC_TASK_STOP_BIT");
            xEventGroupSetBits(adc_progress, BIT11);
            break;  // Exit the loop and terminate task
        }
    }

    xEventGroupSetBits(adc_progress, BIT14);

    ESP_LOGI(TAG, "ADC task exiting");
    setStatus(STAT_ADS, "OFFLINE");

// Proceed to stop and deinitialize the ADC
    if (adc_handle != NULL) {
        esp_err_t ret = adc_continuous_stop(adc_handle);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "Failed to stop ADC continuous mode: %d", ret);
        }

        ret = adc_continuous_deinit(adc_handle);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "Failed to deinitialize ADC continuous handle: %d", ret);
        }
        adc_handle = NULL; // Clear the handle after deinitialization
    }

    GVs->settings->clamps.clampModel = 0; // This will delete task. Try again ??
    setCommActive(STAT_ADS, COL_RED);
    // sæt denne værdi til eksempelvis FF og få main task til at restarte task

    vTaskDelete(NULL);
}

When I run this below (around 11K totally is stored), the ADC goes into timeout, and never recovers. I have read about this problem under heavy load in 5.0.2, but has it been solved? I do have a heavy load, around 70% in the ADC task, and initially the task (not same task) that uses the filesystem was running on same core, but moving that task to the second core, did not make any difference.

char buf[40] = "";
sprintf(buf, "/fatfs/%s-%ld.bin", name, FileFimeStamp);
printf("Save file: %s\n", buf);

// Serialize the struct to a file
FILE* outFile = fopen(buf, "wb");
if (outFile == NULL) {
    ESP_LOGE("FATFS", "Failed to open file for writing: %s", buf);
    perror("Error"); // This will print a more detailed error

    xSemaphoreGive(xMutexFatFS);
    return false;
}

size_t written = 0;
while (written < size) {
    size_t to_write = (size - written) < 512 ? (size - written) : 512;
    fwrite(data + written, 1, to_write, outFile);
    written += to_write;
    vTaskDelay(1); // Delay for 1 millisecond
}

//            fwrite(data, size, 1, outFile);
fclose(outFile);

Debug Logs.

There is no crash, but the FATFS runs once every hour, and then its like the ADC DMA simply stops

---- Everything running fine, calculating from ADC every second
I (550218) ads: Calculated: 0:-0.00 1:-0.00 2:-0.00
Save file: /fatfs/GRAPH-1737360000.bin
Save file: /fatfs/METER_GRID-1737360000.bin
Save file: /fatfs/METER_SUN-1737360000.bin
I (552088) kmq: Compare1: 49: DSP alarm code - 8400 0.00
E (552148) ads: Error ESP_ERR_TIMEOUT
E (552148) ads: TIMEOUT, LOGGING STOPPED!

More Information.

I tried to separate the 2 tasks on different cores - does not help.
I have tried to increase the ADC buffers, and funny enough, when the buffer is real big, like 10K, sometimes it surveives the filewrite, but ADC still stops most of the times
There is no overrun of the buffer
There is no memory leaks or nothing
I have changed my FATFS to write in bulks with a delay, to make sure there are time for the ADC task. The ADC task have hightst priority of all my tasks.
The task just keeps looping with ESP_ERR_TIMEOUT and do not recover

@FrankBJensen FrankBJensen added the Type: Bug bugs in IDF label Jan 20, 2025
@github-actions github-actions bot changed the title ADC in continous mode STOPS when using FATFS ADC in continous mode STOPS when using FATFS (IDFGH-14463) Jan 20, 2025
@espressif-bot espressif-bot added the Status: Opened Issue is new label Jan 20, 2025
@FrankBJensen
Copy link
Author

Making this trick when there is a timeout, makes it run another hour, until FATFS is active again

adc_continuous_stop(adc_handle);
vTaskDelay(1);
adc_continuous_start(adc_handle);

@safocl
Copy link

safocl commented Jan 20, 2025

gpio_isr_handler_add(IO_PW, gpio_isr_handler, (void *)IO_PW);

is this code correct? (IO_PW reinterpret to void*). If gpio_isr_handler uses this pointer, perhaps this is undefined behavior?

@FrankBJensen
Copy link
Author

Hi Safocl.

I only use this interupt to detect, if incomming is 50 or 60Hz. It does not interfear with the ADC at all, except I set the sampling frequency to 40 or 48 KHz when initializing, in order to have same number of samples for a period (200 samples).

void MyADs::gpio_isr_handler(void *arg)
{
    pulse_data.timestamp = esp_timer_get_time(); // uS
    if (pulse_data.timestamp - pulse_data.last_timestamp < 15000) return;

    pulse_data.count = pulse_data.count +1;
    
    pulse_data.pulse_width = pulse_data.timestamp - pulse_data.last_timestamp;
    pulse_data.hz = 1.0 / ((double)pulse_data.pulse_width * 1e-6);

    pulse_data.last_timestamp = pulse_data.timestamp;
}

This also do not explain, why the error occurs, exactly every whole hour, when I run the FATFS task. Also at 14:00, 15:00, 16:00 etc.

@FrankBJensen
Copy link
Author

FrankBJensen commented Jan 20, 2025

Here is a standalone code, ready for you to compile and run. It replicates the fault. As soon as the fasfs is called, the ADC have a TIMEOUT, and do not recover

This is the log

I (33883) ads: Data OK
I (33883) ads: Data OK
I (33883) ads: Data OK
I (33883) ads: Data OK
I (33883) ads: Data OK
I (33883) ads: Data OK
I (33883) ads: Data OK
I (33893) ads: Data OK
I (33893) ads: Data OK
I (33893) ads: Data OK
I (33893) ads: Data OK
I (33893) ads: Data OK
I (33893) ads: Data OK
I (33903) ads: Data OK
I (33903) ads: Data OK
I (33903) ads: Data OK
I (33903) ads: Data OK
I (33903) ads: Data OK
I (33903) ads: Data OK
Save file: /fatfs/TESTFILE-1000.bin
I (33913) ads: Data OK
I (33913) ads: Data OK
I (33913) ads: Data OK
I (33913) ads: Data OK
I (33913) ads: Data OK
I (33913) ads: Data OK
I (33913) ads: Data OK
E (38913) ads: Error ESP_ERR_TIMEOUT
E (38913) ads: TIMEOUT, LOGGING STOPPED!
E (43913) ads: Error ESP_ERR_TIMEOUT
E (43913) ads: TIMEOUT, LOGGING STOPPED!
E (48913) ads: Error ESP_ERR_TIMEOUT
E (48913) ads: TIMEOUT, LOGGING STOPPED!
E (53913) ads: Error ESP_ERR_TIMEOUT
E (53913) ads: TIMEOUT, LOGGING STOPPED!
E (58913) ads: Error ESP_ERR_TIMEOUT
E (58913) ads: TIMEOUT, LOGGING STOPPED!
E (63913) ads: Error ESP_ERR_TIMEOUT
E (63913) ads: TIMEOUT, LOGGING STOPPED!
Save file: /fatfs/TESTFILE-1000.bin
E (68913) ads: Error ESP_ERR_TIMEOUT
E (68913) ads: TIMEOUT, LOGGING STOPPED!
E (73913) ads: Error ESP_ERR_TIMEOUT
E (73913) ads: TIMEOUT, LOGGING STOPPED!

Complete code to replicate

extern "C"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"

#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_timer.h"

#include <cmath>
#include "driver/gpio.h"
#include "driver/gptimer.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_timer.h"
#include "driver/timer.h"

#include <algorithm>
#include "esp_vfs_fat.h"

#define SCOP_BUF            210
#define SCOP_CYC              5
#define NUM_SAMPLES          50      // 100   195   450 svarer til 4.5 sekund, oversampling value
#define ADS_STACK          6000      //  3500
#define ADC_BUFFER_SIZE    2048      // 10240
#define ADC_FRAME_SIZE      256      //  2560

#define ADC_TASK_STOP_BIT       (1 << 0)
#define ADC_TASK_OVERFLOW_BIT   (1 << 1)
#define ADC_TASK_TIMEOUT_BIT    (1 << 2)
#define ADC_TASK_READY_BIT      (1 << 3)

static const char *TAGFS = "FATFS";
bool fatfs_Struct(void* data, size_t size, const char* name, long FileFimeStamp);

struct TESTFILE {
    char test[10000];
};

class MyADs {

    private:
        TaskHandle_t taskHandle = NULL;

        static void _task_adc(void* parameter);
        static void calculateRMS(uint16_t grafCount, uint16_t baseline);
        static void IRAM_ATTR gpio_isr_handler(void *arg);
        void begin();

    public:
        MyADs();
        ~MyADs();
};

const char *path = "/fatfs";
wl_handle_t s_wl_handle;

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    bool startADC = true;
    TESTFILE* test_file;
    test_file  = (TESTFILE*)heap_caps_malloc(sizeof(TESTFILE), MALLOC_CAP_SPIRAM);
if (test_file != NULL) ESP_LOGW("MEM", "Testfile initialized OK, size: %i, len: %i", heap_caps_get_allocated_size(test_file), sizeof(TESTFILE));
    *test_file = TESTFILE();

    long task_threadchecker = esp_timer_get_time()/1000;
    long task_filesave = esp_timer_get_time()/1000;
    MyADs* ADs = NULL;

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
    ESP_LOGW("MAIN", "--------------------- Highwatermark Main: %u ---------------------", uxHighWaterMark);

    for(;;) {

        if (esp_timer_get_time()/1000 - task_threadchecker > 10000) {
            task_threadchecker = esp_timer_get_time()/1000;

            if (ADs != NULL && !startADC) {
                delete ADs;
                ADs = NULL;
            }
            if (ADs == NULL && startADC) ADs = new MyADs();
        }

        if (esp_timer_get_time()/1000 - task_filesave > 30000) {
            task_filesave = esp_timer_get_time()/1000;

            fatfs_Struct(&test_file, sizeof(TESTFILE), "TESTFILE", 1000);
        }

        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

static const char *TAG = "ads";

adc_cali_handle_t adc_cali_handle;
adc_continuous_handle_t adc_handle{nullptr};
uint8_t* result = NULL;

EventGroupHandle_t adc_event_group = NULL;

MyADs::MyADs() {

    ESP_LOGI(TAG, "ADC construct");

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();

    begin();
}

MyADs::~MyADs() {

    ESP_LOGI(TAG, "ADC deconstruct");

    if (taskHandle != NULL) {

        // Signal the task to stop
        xEventGroupSetBits(adc_event_group, ADC_TASK_STOP_BIT);

        // Wait a bit for the task to terminate
        vTaskDelay(pdMS_TO_TICKS(1000)); 

        if (adc_cali_handle != NULL) {
            esp_err_t ret = adc_cali_delete_scheme_curve_fitting(adc_cali_handle);
            if (ret != ESP_OK) {
                ESP_LOGE(TAG, "Failed to delete ADC calibration scheme: %d", ret);
            }

            adc_cali_handle = NULL; // Clear the handle after deletion
        }

        // Pause, disable, and deinitialize the timer
        timer_pause(TIMER_GROUP_0, TIMER_0);
        timer_disable_intr(TIMER_GROUP_0, TIMER_0);
        timer_deinit(TIMER_GROUP_0, TIMER_0);

        taskHandle = NULL; // Clear the task handle after deletion

        ESP_LOGE(TAG, "All free !!!!!!");
    }

    if (result != NULL) heap_caps_free(result);
    result = NULL;
}

void MyADs::begin() {

    xTaskCreatePinnedToCore(
        this->_task_adc,            /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        &taskHandle,                /* Task handle. */
        1);
}

// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

    return false; // Ssouldn't get to here.
}

void MyADs::_task_adc(void* parameter)
{

ESP_LOGE(TAG, "Boot");
vTaskDelay(2000/portTICK_PERIOD_MS);
ESP_LOGE(TAG, "before ADC, waiting for HZ");

// Init calibration

//    adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

// Configure AD for multiplex

    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
//    adc_continuous_handle_t handle{nullptr};

    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = 40000;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    EventBits_t bits = xEventGroupWaitBits(adc_event_group, ADC_TASK_STOP_BIT, pdFALSE, pdTRUE, 0);

    for(;;) {

        uint32_t ret_num = 0;

        while (1) {

            EventBits_t bits = xEventGroupGetBits(adc_event_group);
            if (bits & ADC_TASK_OVERFLOW_BIT) {
                ESP_LOGE(TAG, "ADC buffer overflow detected!");
                xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
            }
            if (bits & ADC_TASK_TIMEOUT_BIT) { // TIMEOUT
                ESP_LOGE(TAG, "TIMEOUT, LOGGING STOPPED!");
//                esp_log_level_set("*", ESP_LOG_NONE); // Disable all logging
            }

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 5000);

            if (ret_adc == ESP_OK) {
                ESP_LOGI(TAG, "Data OK");
            } else if (ret_adc == ESP_ERR_TIMEOUT) {

                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_event_group, ADC_TASK_TIMEOUT_BIT);
/*
                vTaskDelay(1);
                adc_continuous_stop(adc_handle);
                vTaskDelay(1);
                adc_continuous_start(adc_handle);
                vTaskDelay(1);
*/
                break; // stop med at hente data fra ADC
            }
        }
    }
}


bool fatfs_Struct(void* data, size_t size, const char* name, long FileFimeStamp) {

    char buf[40] = "";
    sprintf(buf, "/fatfs/%s-%ld.bin", name, FileFimeStamp);
    printf("Save file: %s\n", buf);

    // Serialize the struct to a file
    FILE* outFile = fopen(buf, "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", buf);
        perror("Error"); // This will print a more detailed error
        return false;
    }

    size_t written = 0;
    while (written < size) {
        size_t to_write = (size - written) < 512 ? (size - written) : 512;
        fwrite(data + written, 1, to_write, outFile);
        written += to_write;
        vTaskDelay(1); // Delay for 1 millisecond
    }

    fclose(outFile);

    return true;
}

@safocl
Copy link

safocl commented Jan 20, 2025

bool startADC = true;

this variable is not changed from code. it always is true.
the following code is unreachable:

if (ADs != NULL && !startADC) {
delete ADs;
ADs = NULL;
}

@safocl
Copy link

safocl commented Jan 21, 2025

driver/timer.h is deprecated

@safocl
Copy link

safocl commented Jan 21, 2025

fwrite(data + written, 1, to_write, outFile);

data is of type void* -- pointer arithmetic is not allowed.

@safocl
Copy link

safocl commented Jan 21, 2025

EventBits_t bits = xEventGroupWaitBits(adc_event_group, ADC_TASK_STOP_BIT, pdFALSE, pdTRUE, 0);

this code wait ADC_TASK_STOP_BIT bits be activate and:

[Potentially] block to wait for one or more bits to be set within a previously created event group.
but only ADC destructor set it...

(docs)

@safocl
Copy link

safocl commented Jan 21, 2025

i executed this code (with some modifications) and it gave an error.

E (7280) main: testfile don't allocated.

@FrankBJensen
Copy link
Author

You need to activate PSRAM in sdkconfig.

@FrankBJensen
Copy link
Author

I have simplified the code, the error persists.
Now I dont use PSRAM, so you should be able to run the code without PSRAM.

Log

I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18851) ADC: Data OK
I (18861) ADC: Data OK
I (18861) ADC: Data OK
I (18861) ADC: Data OK
I (18861) ADC: Data OK
I (18861) ADC: Data OK
I (18861) ADC: Data OK
Save file: /fatfs/test.bin
I (18871) ADC: Data OK
I (18871) ADC: Data OK
I (18871) ADC: Data OK
I (18871) ADC: Data OK
I (18871) ADC: Data OK
I (18871) ADC: Data OK
E (23871) ADC: Error ESP_ERR_TIMEOUT
E (23871) ADC: TIMEOUT!
E (28871) ADC: Error ESP_ERR_TIMEOUT
E (28871) ADC: TIMEOUT!

code

extern "C"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"

#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_timer.h"

#include <cmath>
#include "driver/gpio.h"
#include "driver/gptimer.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_timer.h"
#include "driver/timer.h"

#include <algorithm>
#include "esp_vfs_fat.h"

#define SCOP_BUF            210
#define SCOP_CYC              5
#define NUM_SAMPLES          50      // 100   195   450 svarer til 4.5 sekund, oversampling value
#define ADS_STACK          6000      //  3500
#define ADC_BUFFER_SIZE    2048      // 10240
#define ADC_FRAME_SIZE      256      //  2560

#define ADC_TASK_STOP_BIT       (1 << 0)
#define ADC_TASK_OVERFLOW_BIT   (1 << 1)
#define ADC_TASK_TIMEOUT_BIT    (1 << 2)
#define ADC_TASK_READY_BIT      (1 << 3)

static const char *TAGFS = "FATFS";
static const char *TAG = "ADC";

bool fatfs_Struct(void* data, size_t size);
static void _task_adc(void* parameter);

struct TESTFILE {
    char test[10000];
};

wl_handle_t s_wl_handle;
EventGroupHandle_t adc_event_group = NULL;
adc_cali_handle_t adc_cali_handle;
adc_continuous_handle_t adc_handle{nullptr};

const char *path = "/fatfs";
uint8_t* result = NULL;
uint32_t ret_num = 0;

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    TESTFILE* test_file;
    test_file  = (TESTFILE*)heap_caps_malloc(sizeof(TESTFILE), MALLOC_CAP_DEFAULT);
if (test_file != NULL) ESP_LOGW("MEM", "Testfile initialized OK, size: %i, len: %i", heap_caps_get_allocated_size(test_file), sizeof(TESTFILE));
    *test_file = TESTFILE();

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    ESP_LOGI(TAG, "ADC construct");

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();

    xTaskCreatePinnedToCore(
        _task_adc,                  /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        NULL,                       /* Task handle. */
        1);


    for(;;) {

        vTaskDelay(pdMS_TO_TICKS(15000));

        fatfs_Struct(&test_file, sizeof(TESTFILE));
    }
}

// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

    return false; // Ssouldn't get to here.
}

void _task_adc(void* parameter)
{
//   adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

// Configure AD for multiplex
    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = 40000;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    for(;;) {

        EventBits_t bits = xEventGroupGetBits(adc_event_group);
        if (bits & ADC_TASK_OVERFLOW_BIT) {
            ESP_LOGE(TAG, "ADC buffer overflow detected!");
            xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
        }
        if (bits & ADC_TASK_TIMEOUT_BIT) { // TIMEOUT
            ESP_LOGE(TAG, "TIMEOUT!");
        }

        while (1) {

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 5000);

            if (ret_adc == ESP_OK) {
                ESP_LOGI(TAG, "Data OK");
            } else if (ret_adc == ESP_ERR_TIMEOUT) {

                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_event_group, ADC_TASK_TIMEOUT_BIT);

/* This code will resume ADC if enabled
                vTaskDelay(1);
                adc_continuous_stop(adc_handle);
                vTaskDelay(1);
                adc_continuous_start(adc_handle);
                vTaskDelay(1);
*/
                break; // stop med at hente data fra ADC
            }
        }
    }
}

bool fatfs_Struct(void* data, size_t size) {

    printf("Save file: /fatfs/test.bin\n");

    // Serialize the struct to a file
    FILE* outFile = fopen("/fatfs/test.bin", "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
        perror("Error"); // This will print a more detailed error
        return false;
    }

    fwrite(data, size, 1, outFile);
    fclose(outFile);

    return true;
}

@FrankBJensen
Copy link
Author

Unless I made some stupid mistake, that I have overlooked, it seems to me, like FATFS is stopping the DMA and when the ADC buffer is empty, it goes into TIMEOUT, due to there is not comming data from the DMA anymore.

@FrankBJensen
Copy link
Author

Hmm, this is getting stranger and stranger.

  • I have tried to set char test_file[10] in stead of 10000, this makes no difference, still same result with timeout. So filesize does not seem to matter.

  • I have tried to increase ADC_BUFFER_SIZE to 20480 just to make an insane big buffer, still same result with timeout. So buffer size does not seem to matter.

  • Now it gets interesting, messing with ADC_FRAME_SIZE. When i set this to 1500, still same result with timeout. But when I increase it to 2000 - IT WORKS. No timeout. So the size of the frame matters - WHY ?

  • Then I tried to set back the char test_file[10000], then I am back, with same fault, the timeout.

  • Then I increase the ADC_FRAME_SIZE to 3000, AND IT WORKS AGAIN.

SO what is the strange relationship between the filesize that I write with FATFS and the ADC_FRAME_SIZE ?? What is going on here??

AND not to forget. When I write, IT WORKS, I do not know, if it keeps working. Remember, in my original code, it works sometimes, and fails sometimes, even though both file size and frame_size if fixed. But in order to evaluate why this is, I need to understand, the relationship between FATFS and ADC.

Notes:
I have also upgraded to 5.3.1, made no difference.
I have also tried to pin the _task_adc to the other core, made no difference.

@FrankBJensen
Copy link
Author

OK, I can now confirm, that even though it works immediately after modifications with no timeout, it fails over time, and goes into a timeout loop.

@safocl
Copy link

safocl commented Jan 21, 2025

if (test_file != NULL)

if (test_file == NULL) PRINT_ERROR is better for program execution.

@safocl
Copy link

safocl commented Jan 21, 2025

SO what is the strange relationship between the filesize that I write with FATFS and the ADC_FRAME_SIZE ?? What is going on here??

maybe there's a memory overflow going on here -- or an error that you don't catch and continue the program?

@FrankBJensen
Copy link
Author

I do have test_file == NULL check in my real code. This is minimized code to reproduce the fault I am having.

The only code running is the one you see here. Nothing else. I dont see any memory overflow anywhere. The system is running flawlessly for days, until I save a file using FATFS.

Have you tried running the code? It should now be ready to run even without PSRAM.

@FrankBJensen
Copy link
Author

Adding this gives me nothing: esp_log_level_set("adc_continuous", ESP_LOG_VERBOSE);
Is there other tags, that I can enable?

@FrankBJensen
Copy link
Author

I do not even have to write anything into the file, this generates same error

Does FATFS use DMA? I can not find any clear answers.

bool fatfs_Struct(void* data, size_t size) {

    FILE* outFile = fopen("/fatfs/test.bin", "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
        perror("Error"); // This will print a more detailed error
        return false;
    }


    uint32_t written = 0;
//    written = fwrite((uint8_t*)data, size, 1, outFile);
    fclose(outFile);

    printf("/fatfs/test.bin have been written, size: %li %lu\n", (uint32_t)size, written);

    return true;
}

@FrankBJensen
Copy link
Author

FrankBJensen commented Jan 21, 2025

The error occurs when fclose is called - not fopen.
Note I use esp_vfs_fat.h

@safocl
Copy link

safocl commented Jan 21, 2025

I do have test_file == NULL check in my real code. This is minimized code to reproduce the fault I am having.

the program continues to work even after an error, and further memory access will generate undefined behavior.

@safocl
Copy link

safocl commented Jan 21, 2025

this code generates this log

I (20819) ads: About to start ADC
E (25999) ads: Error ESP_ERR_TIMEOUT
E (26029) ads: TIMEOUT, LOGGING STOPPED!
E (31049) ads: Error ESP_ERR_TIMEOUT
E (31059) ads: TIMEOUT, LOGGING STOPPED!
E (36079) ads: Error ESP_ERR_TIMEOUT
E (36099) ads: TIMEOUT, LOGGING STOPPED!
Save file: /fatfs/TESTFILE-1000.bin
E (38339) FATFS: Failed to open file for writing: /fatfs/TESTFILE-1000.bin
Error: No such file or directory
E (41119) ads: Error ESP_ERR_TIMEOUT
E (41139) ads: TIMEOUT, LOGGING STOPPED!

the error is reached even before working with the file.

@FrankBJensen
Copy link
Author

FrankBJensen commented Jan 21, 2025

Please try the latest much simpler code

extern "C"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"

#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_timer.h"

#include <cmath>
#include "driver/gpio.h"
#include "driver/gptimer.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_timer.h"
#include "driver/timer.h"

#include <algorithm>
#include "esp_vfs_fat.h"

#define SCOP_BUF            210
#define SCOP_CYC              5
#define NUM_SAMPLES          50      // 100   195   450 svarer til 4.5 sekund, oversampling value
#define ADS_STACK          6000      //  3500
#define ADC_BUFFER_SIZE    2048      // 10240
#define ADC_FRAME_SIZE      256      //  2560

#define ADC_TASK_STOP_BIT       (1 << 0)
#define ADC_TASK_OVERFLOW_BIT   (1 << 1)
#define ADC_TASK_TIMEOUT_BIT    (1 << 2)
#define ADC_TASK_READY_BIT      (1 << 3)

static const char *TAGFS = "FATFS";
static const char *TAG = "ADC";

bool fatfs_Struct(void* data, size_t size);
static void _task_adc(void* parameter);

struct TESTFILE {
    char test[10000];
};

wl_handle_t s_wl_handle;
EventGroupHandle_t adc_event_group = NULL;
adc_cali_handle_t adc_cali_handle;
adc_continuous_handle_t adc_handle{nullptr};

const char *path = "/fatfs";
uint8_t* result = NULL;
uint32_t ret_num = 0;

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    TESTFILE* test_file;
    test_file  = (TESTFILE*)heap_caps_malloc(sizeof(TESTFILE), MALLOC_CAP_DEFAULT);
if (test_file != NULL) ESP_LOGW("MEM", "Testfile initialized OK, size: %i, len: %i", heap_caps_get_allocated_size(test_file), sizeof(TESTFILE));
    *test_file = TESTFILE();

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    ESP_LOGI(TAG, "ADC construct");

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();

    xTaskCreatePinnedToCore(
        _task_adc,                  /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        NULL,                       /* Task handle. */
        1);


    for(;;) {

        vTaskDelay(pdMS_TO_TICKS(15000));

        fatfs_Struct(&test_file, sizeof(TESTFILE));
    }
}

// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

    return false; // Ssouldn't get to here.
}

void _task_adc(void* parameter)
{
//   adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

// Configure AD for multiplex
    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = 40000;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    for(;;) {

        EventBits_t bits = xEventGroupGetBits(adc_event_group);
        if (bits & ADC_TASK_OVERFLOW_BIT) {
            ESP_LOGE(TAG, "ADC buffer overflow detected!");
            xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
        }
        if (bits & ADC_TASK_TIMEOUT_BIT) { // TIMEOUT
            ESP_LOGE(TAG, "TIMEOUT!");
        }

        while (1) {

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 5000);

            if (ret_adc == ESP_OK) {
                ESP_LOGI(TAG, "Data OK");
            } else if (ret_adc == ESP_ERR_TIMEOUT) {

                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_event_group, ADC_TASK_TIMEOUT_BIT);

/* This code will resume ADC if enabled
                vTaskDelay(1);
                adc_continuous_stop(adc_handle);
                vTaskDelay(1);
                adc_continuous_start(adc_handle);
                vTaskDelay(1);
*/
                break; // stop med at hente data fra ADC
            }
        }
    }
}

bool fatfs_Struct(void* data, size_t size) {

    printf("Save file: /fatfs/test.bin\n");

    // Serialize the struct to a file
    FILE* outFile = fopen("/fatfs/test.bin", "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
        perror("Error"); // This will print a more detailed error
        return false;
    }

    fwrite(data, size, 1, outFile);
    fclose(outFile);

    return true;
}

@safocl
Copy link

safocl commented Jan 21, 2025

The error occurs when fclose is called - not fopen.

my code do not reach to fclose

@safocl
Copy link

safocl commented Jan 21, 2025

#include "driver/timer.h"

this is deprecated -- please don't use it for code...

@FrankBJensen
Copy link
Author

Please try the latest code I just sent, its much simpler.

My partition.csv looks like this, there need to be a storage section

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x009000, 0x6000,
phy_init, data, phy,     0x00f000, 0x1000,
factory,  app,  factory, 0x010000, 2M,
otadata,  data, ota,     0x210000, 0x2000,
ota_0,    app,  ota_0,   0x220000, 2M,
ota_1,    app,  ota_1,   0x420000, 2M,
storage,  data, fat,     ,         1M,

and I have this in my platformio.ini

board_build.partitions = partition.csv

@FrankBJensen
Copy link
Author

I will make sure to exclude driver/timer.h in my real code, thank you.

@safocl
Copy link

safocl commented Jan 21, 2025

hmmm... qemu don't work with ADC? my hardware normally evaluates this code, but qemu don't (produce TIMEOUT ERROR)...

@safocl
Copy link

safocl commented Jan 21, 2025

@FrankBJensen

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x009000, 0x6000,
phy_init, data, phy,     0x00f000, 0x1000,
factory,  app,  factory, 0x010000, 2M,
otadata,  data, ota,     0x210000, 0x2000,
ota_0,    app,  ota_0,   0x220000, 2M,
ota_1,    app,  ota_1,   0x420000, 2M,
storage,  data, fat,     ,         1M,

my hardware is esp32 with 4Mib flash mem...

@FrankBJensen
Copy link
Author

If you use an emulator, do you then get data fra the ADC? I dont know....

Try this, since OTA is not in this simple example

# ESP-IDF Partition Table
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x009000, 0x6000,
phy_init, data, phy,     0x00f000, 0x1000,
factory,  app,  factory, 0x010000, 1M,
storage,  data, fat,     ,         1M,

@safocl
Copy link

safocl commented Jan 21, 2025

this code generates this log

this code on real esp32 (nodemcu-32) hardware do not produce ERROR

@safocl
Copy link

safocl commented Jan 21, 2025

Try this, since OTA is not in this simple example

I can't compile your code - it reports the error not find header files (deprecated).

@safocl
Copy link

safocl commented Jan 21, 2025

platformio.ini

I'm disappointed with platformio -- it doesn't keep up with the times (library and toolchain updates)

@FrankBJensen
Copy link
Author

FrankBJensen commented Jan 21, 2025

I have used Platformio for many years, but I do consider changing to espidf.

Hm, strange. I just compiled this code below, and it produces this log:

I (18850) ADC: Data OK
I (18860) ADC: Data OK
I (18860) ADC: Data OK
I (18860) ADC: Data OK
I (18870) ADC: Data OK
I (18870) ADC: Data OK
I (18870) ADC: Data OK
I (18870) ADC: Data OK
I (18880) ADC: Data OK
I (18880) ADC: Data OK
I (18880) ADC: Data OK
I (18890) ADC: Data OK
I (18890) ADC: Data OK
I (18890) ADC: Data OK // this after 15 seconds and a LOT of Data OK's
File opened
I (18900) ADC: Data OK
I (18900) ADC: Data OK
I (18900) ADC: Data OK
E (23900) ADC: Error ESP_ERR_TIMEOUT
E (23900) ADC: TIMEOUT!
E (28900) ADC: Error ESP_ERR_TIMEOUT
E (28900) ADC: TIMEOUT!
E (33900) ADC: Error ESP_ERR_TIMEOUT
E (33900) ADC: TIMEOUT!
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include <cmath>
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"

#include "esp_vfs_fat.h"

#define ADS_STACK          6000      //  3500
#define ADC_BUFFER_SIZE    20480      // 10240
#define ADC_FRAME_SIZE      512      //  2560

#define ADC_TASK_STOP_BIT       (1 << 0)
#define ADC_TASK_OVERFLOW_BIT   (1 << 1)
#define ADC_TASK_TIMEOUT_BIT    (1 << 2)
#define ADC_TASK_READY_BIT      (1 << 3)

static const char *TAGFS = "FATFS";
static const char *TAG = "ADC";

bool fatfs_Struct(void* data, size_t size);
static void _task_adc(void* parameter);

char test_file[10];

wl_handle_t s_wl_handle;
EventGroupHandle_t adc_event_group = NULL;
adc_cali_handle_t adc_cali_handle;
adc_continuous_handle_t adc_handle{nullptr};

const char *path = "/fatfs";
uint8_t* result = NULL;
uint32_t ret_num = 0;

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    esp_log_level_set("vfs_fat", ESP_LOG_VERBOSE);

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    ESP_LOGI(TAG, "ADC construct");

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();

    xTaskCreatePinnedToCore(
        _task_adc,                  /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        NULL,                       /* Task handle. */
        0);


    for(;;) {

        vTaskDelay(pdMS_TO_TICKS(15000));

        fatfs_Struct(test_file, sizeof(test_file));
    }
}

// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

    return false; // Ssouldn't get to here.
}

void _task_adc(void* parameter)
{
//   adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

// Configure AD for multiplex
    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = 40000;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    for(;;) {

        EventBits_t bits = xEventGroupGetBits(adc_event_group);
        if (bits & ADC_TASK_OVERFLOW_BIT) {
            ESP_LOGE(TAG, "ADC buffer overflow detected!");
            xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
        }
        if (bits & ADC_TASK_TIMEOUT_BIT) { // TIMEOUT
            ESP_LOGE(TAG, "TIMEOUT!");
        }

        while (1) {

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 5000);

            if (ret_adc == ESP_OK) {
                ESP_LOGI(TAG, "Data OK");
            } else if (ret_adc == ESP_ERR_TIMEOUT) {

                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_event_group, ADC_TASK_TIMEOUT_BIT);

/* This code will resume ADC if enabled
                vTaskDelay(1);
                adc_continuous_stop(adc_handle);
                vTaskDelay(1);
                adc_continuous_start(adc_handle);
                vTaskDelay(1);
*/
                break; // stop med at hente data fra ADC
            }
        }
    }
}

bool fatfs_Struct(void* data, size_t size) {

    FILE* outFile = fopen("/fatfs/test.bin", "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
        perror("Error"); // This will print a more detailed error
        return false;
    }

    printf("File opened\n");

//  uint32_t  written = fwrite((uint8_t*)data, size, 1, outFile);
    fclose(outFile);

//    printf("/fatfs/test.bin have been written, size: %li %lu\n", (uint32_t)size, written);

    return true;
}

@safocl
Copy link

safocl commented Jan 21, 2025

@FrankBJensen deleting the code to use FAT produces normal execution?

@FrankBJensen
Copy link
Author

Yes. Then it runs for months.

I have 7 products running my software. I only use FAT if I want to store statestics. I am only using FAT on 2 of these 7 units, the task with FAT is disabled on the 5 pcs.. And only the 2 units with FAT fails. The other 5 units never fail. One has been running more then 90 days.

This is the reason why I began to investigate this error. And then suddenly I discovered, that the error occured exactly at a whole hour, eg. 14:00:00 or 15:00:00, and that is exactly the time, where I run my statestics task.

Then I began pulling the code to bits and pieces, to find out, what caused this, ending up in me narrowing it down to the FAT save procedure. And this is where this thread started, and I copied my actual code snippets to a separate project, in order to better investigate, and have some real compilable code to post here.

@safocl
Copy link

safocl commented Jan 21, 2025

Hm, strange. I just compiled this code below, and it produces this log:

this code on my hardware reports panic error:

[0;32mI (18397) ADC: Data OK[0m
[0;32mI (18407) ADC: Data OK[0m
Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed).

@FrankBJensen
Copy link
Author

Strange. Can you see what line? I have no idea, what cache it talks about.

At least you have Data OK now :-)

@FrankBJensen
Copy link
Author

You can change core to 1, and see if it moves with the adc_task:

xTaskCreatePinnedToCore(
        _task_adc,                  /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        NULL,                       /* Task handle. */
        0);     <------------ change to 1

@FrankBJensen
Copy link
Author

maybe you need to add this to platformio.ini in order to see, what line causes the panic

monitor_filters = direct, esp32_exception_decoder
build_flags =
    -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG

@safocl
Copy link

safocl commented Jan 21, 2025

maybe you need to add this to platformio.ini in order to see, what line causes the panic

i don't use pio...

@safocl
Copy link

safocl commented Jan 21, 2025

the last debug report:

I (9644) ADC: Data OK
fatfs_Struct( test_file, sizeof( test_file ) ); start
fopen( /fatfs/test.bin, wb ); start
V (9654) vfs_fat: vfs_fat_open: path="/test.bin", flags=601, mode=1b6
I (9654) ADC: Data OK
V (9654) ff_diskio_spiflash: ff_wl_read - pdrv=0, sector=3, count=1
D (9664) wl_flash: read - src_addr= 0x00003000, size= 0x00001000
V (9664) wl_flash: calcAddr - addr= 0x00003000 -> result= 0x00004000, dummy_addr= 0x00000000
V (9674) ff_diskio_spiflash: ff_wl_read - pdrv=0, sector=4, count=1
D (9684) wl_flash: read - src_addr= 0x00004000, size= 0x00001000
V (9684) wl_flash: calcAddr - addr= 0x00004000 -> result= 0x00005000, dummy_addr= 0x00000000
V (9694) ff_diskio_spiflash: ff_wl_read - pdrv=0, sector=5, count=1
D (9704) wl_flash: read - src_addr= 0x00005000, size= 0x00001000
V (9704) wl_flash: calcAddr - addr= 0x00005000 -> result= 0x00006000, dummy_addr= 0x00000000
Guru Meditation Error: Core  0 panic'ed (Cache disabled but cached memory region accessed). 

Core  0 register dump:
PC      : 0x400e0868  PS      : 0x00060034  A0      : 0x8008524f  A1      : 0x3ffb10c0  
A2      : 0x00000000  A3      : 0xff000000  A4      : 0x8008b660  A5      : 0x3ffba600  
A6      : 0x3ffc4c58  A7      : 0x3ff420c0  A8      : 0x80085184  A9      : 0x3ffba6a4  
A10     : 0x3ffc4c5c  A11     : 0x3ffca7ac  A12     : 0x3ffb10c4  A13     : 0x3ffb10c8  
A14     : 0x00000001  A15     : 0x3ffb2d2c  SAR     : 0x00000018  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000  


Backtrace: 0x400e0865:0x3ffb10c0 0x4008524c:0x3ffb1100 0x40083431:0x3ffb1120 0x4008ba1d:0x3ffba640 0x4008e11b:0x3ffba660 0x4008493f:0x3ffba6e0 0x400dd3d2:0x3ffba720 0x400dac1a:0x3ffba750 0x400dc241:0x3ffba770 0x400dab06:0x3ffba7b0 0x400d6af9:0x3ffba7d0 0x400d6a0a:0x3ffba800 0x400d6dc3:0x3ffba820 0x400d7904:0x3ffba840 0x400d7ddd:0x3ffba860 0x400d7f17:0x3ffba890 0x400d9c69:0x3ffba8f0 0x4011f3f5:0x3ffba930 0x40100ce2:0x3ffba950 0x40100d75:0x3ffba980 0x400d632a:0x3ffba9a0 0x400d65e4:0x3ffba9c0 0x4011e64b:0x3ffbaa00 0x40087e35:0x3ffbaa30




ELF file SHA256: 577cd0c89

CPU halted.

@FrankBJensen
Copy link
Author

What do this return (earlier in the code)? Is the filesystem mounted?

esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

if (ret != ESP_OK) {
    ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
} else {
    ESP_LOGI(TAGFS, "FAT filesystem mounted");
}

@safocl
Copy link

safocl commented Jan 21, 2025

What do this return (earlier in the code)? Is the filesystem mounted?

yes -- it is successfully

@safocl
Copy link

safocl commented Jan 21, 2025

last full log

@FrankBJensen
Copy link
Author

That is strange. If I enable this logging below,

esp_log_level_set("vfs_fat", ESP_LOG_VERBOSE);
esp_log_level_set("ff_diskio_spiflash", ESP_LOG_VERBOSE);
esp_log_level_set("wl_flash", ESP_LOG_VERBOSE);

Then I get this log (and note, timeout just after write......)

I (18880) ADC: Data OK
I (18880) ADC: Data OK
I (18890) ADC: Data OK
I (18890) ADC: Data OK
I (18890) ADC: Data OK
I (18900) ADC: Data OK
I (18900) ADC: Data OK
I (18900) ADC: Data OK
I (18910) ADC: Data OK
D (18910) wl_flash: read - src_addr= 0x00003000, size= 0x00001000
File opened
D (18910) wl_flash: erase_range - start_address= 0x00003000, size= 0x00001000
D (18910) wl_flash: erase_sector - sector= 0x00000003
I (18910) ADC: Data OK
I (18910) ADC: Data OK
I (18910) ADC: Data OK
D (18940) wl_flash: write - dest_addr= 0x00003000, size= 0x00001000
E (23910) ADC: Error ESP_ERR_TIMEOUT
E (23910) ADC: TIMEOUT!
E (28910) ADC: Error ESP_ERR_TIMEOUT
E (28910) ADC: TIMEOUT!
E (33910) ADC: Error ESP_ERR_TIMEOUT
E (33910) ADC: TIMEOUT!

@safocl
Copy link

safocl commented Jan 21, 2025

log with code

@FrankBJensen
Copy link
Author

So it fails here
FILE * outFile = fopen( "/fatfs/test.bin", "wb" );
But that should be basic stuff, not relying on any of our code.

There must be something wrong with the mount or something....... You do have 4mb flash, and you dont adress more than that?

Can you compile using my sdkconfig? Just in case, there is a setting somewhere with cache?

@safocl
Copy link

safocl commented Jan 21, 2025

Can you compile using my sdkconfig?

my hardware is not ESP32-S3 -- but it is ESP32

@FrankBJensen
Copy link
Author

OK. But the file system should work on any ESP32, I guess....

Do you have another project, where the filesystem is working?

@FrankBJensen
Copy link
Author

Googling, something like this keeps comming up:

Ensure Proper Memory Allocation: Make sure that the memory regions used by the WL layer are correctly allocated and not in cached regions when the cache is disabled.

Maybe try turning wear leveling OFF ?

@safocl
Copy link

safocl commented Jan 21, 2025

Do you have another project, where the filesystem is working?

no

@FrankBJensen
Copy link
Author

I made a new file-only project from scratch.

I made the partition 512K like you, and that gave me some problems, so I had to change sector and wear level size to 512 bytes, in order for it to mount successfully.

Maybe you should try changing sector and wear level size to 512 bytes??
And see if this compiles and run ??

log

FATFS: FAT filesystem mounted
File opened
/fatfs/test.bin have been written, size: 10 1

code

#include "esp_vfs_fat.h"
#include "esp_log.h"

char test_file[10];
const char *path = "/fatfs";
wl_handle_t s_wl_handle;

static const char *TAGFS = "FATFS";

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    esp_log_level_set("vfs_fat", ESP_LOG_VERBOSE);
    esp_log_level_set("ff_diskio_spiflash", ESP_LOG_VERBOSE);
    esp_log_level_set("wl_flash", ESP_LOG_VERBOSE);

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAGFS, "General failure, possibly due to incorrect partition size or label.");
        } else if (ret == ESP_ERR_NO_MEM) {
            ESP_LOGE(TAGFS, "Out of memory.");
        } else if (ret == ESP_ERR_NOT_FOUND) {
            ESP_LOGE(TAGFS, "Partition not found.");
        } else if (ret == ESP_ERR_INVALID_STATE) {
            ESP_LOGE(TAGFS, "Invalid state, possibly due to incorrect wear leveling configuration.");
        }
        while (1) {
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    FILE* outFile = fopen("/fatfs/test.bin", "wb");
    if (outFile == NULL) {
        ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
        perror("Error"); // This will print a more detailed error
        while (1) {
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    }

    printf("File opened\n");

    uint32_t  written = fwrite((uint8_t*)test_file, sizeof(test_file), 1, outFile);
    fclose(outFile);

    printf("/fatfs/test.bin have been written, size: %u %lu\n", sizeof(test_file), written);

    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

@safocl
Copy link

safocl commented Jan 21, 2025

Maybe you should try changing sector and wear level size to 512 bytes??

yes, i did it.

@safocl
Copy link

safocl commented Jan 21, 2025

I made a new file-only project from scratch.

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:7112
load:0x40078000,len:15644
ho 0 tail 12 room 4
load:0x40080400,len:4
load:0x40080404,len:3860
entry 0x4008063c
[0;32mI (31) boot: ESP-IDF 46acfdce-dirty 2nd stage bootloader[0m
[0;32mI (31) boot: compile time Jan 22 2025 02:09:52[0m
[0;32mI (31) boot: Multicore bootloader[0m
[0;32mI (36) boot: chip revision: v3.1[0m
[0;32mI (40) boot.esp32: SPI Speed      : 40MHz[0m
[0;32mI (45) boot.esp32: SPI Mode       : DIO[0m
[0;32mI (49) boot.esp32: SPI Flash Size : 4MB[0m
[0;32mI (54) boot: Enabling RNG early entropy source...[0m
[0;32mI (59) boot: Partition Table:[0m
[0;32mI (63) boot: ## Label            Usage          Type ST Offset   Length[0m
[0;32mI (70) boot:  0 nvs              WiFi data        01 02 00009000 00006000[0m
[0;32mI (77) boot:  1 phy_init         RF data          01 01 0000f000 00001000[0m
[0;32mI (85) boot:  2 factory          factory app      00 00 00010000 00100000[0m
[0;32mI (92) boot:  3 storage          Unknown data     01 81 00110000 00100000[0m
[0;32mI (100) boot: End of partition table[0m
[0;32mI (104) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=0ad54h ( 44372) map[0m
[0;32mI (128) esp_image: segment 1: paddr=0001ad7c vaddr=3ff80000 size=00018h (    24) load[0m
[0;32mI (128) esp_image: segment 2: paddr=0001ad9c vaddr=3ffb0000 size=02374h (  9076) load[0m
[0;32mI (137) esp_image: segment 3: paddr=0001d118 vaddr=40080000 size=02f00h ( 12032) load[0m
[0;32mI (147) esp_image: segment 4: paddr=00020020 vaddr=400d0020 size=247f0h (149488) map[0m
[0;32mI (202) esp_image: segment 5: paddr=00044818 vaddr=40082f00 size=0ddf4h ( 56820) load[0m
[0;32mI (232) boot: Loaded app from partition at offset 0x10000[0m
[0;32mI (232) boot: Disabling RNG early entropy source...[0m
I (244) cpu_start: Multicore app
I (253) cpu_start: Pro cpu start user code
I (253) cpu_start: cpu freq: 160000000 Hz
I (253) app_init: Application information:
I (253) app_init: Project name:     test_issue
I (257) app_init: App version:      1
I (261) app_init: Compile time:     Jan 22 2025 02:10:19
I (266) app_init: ELF file SHA256:  6bb8bab43...
I (270) app_init: ESP-IDF:          46acfdce-dirty
I (274) efuse_init: Min chip rev:     v3.1
I (278) efuse_init: Max chip rev:     v3.99 
I (282) efuse_init: Chip rev:         v3.1
I (286) heap_init: Initializing. RAM available for dynamic allocation:
I (293) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (298) heap_init: At 3FFB2CF0 len 0002D310 (180 KiB): DRAM
I (303) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (308) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (314) heap_init: At 40090CF4 len 0000F30C (60 KiB): IRAM
I (321) spi_flash: detected chip: generic
I (323) spi_flash: flash io: dio
I (327) main_task: Started on CPU0
I (337) main_task: Calling app_main()
I (3337) FATFS: FAT filesystem mounted
File opened
/fatfs/test.bin have been written, size: 10 1

@FrankBJensen
Copy link
Author

OK, that seems to work. Based on that, I made this modified code. If you use same project, and paste this, then file should work. The fault with timeout still persists. Please try this

Log

I (18396) ADC: Data OK
I (18396) ADC: Data OK
I (18406) ADC: Data OK
I (18406) ADC: Data OK
I (18406) ADC: Data OK
I (18416) ADC: Data OK
I (18416) ADC: Data OK
I (18416) ADC: Data OK
I (18426) ADC: Data OK
I (18426) ADC: Data OK
I (18426) ADC: Data OK
I (18436) ADC: Data OK
I (18436) ADC: Data OK
I (18436) ADC: Data OK
I (18436) ADC: Data OK
File opened
/fatfs/test.bin have been written, size: 10 1
E (23446) ADC: Error ESP_ERR_TIMEOUT
E (23446) ADC: TIMEOUT!
E (28446) ADC: Error ESP_ERR_TIMEOUT
E (28446) ADC: TIMEOUT!

Code

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include <cmath>
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"

#include "esp_vfs_fat.h"

#define ADS_STACK          6000      //  3500
#define ADC_BUFFER_SIZE    20480      // 10240
#define ADC_FRAME_SIZE      512      //  2560

#define ADC_TASK_STOP_BIT       (1 << 0)
#define ADC_TASK_OVERFLOW_BIT   (1 << 1)
#define ADC_TASK_TIMEOUT_BIT    (1 << 2)
#define ADC_TASK_READY_BIT      (1 << 3)

static const char *TAGFS = "FATFS";
static const char *TAG = "ADC";

bool fatfs_Struct(void* data, size_t size);
static void _task_adc(void* parameter);

char test_file[10];

wl_handle_t s_wl_handle;
EventGroupHandle_t adc_event_group = NULL;
adc_cali_handle_t adc_cali_handle;
adc_continuous_handle_t adc_handle{nullptr};

const char *path = "/fatfs";
uint8_t* result = NULL;
uint32_t ret_num = 0;

extern "C" void app_main(void)
{
    vTaskDelay(pdMS_TO_TICKS(3000));

    esp_log_level_set("vfs_fat", ESP_LOG_VERBOSE);
    esp_log_level_set("ff_diskio_spiflash", ESP_LOG_VERBOSE);
    esp_log_level_set("wl_flash", ESP_LOG_VERBOSE);

    // Mount configuration
    esp_vfs_fat_mount_config_t mount_config = {
        .format_if_mount_failed = true,
        .max_files = 5,
        .allocation_unit_size = CONFIG_WL_SECTOR_SIZE
    };

    // Mount the partition named "storage" as FAT with wear leveling
    esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(path, "storage", &mount_config, &s_wl_handle);

    if (ret != ESP_OK) {
        ESP_LOGE(TAGFS, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
        if (ret == ESP_FAIL) {
            ESP_LOGE(TAGFS, "General failure, possibly due to incorrect partition size or label.");
        } else if (ret == ESP_ERR_NO_MEM) {
            ESP_LOGE(TAGFS, "Out of memory.");
        } else if (ret == ESP_ERR_NOT_FOUND) {
            ESP_LOGE(TAGFS, "Partition not found.");
        } else if (ret == ESP_ERR_INVALID_STATE) {
            ESP_LOGE(TAGFS, "Invalid state, possibly due to incorrect wear leveling configuration.");
        }
        while (1) {
            vTaskDelay(pdMS_TO_TICKS(10));
        }
    } else {
        ESP_LOGI(TAGFS, "FAT filesystem mounted");
    }

    ESP_LOGI(TAG, "Start task");

    result = (uint8_t*)heap_caps_malloc(ADC_BUFFER_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); // MALLOC_CAP_SPIRAM);
    std::fill(result, result + ADC_BUFFER_SIZE, 0);

    adc_event_group = xEventGroupCreate();

    xTaskCreatePinnedToCore(
        _task_adc,                  /* Task function. */
        "ads",                      /* String with name of task. */
        ADS_STACK,                  /* Stack size in words. */
        NULL,                       /* Parameter passed as input of the task */
        8,                          /* Priority of the task. */
        NULL,                       /* Task handle. */
        0);


    for(;;) {

        vTaskDelay(pdMS_TO_TICKS(15000));

        FILE* outFile = fopen("/fatfs/test.bin", "wb");
        if (outFile == NULL) {
            ESP_LOGE("FATFS", "Failed to open file for writing: %s", "/fatfs/test.bin");
            perror("Error"); // This will print a more detailed error
            while (1) {
                vTaskDelay(pdMS_TO_TICKS(10));
            }
        }

        printf("File opened\n");

        uint32_t  written = fwrite((uint8_t*)test_file, sizeof(test_file), 1, outFile);
        fclose(outFile);

        printf("/fatfs/test.bin have been written, size: %u %lu\n", sizeof(test_file), written);
    }
}

// ================ Ring buffer overflow callback: ==================================================
static bool IRAM_ATTR adc_pool_overflow_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data)
{
    xEventGroupSetBitsFromISR(adc_event_group, ADC_TASK_OVERFLOW_BIT, NULL);

    return false; // Ssouldn't get to here.
}

void _task_adc(void* parameter)
{
//   adc_cali_handle_t adc_cali_handle;
    adc_cali_curve_fitting_config_t cali_config = { };
    cali_config.unit_id = ADC_UNIT_1;
    cali_config.atten = ADC_ATTEN_DB_12;
    cali_config.bitwidth = ADC_BITWIDTH_DEFAULT;
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle));

// Configure AD for multiplex
    static adc_channel_t channel[4] = { ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_8 };

    adc_continuous_handle_cfg_t adc_config = {};
    adc_config.max_store_buf_size = ADC_BUFFER_SIZE;
    adc_config.conv_frame_size = ADC_FRAME_SIZE;
    adc_continuous_new_handle(&adc_config, &adc_handle);

ESP_LOGE(TAG, "Size: %u", sizeof(channel)/sizeof(adc_channel_t));

    adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = { 0 };
    for (int i = 0; i < sizeof(channel)/sizeof(adc_channel_t); i++) {
        adc_pattern[i].atten = ADC_ATTEN_DB_12;                 // analog scale
        adc_pattern[i].channel = channel[i];                    // Kanal
        adc_pattern[i].unit = ADC_UNIT_1;                       // ADC1
        adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;   // Bit 12

ESP_LOGE(TAG, "Size: %u, num %i", sizeof(channel)/sizeof(adc_channel_t), i);

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

    adc_continuous_config_t dig_cfg = {};
    dig_cfg.sample_freq_hz = 40000;            // ADC_TEST_FREQ_HZ,  40000
    dig_cfg.conv_mode = ADC_CONV_SINGLE_UNIT_1;     // Kun ADC1
    dig_cfg.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;  // Format 2, hvad det så end er......
    dig_cfg.adc_pattern = adc_pattern;
    dig_cfg.pattern_num = sizeof(channel)/sizeof(adc_channel_t);
    adc_continuous_config(adc_handle, &dig_cfg);

    adc_continuous_evt_cbs_t adc_callbacks =
    {
        .on_pool_ovf = adc_pool_overflow_cb,
    };
    ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(adc_handle, &adc_callbacks, NULL) );

    ESP_LOGI(TAG, "About to start ADC");
    adc_continuous_start(adc_handle);

    for(;;) {

        EventBits_t bits = xEventGroupGetBits(adc_event_group);
        if (bits & ADC_TASK_OVERFLOW_BIT) {
            ESP_LOGE(TAG, "ADC buffer overflow detected!");
            xEventGroupClearBits(adc_event_group, ADC_TASK_OVERFLOW_BIT);
        }
        if (bits & ADC_TASK_TIMEOUT_BIT) { // TIMEOUT
            ESP_LOGE(TAG, "TIMEOUT!");
        }

        while (1) {

            esp_err_t ret_adc = adc_continuous_read(adc_handle, result, ADC_FRAME_SIZE, &ret_num, 5000);

            if (ret_adc == ESP_OK) {
                ESP_LOGI(TAG, "Data OK");
            } else if (ret_adc == ESP_ERR_TIMEOUT) {

                ESP_LOGE(TAG, "Error ESP_ERR_TIMEOUT");
                xEventGroupSetBits(adc_event_group, ADC_TASK_TIMEOUT_BIT);

/* This code will resume ADC if enabled
                vTaskDelay(1);
                adc_continuous_stop(adc_handle);
                vTaskDelay(1);
                adc_continuous_start(adc_handle);
                vTaskDelay(1);
*/
                break; // stop med at hente data fra ADC
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Opened Issue is new Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

4 participants