Mascheraggio degli Interrupt nei Sistemi Embedded: Cosa, Perché e Come
Cos'è una Maschera di Interrupt?
Una maschera di interrupt è un meccanismo hardware o software che disabilita temporaneamente (maschera) una o più fonti di interrupt, impedendo loro di interrompere la CPU. Agisce come un gatekeeper: quando il bit di maschera di un interrupt è impostato, la CPU ignora quella richiesta di interrupt; quando cancellato, l'interrupt è abilitato e può attivare una routine di servizio interrupt (ISR).
Perché è Necessario il Mascheraggio?
Il mascheraggio degli interrupt è essenziale per diversi scenari critici:
- Protezione di Sezioni Critiche: Quando si esegue codice che non deve essere interrotto (es. aggiornamento di strutture dati condivise, modifica di registri hardware, switch di contesto), il mascheraggio garantisce esecuzione atomica.
- Gestione Predittibile degli Interrupt: Mascherando selettivamente gli interrupt a bassa priorità durante l'esecuzione di ISR ad alta priorità, applichi uno schema di priorità deterministico.
- Gestione delle Risorse: Previene condizioni di competizione su periferiche o buffer di memoria condivisi accessibili sia dal codice principale che dalle ISR.
- Gestione Energetica: Mascherare gli interrupt di risveglio non necessari durante modalità a basso consumo evita risvegli spurii.
- Debug e Test: Consente agli sviluppatori di isolare percorsi di codice disabilitando temporaneamente fonti di interrupt specifiche.
Come Funzionano le Maschere di Interrupt?
Tipicamente, ogni fonte di interrupt ha un bit corrispondente in un Interrupt Mask Register (IMR) o Interrupt Enable Register (IER):
- Bit di maschera = 1 (impostato) → Interrupt è disabilitato (mascherato).
- Bit di maschera = 0 (cancellato) → Interrupt è abilitato.
La CPU controlla questo registro prima di riconoscere un interrupt. In molte architetture (ARM Cortex-M, AVR, x86), esistono sia istruzioni globali di abilitazione/disabilitazione degli interrupt (es. CPSID I/CPSIE I, cli/sti) sia registri di maschera per-interrupt per un controllo fine.
Quali Interrupt Possono Essere Mascherati?
La granularità del mascheraggio varia in base all'architettura:
- Mascheraggio globale: Disabilita tutti gli interrupt mascherabili in una volta (gli interrupt non mascherabili, NMI, non possono essere mascherati).
- Mascheraggio a livello periferico: Ogni periferica (UART, timer, ADC, GPIO, ecc.) ha il proprio bit di abilitazione in un controllore di interrupt centrale (es. NVIC su ARM, PIC/APIC su x86).
- Mascheraggio basato sulla priorità: Alcuni controllori (come l'NVIC di ARM) consentono il mascheraggio per livello di priorità (es. registro
BASEPRI), abilitando tutti gli interrupt sopra una certa priorità mentre disabilita quelli inferiori.
Migliori Pratiche
- Mantieni le regioni mascherate il più brevi possibile per minimizzare la latenza degli interrupt.
- Preferisci il mascheraggio per-interrupt rispetto alla disabilitazione globale quando solo fonti specifiche necessitano di blocco.
- Riabilita sempre (smaschera) gli interrupt nello stesso percorso di esecuzione, inclusi i gestori di errore/eccezione.
- Usa operazioni atomiche read-modify-write o registri dedicati set/clear per evitare condizioni di competizione durante la modifica dei bit di maschera.
Un corretto mascheraggio degli interrupt è una pietra angolare del design affidabile di firmware embedded in tempo reale.