ESP32 : analogContinuous et Accès NVS = reset

Bonjour,
je programme pour le plaisir et là je bloque, (c'est mon premier message sur le forum / vous m'excusez si c'est pas dans la bonne catégorie)

Je lance une lecture ADC en continu sur des gpio, cette fonction seul fonctionne relativement bien (a un détail prés du bug ESP32 qui saute 2 valeurs sur 11, avec un ESP32S3 le problème est résolu).
Dans le programme complet, j'ai quelques fois besoin de stocker des données en mémoire flash (Non Volatile Storage), et c'est là que le problème apparait. quelques fois ça passe et très souvent, ça fait planter l'ESP avec un redémarrage affichant

rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)

dans la doc Espressif et sur d'autres forums, il est question d'activer le paramètre CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE pour gérer les lectures en continu en mode interruption et ne pas interférer avec l'écriture en NVS. Seulement je ne vois absolument pas où je peux mettre ce paramètre, (ni si ça peut solutionner mon problème)

quand il y a un backtrace, le décodage donne ça:

Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed). 

Core  1 register dump:
PC      : 0x400e4c60  PS      : 0x00060035  A0      : 0x800843a8  A1      : 0x3ffbfa1c  
A2      : 0x00000000  A3      : 0x00000200  A4      : 0x80082156  A5      : 0x3ffb1f40  
A6      : 0x3ffb8c3c  A7      : 0x3ffb8c38  A8      : 0x800842e8  A9      : 0x00000004  
A10     : 0x3ffb8c3c  A11     : 0x3ffb8dd0  A12     : 0x3ffbfa2c  A13     : 0x3ffbfa30  
A14     : 0x00000001  A15     : 0x00000002  SAR     : 0x00000000  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x40086411  LEND    : 0x40086415  LCOUNT  : 0x00000000  

Backtrace: 0x400e4c5d:0x3ffbfa1c |<-CORRUPTED

PC: 0x400e4c60: adc_hal_get_reading_result at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/hal\adc_hal.c:232
EXCVADDR: 0x00000000

Decoding stack results
0x400e4c5d: adc_hal_digi_dma_link at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/hal\adc_hal.c:229

Je poste ici un bout de code (réduit) pour reproduire le problème, espérant que quelqu'un me propose une solution, merci d'avance

#include <Preferences.h>

#define ADC_PIN1 32  // GPIO first ADC input
#define ADC_PIN2 33  // GPIO second ADC input

uint8_t adc_pins[] = { ADC_PIN1, ADC_PIN2 };                  //some of ADC1 pins for ESP32
uint8_t adc_pins_count = sizeof(adc_pins) / sizeof(uint8_t);  // Calculate how many pins are declared in the array
uint32_t previousStorageTime = 0;
uint32_t previousMessageTime = 0;
volatile uint32_t sampleCount = 0;
volatile uint32_t totalADC1 = 0;
volatile uint32_t totalADC2 = 0;
Preferences myPrefs;


void ARDUINO_ISR_ATTR adcComplete() {      // ISR Function that will be triggered when ADC conversion is done
  adc_continuous_data_t *result = NULL;    // Result structure for ADC Continuous reading, memory allocated by driver
  if (analogContinuousRead(&result, 0)) {  // get data from
    for (int i = 0; i < adc_pins_count; i++) {
      if (result[i].pin == ADC_PIN1) {
        totalADC1 += result[i].avg_read_raw;
      } else if (result[i].pin == ADC_PIN2) {
        totalADC2 += result[i].avg_read_raw;
      }
      sampleCount++;
    }
  } else {
    ets_printf("Error occurred during reading data.\n");
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start setup");
  myPrefs.begin("myNVSArea", false);
  if (myPrefs.isKey("Avg")) Serial.printf("Previous avg = %ld\n", myPrefs.getLong("Avg"));
  myPrefs.putLong("Avg", 0);
  analogContinuousSetWidth(12);
  analogContinuousSetAtten(ADC_11db);
  analogContinuous(adc_pins, adc_pins_count, 3, 72000, &adcComplete); // 72000 reads per seconde on 2 pins with average on 3 reads 
  analogContinuousStart();
  Serial.println("End of setup");
}

void loop() {
  if (millis() - previousMessageTime > 3000) {
    previousMessageTime = millis();
    Serial.println("Alive, ADC continuous Read ... working ");
  }
  if (millis() - previousStorageTime > 20000) {  // every 20s
    previousStorageTime = millis();
    delay(1);
    long avg = (totalADC1 + totalADC2) / (2 * sampleCount);
    Serial.printf("%ld samples / Store Avg=%ld in myNVSArea\n", sampleCount, avg);
    Serial.flush();
    // next instruction produce crash sometime, with reset : rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    myPrefs.putLong("Avg", avg);
    Serial.println("Stored");
    Serial.flush();
    sampleCount = 0;
  }
}

Bonjour

ça ressemble à un paramètre activable dans l'IDF d'Espressif, pas accessible avec le core ESP32 pour IDE Arduinbo et ses diverses bibliothèques précompilées.

1)par curiosité le bug disparait-il si tu suspends l'acquisition analogique continue le temps d'écrire en mémoire volatile ?

analogContinuousStop();
.....
analogContinousStart()
  1. as-tu essayé de passer moins de temps dans la routine d'interruption en déportant le traitement qui est fait actuellement ?
    Intuitivement j'ai l'impression que tu y passes un temps trop long pour que l'écriture en mémoire flash (partition NVS) se passe sans problème

Plus globalement : a quel besoin répond l'écriture de données en NVS (Préférences) dans ton cas ?
C'est conseillé pour des données changeant rarement, la NVS étant gérée, il me semble, avec pas ou très peu de wear-levelling , l'usure de la Flash est à prendre en compte
Les systèmes de fichier LittleFS et SPIFFS intègrent un wear-levelling plus conséquent

Bonjour,

merci, ces informations m'ont remis sur la bonne voie

Le premier point Stop() and Start(), c'est efficace dans cet extrait de code où tout se passe dans le loop(),

analogContinuousStop();
myPrefs.putLong(....);
analogContinousStart();

En fait ce n'est qu'un extrait que je pensais représentatif, mais en fait l'appel qui déclenche l'enregistrement en NVS est déclenché par une action sur une page web (ça réponds au 'plus globalement' -> je ne fais pas de harcèlement d'écriture en zone NVS, ce ne sont que des paramètres qui sont enregistrés (rarement)

En ajustant mon code (beaucoup plus grand), j'ai obtenu un autre effet de bord :
Le problème d'appeler le ...Stop() a partir d'une requête web c'est que c'est un callback en mode ISR avec AsyncWebServer (et on ne peux pas faire le ...Stop() dans une ISR ). J'ai donc simplement activé un flag (que j'ai appelé requestWriteNVSInTaskLoop) et dans le loop de la même tache qui a servi a faire le ...Start() initial, j'intercepte le flag et fais les actions

if (requestWriteNVSInTaskLoop) {
  analogContinuousStop();
  myPrefs.putLong("Avg", avg); 
  requestWriteNVSInTaskLoop = false;
  analogContinousStart();
}

Et la ça marche [même si le traitement dans void ARDUINO_ISR_ATTR adcComplete() est beaucoup plus conséquent]

Encore merci pour cette aide

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.