Il est clairement documenté que lorsque des données globales sont partagées avec un ISR et le programme principal, les données doivent être déclarées volatile
afin de garantir la visibilité de la mémoire (et cela ne suffit que pour les données à 1 octet; tout ce qui est plus grand nécessite des dispositions spéciales pour garantir également l'atomicité) . Ici, nous avons de bonnes règles:
- Les variables utilisées uniquement en dehors d'un ISR ne doivent pas être volatiles.
- Les variables utilisées uniquement à l'intérieur d'un ISR ne doivent pas être volatiles.
- Les variables utilisées à l'intérieur et à l'extérieur d'un ISR doivent être volatiles.
Mais est-il volatile
nécessaire lorsque la variable est accessible à partir de> 1 ISR, mais n'est pas partagée en dehors des ISR? Par exemple, j'ai une fonction qui maintient l'état interne à l'aide d'une static
variable:
void func() {
static volatile long counter; // volatile or not?
// Do stuff with counter etc.
}
Cette fonction est appelée de deux manières: à partir de l'interruption de broche et de la bibliothèque TimerOne :
attachInterrupt(0, func, CHANGE);
Timer1.attachInterrupt(func);
Il n'y a aucun problème d'atomicité, car lorsqu'un ISR est entré, les interruptions sont automatiquement désactivées , mais il volatile
s'agit davantage d'une question de compilation: ce qui est mis en cache et ce qui ne l'est pas.
Mieux vaut prévenir que guérir, bien sûr ...
volatile
, car elle n'est pas modifiée par autre chose que le code généré; le compilateur peut "supposer" que l'ISR s'exécute linéairement, et il le fait, tant que les interruptions ne s'emboîtent pas. Ça a du sens. Merci!