web-dev-qa-db-fra.com

ESP8266 / Arduino: Pourquoi est-il nécessaire d'ajouter la macro ICACHE_RAM_ATTR aux ISR et aux fonctions appelées à partir de là?

J'ai lu que je besoin d'ajouter la macro iCache_ram_attr aux routines de service Interrupve (ISRS)et à chaque fonction appelée à partir de là Dans mon code Arduino pour ESP8266 pour empêcher les collisions aléatoires . J'ai aussi trouvé ne explication de ce que la macro itache_ram_attr , bien que je ne sois pas sûr si l'explication, qui est pour l'espressif ESP8266 SDK, est également vrai pour Arduino sur ESP8266. Et je n'ai pas compris pourquoi j'ai besoin d'ajouter la macro aux ISR.

Première question: Pourquoi dois-je ajouter la macro ICACHE_RAM_ATTR à ISRS et toutes les fonctions appelées à partir de là?

La question suivante est, que se passe-t-il si je force à inliquer une fonction appelée d'une ISR:

inline void doStuff() __attribute__((__always_inline__)) { // <-- necessary to add ICACHE_RAM_ATTR here?
    // no more function calls here
}

void ICACHE_RAM_ATTR handleInterrupt() {
    doStuff();
}

Deuxième question: Dois-je ajouter la macro ICACHE_RAM_ATTR à des fonctions forcées d'être inlinée?

8
x-ray

Les ICACHE_RAM_ATTR et ICACHE_FLASH_ATTR sont des attributs de liaison. Une fois que vous compilez votre croquis, vous pouvez dire si la fonction doit être stockée dans le RAM ou Flash (normalement, vous ne définissez rien: pas de cache).

L'ESP8266 est multitâche et l'ESP32 a 2 cœurs. Vous pouvez donc exécuter votre code comme multithreading - car il utilise les RTO.

Et maintenant, le problème: tout le flash est utilisé pour le programme et le stockage. La lecture et l'écriture au flash ne peuvent être effectuées que sur 1 fil. Si vous essayez d'accéder simultanément au flash sur 2 threads différents, votre ESP va probablement planter.

En effet, vous pouvez mettre votre fonction dans RAM au lieu du flash. Donc, même si vous écrivez quelque chose dans l'EEPROM ou Flash, cette fonction peut être appelée sans accéder au flash.

Avec ICACHE_RAM_ATTR Vous mettez la fonction sur la RAM.

Avec ICACHE_FLASH_ATTR Vous mettez la fonction sur le flash (pour enregistrer la RAM).

Les fonctions d'interruption doivent utiliser ICACHE_RAM_ATTR. La fonction appelée souvent, ne doit pas utiliser aucun attribut de cache.

Important: n'accumulez jamais votre flash à l'intérieur d'une interruption! L'interruption peut se produire lors d'un accès éclair. Si vous essayez d'accéder au flash en même temps, vous obtiendrez un crash (et cela se produit parfois après 1-2 heures après l'utilisation de votre appareil).

Comme vous n'avez que 32 ko d'IRAM (RAM INSTRUCTION), vous devriez essayer de ne pas interrompre les fonctions de la RAM, pas toutes vos fonctions, même si elle est possible de le faire.

Deuxième question: Non, absolument non! Inline est un autre drapeau du compilateur, de sorte que le compilateur essaie de placer toute votre fonction à l'intérieur de la fonction de l'appelant => Convertir un appel de fonction sur C++ Code à l'intérieur de votre principal. Cela ne signifie pas que le compilateur le fera, essayez simplement. Vous ne pouvez pas demander de mettre la fonction à l'intérieur de la RAM, si la fonction n'existe plus une fois que vous avez compilé votre croquis.

5
Adriano

Merci beaucoup pour l'Itache_ram_attr, je l'ai utilisé sur le haut de mon code ... et bien sûr, il y a des broches qui ne fonctionnaient pas comme une interruption, par exemple dans mon cas, j'utilisais Board Wemos D1 Mini Pro et le PIN D0 (GPIO 16) N'a pas fonctionné, jusqu'à ce que je ne chanse au prochain code PIN (GPIO 14), il fonctionne parfaitement ....

L'ICACHE_RAM_ATTR travaille avec de nouvelles bibliothèques, la bibliothèque de 2,5 obsolète fonctionne également sans ce morceau de code.

Merci beaucoup!

const uint8_t interruptPin = 14;
volatile byte interruptCounter = 0;
int numberOfInterrupts = 0;
void ICACHE_RAM_ATTR handleInterrupt();

void setup() {

  Serial.begin(9600);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, CHANGE);

}

void handleInterrupt() {
  interruptCounter++;
}

void loop() {

  if(interruptCounter>0){

      interruptCounter--;
      numberOfInterrupts++;

      Serial.print("An interrupt has occurred. Total: ");
      Serial.println(numberOfInterrupts);
  }

}
1
Alfredo Ramirez