L' Interrupt
Un programma è essenzialmente una sequenza ordinata di
istruzioni che svolge i compiti previsti dal programmatore.
E' possibile che, in una applicazione reale, siano
disponibili eventi che richiedono una attenzione immediata. Ad esempio, se
stiamo leggendo un libro, siamo impegnati nello scorrere le parole e le
frasi e a comprenderne il significato (qeusto è il flusso principale del
"programma").
Ma ecco che squilla il telefono (interrupt): occorre sospendere la lettura e
rispondere alla chiamata. Dopo di che si potrà nuovamente riprendere la
lettura dal punto in cui è stata interrotta.
Analogamente, il flusso del programma può avere la
necessità di essere interrotto per passare il controllo ad altre sezioni
del programma che hanno lo scopo di gestire la causa dell' interruzione.
|
Nei PIC, come in altri processori embedded, la procedura di
interrupt consiste essenzialmente nella sostituzione del valore contenuto
nel Program Counter con un indirizzo fisso, predeterminato dalla struttura
del processore. Questo fa si che l' istruzione successiva all' evento di
interrupt sia la prima che si trova a questo indirizzo.
Ovvero, dalla posizione attuale, sospendendo il flusso di
istruzioni principale, si passa immediatamente ad un indirizzo determinato,
dove il programmatore ha posizionato le routines di gestione dell' interrupt.
Al termine dell' esecuzione di queste routines, una speciale
istruzione di ritorno-da-interrupt (RETFIE) ripristina il Program Counter
nella posizione da cui si era distaccato, riprendendo il flusso di
istruzioni principale.
|
Il salto all' indirizzo di inizio delle routines di
interrupt può essere causato da numerose fonti di evento interne (timer,
UART, MSSP, ecc) oppure esterne (cambio di livello sui pin, tensione, ecc.).
I PIC18F dispongono
di una numerosa serie di possibili fonti di interrupt, dato che integrano un
altrettanto elevato numero di periferiche, tipicamente superiore
ai mid-range, ma sopratutto, di una struttura di gestione dell' interrupt a
priorità.
Ne deriva che un
buon numero di registri sono disponibili per la gestione degli eventi.
Ogni sorgente di interrupt dispone di TRE di bit di
controllo :
bit |
funzione |
IE - Interrupt Enable |
bit di abilitazione. la cui sigla termina
tipicamente con IE; settando questo bit si abilita la sorgente a generare interruzioni |
IF - Interrupt Flag |
bit di flag, la cui sigla termina con IF.
Quando questo bit va a livello 1 livello indica l' avvenuto
evento. |
IP - Interrupt Priority |
bit di priorità, la cui sigla termina con Ip.
Questo bit stabilisce il livello di priorità ed è attivo in
dipendenza dal valore assegnato a IPEN <RCON:7> (questo bit 1 abilita la
priorità a due livelli). |
Per consentire una gestione dell' evento, il flag IF resta a
livello 1 fino a che non viene azzerato dall' utente. Questo comporta la
necessità assoluta di resettare il flag una volta servito onde evitare che,
non appena usciti dalla routine di interrupt, il flag a 1 la riattivi
immediatamente, con i risultati immaginabili.
ATTENZIONE:
La gestione di un interrupt deve SEMPRE prevedere la
cancellazione del flag della periferica che ha generato la
chiamata. In caso contrario non sarà possibile uscire da un loop
sul vettore dell' interrupt. |
L' abilitazione dei bit IE non è sufficiente ad attivare l' interrupt
: un ulteriore bit GIE (Global Interrupt Enable) funge da "interruttore
generale" e sarà necessario settare anche questo perchè l' evento di
interrupt abbia effetto.
INTERRUPT Periferici e non periferici
I PIC distinguono
poi due categorie di sorgenti di interrupt :
La differenza
consiste in questo : le sorgenti di interrupt "non periferici"
hanno i bit IE e IF nei registri INTCON, mentre le sorgenti
"periferiche" hanno i bit di controllo nei registri PIR/PIE.
A seguito di questa divisione, i bit di abilitazione globale diventano due :
il già citato GIE e un PEIE (PEripheral Interrupt Enable) .
Per attivare gli interrupt periferici, oltre a GIE, sarà necessario
attivare anche PEIE; ovvero PEIE funge da interruttore generale per gli
interrupt periferici e GIE funge da interruttore generale per tutte le
sorgenti di interrupt, periferiche e non. Quindi, per abilitare un interrupt
periferico, sarà necessari settare sia il relativo bit IE sia il bit GIE,
mentre per attivare un interrupt non periferico si dovrà settare sia IE che
GIE e PEIE.
Questo, a fronte di una maggiore complessità di gestione, consente una
maggiore flessibilità nell' attivazione/disattivazione degli interrupt.
Lo schema complesso qui sopra utilizza delle funzioni
logiche AND e OR per spiegare il funzionamento della catena di bit preposti
al controllo di un interrupt.
Prendiamo ad esempio l' interrupt generato dal fine conteggio di TIMER0.
Se il timer termina il conteggio, passando da FFh a 00h, il
bit TMR0IF va a livello 1. Questo bit è in AND con i bit di abilitazione
TMR0IE e il bit di priorità TMR0IP: se entrambi sono a livello 1, anche l'
uscita dell' AND va a livello 1.
Questa uscita è in OR con altre catene similari: dunque
basta che uno solo degli ingressi dell' OR vada a livello 1 perchè l'
uscita del gate sia pure a livello 1.
Questa uscita viene riportata ad un ulteriore AND che la
somma al bit di abilitazione GIE/GIEH: se questo è a livello 1, l' uscita
dell' AND, a livello 1, attiva la chiamata di interrupt.
Nello stesso tempo, se la funzione è abilitata a questo, un gate OR comanda
il wake up dalla condizione di sleep.
Il vettore che viene sostituito al Program Counter, a
seguito della richiesta di interrupt, è posto a 0008h.
Nella modalità ad un solo livello di priorità, il bit
TMR0IP non ha effetto. Quindi, se esemplifichiamo quanto detto con una
catena di interruttori, otteniamo:
Se è selezionata la modalità con due livelli di priorità,
in serie alla catena si inserisce anche il bit TMR0IP.
Un caso particolare è costituito dall' INT0, che non ha bit
di selezione del livello di priorità e quindi è attivo sempre alla
priorità più alta.
Così dovrebbe essere facile seguire le altre fonti di
interrupt attraverso la catena degli "interruttori" logici che le
abilitano, osservando che lo switch di priorità IP (quando abilitato),
invia la chiamata di interrupt ad un vettore diverso, posto a 0018h.
|
Da notare che questo vettore è abiltato dal bit GIEH(GIE), ma
anche dal bit GIEL(PEIE).
GIE abilta il complesso degli interrupt e PEIE solo quelli
periferici, in modalità senza priorità.
Nel modo con priorità GIE, che viene chiamato GIEH, di nuovo
abilita in generale gli interrupt, mentre PEIE, che viene chiamato
GIEL, abilita solo quelli a priorità bassa |
Schematizzato come interruttori:
Ma vediamo ora altri dettagli per chiarire l' argomento.