• # volatile et interruptions

    Posté par . En réponse au message Volatile, struct et interruptions.. Évalué à 3.

    L'utilisation du mot clé "volatile" est indispensable à maîtriser lorsqu'on écrit du code embarqué: elle permet à l'utilisateur d'éviter que le compilateur, lorsqu'utilisé avec les optimisations qui vont bien n'en fasse trop. L'exemple le plus courant est le polling sur une pin d'entrée:
    si pin_b0 est le nom de la "variable" qui permet d'accéder à la pin 0 du port B du uC, alors, sans le mot clé "volatile", le code suivant qui permet de détecter le passage à 1 de cette entrée a pour conséquence de faire "disparaitre" la boucle while et de se faire rick-roller et c'est surtout pas ça ce qu'on veut:

    // Code "RACHE certified" before while loop
    isRisingEdgeDetected = false
    while(!pin_b0)
    {
     isRisingEdgeDetected = true
    }
    // Code "RACHE certified" after while loop
    if(!isRisingEdgeDetected)
    {
     // Listen to Rick Roll/Never Gonna Give You Up!
    }

    Jeter un coup d'oeil à sfr_defs.h, io.h (etc.) pour la définition des accès mémoires des pins du uC de type AVR. Pour définir une variable volatile de type "la structure que tu veux définir":

    typedef struct S_MASTRUCTURE t_mastructure;
    #ifndef _S_MASTRUCTURE
    struct S_MASTRUCTURE
    {
     u8* pBuffer;
     u16 aWord;
     u8 aByte;
    };
    #endif
    volatile t_mastructure maVariableDeTypeMastructure;

    Pour l'embarqué tel que pour un AVR, lorsqu'on veut modifier une variable par le code principal et par une interruption, il faut désactiver les interruptions dans le code principal lorsqu'on y accède.
    exemple, pour modifier aWord par le code principal ET par l'interruption pour un uC de type AVR:

    ISR(USARTC0_RXC_vect)
    {
     // Modify a "shared value"
     maVariableDeTypeMastructure.aWord++;
    }
    int main (void)
    {
     // Code "RACHE certified"
     ...
     for(;;)
     {
     // Deactivate interruptions
     __asm__ __volatile__ ("cli" ::)
     // Modify a shared variable
     maVariableDeTypeMastructure.aWord+=2;
     // Reactivate interruptions
     __asm__ __volatile__ ("sei" ::)
     // Fantastic code
     ...
     }
     return 0;
    }

    Sans désactiver les interruptions, sur un micro 8bit, on risque l'interruption en plein cours de modification de aWord dans le programme principal et là, c'est le drame!
    Et même si la variable est de type 8bit, parce qu'entre le moment où la variable va être chargée dans un registre et le moment où le registre va être modifié et le moment où il va être réécrit dans la mémoire, il y a des malchances qu'une interruption claque et qu'à la fin, la variable se retrouve avec une valeur totalement indéterminée. Je te laisse imaginer le cas où cette variable est de type pointeur, à côté des dégats que celà peut engendrer, tu préfèrerais être rickrollé!

    Mutex, semaphore et autres mécanismes du même type sont des implémentations pour langage "haut-niveau" (os, multithread, etc.) pour éviter ces problèmes, mais la base est ci-dessus!

    a2g