La volatilité est-elle nécessaire lorsque la variable est accessible à partir de> 1 ISR, mais n'est pas partagée en dehors des ISR?


9

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 volatileafin 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 volatilené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 staticvariable:

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 :

  1. attachInterrupt(0, func, CHANGE);
  2. 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 volatiles'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 ...

Réponses:


9

volatile informe uniquement le générateur de code du compilateur que la variable peut être modifiée par autre chose que le code généré, afin de ne pas supposer qu'une copie de celle-ci reste exacte.

Le code ISR doit être écrit / généré sous l'hypothèse qu'il n'a pas de contexte à l'entrée et préserve le contexte du CPU autour de son propre fonctionnement (ISR). Ainsi, comme pour l'indivisibilité des opérations non atomiques, la volatilité dépend, dans ce cas * , du fait que les interruptions sont autorisées ou non à s'imbriquer. Si la non imbrication est garantie, la variable partagée ne peut pas être modifiée par un autre que cet ISR lors de sa propre exécution. Si votre ISR peut un jour être utilisé dans un environnement où les interruptions sont autorisées à s'imbriquer, alors cette contrainte ne tiendra plus.

* dans ce cas :
je suppose une variable gérée par logiciel ici. Si nous parlons d'une variable qui peut être mise à jour par un événement matériel, un registre de timer par exemple, tous les paris sont désactivés: la variable est volatile quoi qu'il arrive.


Donc, tant que je ne change pas le comportement par défaut d'Arduino "les interruptions ne s'emboîtent pas", alors la variable n'a pas besoin d'être 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!
Joonas Pulakka
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.