I have something, that behaves unexpected. I am running ADC in continous mode in one task, and use the file system totally independent in another task, but somehow just opening a file, even without writing anything, the ADC goes into timeout, when I call fclose.
If I make the ADC buffer really big, I can make this fault occur more random, sometimes days inbetween, but setting the buffer to what is enough, the fault occur everytime I access the filesystem - once an hour.
I have boiled the code down to a minimum, and the fault persists. I am using my own hardware with ESP32-S3-N16R8V, and I have repliceated the error on a original Espressif esp32-s3-devkitc-1.
I use Platformio, CPP and latest ESPIDF 5.3.1. The fault was also in 5.3.0.
I stop and start ADC in order to get the ADC back on track, but would like to get to the root of this. I suspect, that the DMA for the ADC might stop on fclose. If the DMA does not stop, I would expect an overflow, and this do not happen. A timeout indicates to me, that the dataflow has stopped.
Is there anything wrong with my code, or is it an actual bug. Input apreciated

The log looks like this:
Code: Select all
I (18775) ADC: Data OK
I (18775) ADC: Data OK
I (18775) ADC: Data OK
I (18785) ADC: Data OK
I (18785) ADC: Data OK
I (18785) ADC: Data OK
I (18795) ADC: Data OK
I (18795) ADC: Data OK
I (18795) ADC: Data OK
D (18805) wl_flash: read - src_addr= 0x00003000, size= 0x00001000
File opened
D (18805) wl_flash: erase_range - start_address= 0x00003000, size= 0x00001000
D (18805) wl_flash: erase_sector - sector= 0x00000003
I (18805) ADC: Data OK
I (18805) ADC: Data OK
I (18805) ADC: Data OK
D (18855) wl_flash: write - dest_addr= 0x00003000, size= 0x00001000
E (23805) ADC: Error ESP_ERR_TIMEOUT
E (23805) ADC: TIMEOUT!
E (28805) ADC: Error ESP_ERR_TIMEOUT
Code: Select all
#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
}
}
}
}