Masquage d'interruptions dans les systèmes embarqués : Quoi, Pourquoi, Comment
Qu'est-ce qu'un masque d'interruption ?
Un masque d'interruption est un mécanisme matériel ou logiciel qui désactive temporairement (masque) une ou plusieurs sources d'interruption, les empêchant d'interrompre le CPU. Il agit comme un gardien : quand le bit de masque d'une interruption est à 1, le CPU ignore cette demande ; quand il est à 0, l'interruption est activée et peut déclencher une routine de service d'interruption (ISR).
Pourquoi le masquage est-il nécessaire ?
Le masquage d'interruptions est essentiel pour plusieurs scénarios critiques :
- Protection sections critiques : Lors d'exécution de code qui ne doit pas être interrompu (ex. mise à jour structures données partagées, modification registres matériel, commutation contexte), le masquage assure exécution atomique.
- Gestion prévisible interruptions : En masquant sélectivement interruptions de priorité inférieure pendant exécution ISR haute priorité, on impose un schéma de priorité déterministe.
- Gestion ressources : Évite conditions de concurrence sur périphériques ou tampons mémoire partagés accédés par code principal et ISR.
- Gestion énergie : Masquer interruptions de réveil inutiles en modes basse consommation évite réveils intempestifs.
- Débogage et tests : Permet aux développeurs d'isoler chemins de code en désactivant temporairement sources d'interruption spécifiques.
Comment fonctionnent les masques d'interruption ?
Typiquement, chaque source d'interruption a un bit correspondant dans un Registre Masque Interruption (IMR) ou Registre Activation Interruption (IER) :
- Bit masque = 1 (positionné) → Interruption désactivée (masquée).
- Bit masque = 0 (effacé) → Interruption activée.
Le CPU vérifie ce registre avant d'acquitter une interruption. Dans de nombreuses architectures (ARM Cortex-M, AVR, x86), il y a à la fois instructions globales d'activation/désactivation (ex. CPSID I/CPSIE I, cli/sti) et registres de masque par interruption pour contrôle fin.
Quelles interruptions peuvent être masquées ?
La granularité varie selon l'architecture :
- Masquage global : Désactive toutes les interruptions masquables d'un coup (interruptions non masquables, NMI, ne peuvent pas être masquées).
- Masquage par périphérique : Chaque périphérique (UART, timer, ADC, GPIO, etc.) a son bit d'activation dans un contrôleur d'interruption central (ex. NVIC sur ARM, PIC/APIC sur x86).
- Masquage par priorité : Certains contrôleurs (comme NVIC ARM) permettent masquage par niveau de priorité (ex. registre
BASEPRI), activant toutes interruptions au-dessus d'une certaine priorité tout en désactivant les plus basses.
Bonnes pratiques
- Garder régions masquées aussi courtes que possible pour minimiser latence interruption.
- Préférer masquage par interruption au masquage global quand seules sources spécifiques doivent être bloquées.
- Toujours réactiver (démasquer) interruptions dans le même chemin d'exécution, y compris gestionnaires erreur/exception.
- Utiliser lecture-modification-écriture atomique ou registres dédiés set/clear pour éviter conditions de concurrence lors modification bits masque.
Un masquage d'interruption correct est une pierre angulaire du firmware embarqué temps réel fiable.
