Tutorials - PIC18 by Data Sheet

 

pag 91 - INTERRUPT


INTERRUPT con e senza priorità

 

Riprendiamo la schematizzazione con gli interruttori prima accennata.

Ad esempio, per una struttura di interrupt senza priorità, restando valida la differenziazione tra interrupt periferici e non periferici già presente nei mid-range:

  • Una sorgente di interrupt non periferico agisce sul bit di flag IF, portandolo a livello 1. 
    Se, contemporaneamente è stato abilitato quell' interrupt portando da programma a 1 il bit IE, la chiamata di interrupt arriva allo switch costituito dal bit GIE. 
    Se questo bit è stato posto a 1, la richiesta di interrupt viene processata.
     

  • Analogamente per un interrupt periferico, il flag di abilitazione IE a livello 1 consente il passaggio della richiesta evidenziata dal flag IF. Solamente che, per arrivare al processo di richiesta di interrupt, la chiamata deve passare non solo da GIE, ma anche attraverso lo switch PEIE, che, per abilitarla, deve essere stato pure lui posto a 1.

E' evidente che tutti gli interrupt periferici possono essere esclusi o inclusi agendo sul solo bit di "interruttore generale" PEIE, mentre GIE abilità tutto il complesso delle richieste di interrupt.

Se consideriamo invece la struttura di interrupt con priorità:

osserviamo che la funzione dei bit IF e IE è identica, ma tra la sorgente e la destinazione è interposto un deviatore costituito dal bit IP: se è stato programmato a livello 1, la richiesta si inserisce sul ramo ad alta priorità; se è stato programmato a livello 0 la richiesta passa al ramo a bassa priorità.
Gli "interruttori generali" dei due rami sono analoghi a quanto visto per la singola priorità; solamente cambiano i nomi dei due bit, diventando GIEL per lo switch della bassa priorità e GIEH per quello complessivo.

La presenza o meno dei "deviatori" IP è fissata dal bit IPEN: questa condizione è fissata nella fase di _CONFIG, dato che costituisce un elemento fondamentale dell' organizzazione del controller.

Per default al POR, il bit IPEN è disabilitato e il processore parte in modalità "legacy" con i mid-range, ovvero con interrupt senza priorità.


NOTA:

Va anche notato che i bit IF di flag dell' evento vengono azionati in ogni caso dall' evento stesso, sia che la catena dell' interrupt sia abilitata oppure no.

In altre parole, se, ad esempio, il TIMER0 ha terminato il conteggio, il relativo flag TMR0IF va a livello 1. 
Solo se il bit TMR0IE è stato abilitato dal programma, e lo è anche lo switch generale GIE, l' evento di fine conteggio genererà una richiesta di interrupt. 
Se TMR0IE e/o GIE sono disabilitati, non viene richiesto l' interrupt, ma ugualmente TMR0IF va a 1.

Questo determina due conseguenze:

  1. un evento su una periferica può essere analizzato sia con una gestione di interrupt, sia con una gestione in polling, semplicemente testando lo stato del relativo bit di flag.


     
  2. prima di abilitare una sorgente di interrupt è opportuno CANCELLARE il flag IF relativo in quanto esso potrebbe essere già a livello 1 per un evento precedente e quindi attivare immediatamente una richiesta di interrupt inaspettata

Se nel caso di interrupt senza priorità è necessario un solo vettore comune di accesso alle routines di gestione dell' evento, nel caso di doppia priorità, Microchip ha inserito due vettori distinti.

Si vengono così ad identificare tre indirizzi particolari:

Indirizzo Funzione
0x0000 Vettore del RESET
0x0008 Vettore Interrupt senza priorità o a priorità alta
0x0018 Vettore Interrupt a bassa priorità

Il meccanismo è semplice: le sorgenti a cui è attribuita la priorità maggiore inviano il program counter all' indirizzo 0008H , mentre quelle a bassa priorità usano il vettore a 0018H.
O, in altre parole:

  • Tutte le interruzioni ad alta priorità o in modalità senza priorità fanno capo a 0008h

  • Tutte le interruzioni a bassa prorità fanno capo a 0018h

Durante la gestione di un interrupt a priorità singola, gli switch "generali" PEIE/GIE vengono aperti per evitare una interruzione dell' interruzione, che, avendo un solo vettore di accesso, creerebbe un loop senza uscita.

Durante la gestione di un interrupt con priorità, il funzionamento degli switch è più complesso, dato che il meccanismo di gestione dei due livelli di interrupt è organizzato in modo tale che un evento a priorità alta può interrompere una chiamata a livello basso in quel momento attiva, ma non il contrario. E un evento ad alta priorità non può interrompere un altro evento ad alata priorità in corso in quel momento.

Ovvero, essendo in corso la gestione di un interrupt a bassa priorità, che fa capo al vettore 0018h, l' apparire di un interrupt ad alta priorità interrompe il processo in corso e passa la gestione al vettore 0008h, per rientrare poi al punto in cui era avvenuta la sospensione.

Questo permette una maggiore flessibilità di uso e una maggiore efficacia nella gestione degli eventi di interruzione, sopratutto quando ne esistano diversi.

Un automatismo fa si che all' uscita della gestione dell' interrupt, l' istruzione RETFIE chiuda nuovamente gli "interruttori generali" che erano stati aperti durante la gestione dell' interrupt, permettendo così successive interruzioni, senza alcun necessità di intervento del programmatore.


ATTENZIONE:

Questo determina la conseguenza che:

  • il flag IF, una volta identificato l' evento, va SEMPRE cancellato da programma (salvo poche eccezioni che si cancellano da sole a seguito, in genere, della lettura di un registro). 


Se non venisse cancellato, il flag IF, restando a 1, al momento della riabilitazione degli switch generali di interrupt da parte dell' istruzione RETFIE, scatenerebbe una immediata richiesta di interrupt, bloccando il processore in un loop difficile da debuggare. 

 

 

Se non viene usata la priorità, il vettore a 0018h può essere ignorato.

Da notare che solo 10 bytes separano i due vettori, per cui, nel caso di priorità sarà giocoforza inserire istruzioni di salto alle routine di gestione dell' alta priorità.
Per contro, se non viene usata la priorità, si potranno scrivere queste in modo continuo, ignorando come detto l' esistenza del vettore a 0018h (che, non essendo abilitata la priorità, non sarà considerato dal microcontroller).

Ad esempio, per interrupt con priorità:

;=============================================================================
; Vettore del RESET
      
    ORG 0x00 

      nop                  ; per debug
      goto    main         ; va al programma principale 

;=============================================================================
; Vettore Interrupt Alta Priorità 

    ORG 0x08

      goto    INThp      ; vai alla gestione dell' evento

;=============================================================================
; Vettore Interrupt Bassa Priorità 

    ORG 0x18 

; salvataggio ambiente
     movff STATUS, status_lp
     movff WREG, wreg_lp
     movff FSR0L, fsr0l_lp
     movff FSR0H, fsroh_lp

; gestione interrupt
     btfss INTCON3,INT0IE    ; INT0 abilitato ?
     bra   next1             ; no - prossimo test
     btfss INTCON3,INT0IF    ; no - INT0IF ?
     bra   next1             ; no - prossimo test
     rcall INT0Manage        ; si - gestione ebvento
next1 ......                 ; altri test

; restore ambiente
     movff fsr0_lp, FSR0L 
     movff fsr0_lp+1, FSR0H
     movff status_lp, STATUS
     movff wreg_lp, WREG
     retfie

INT0Manage                   ; gestione di INT0
     ......
     bcf  INTCON3,INT0IF     ; cancella flag
     return

; gestione interrupt alta priorità

INThp  .......               ; gestione
     retfie FAST             ; rientro con Fast Register Stack

e per interrupt senza priorità:

;=============================================================================
; Vettore del RESET
      
    ORG 0x00 

      nop                  ; per debug
      goto    main         ; va al programma principale 

;=============================================================================
; Vettore Interrupt senza priorità 

    ORG 0x08    

     btfss INTCON3,INT0IE    ; INT0 abilitato ?
     bra   next1             ; no - prossimo test
     btfss INTCON3,INT0IF    ; no - INT0IF ?
     bra   next1             ; no - prossimo test
     rcall INT0Manage        ; si - gestione ebvento
next1 ......                 ; altri test
      .......
     retfie FAST             ; rientro con Fast Register Stack

INT0Manage                   ; gestione di INT0
     ......
     bcf  INTCON3,INT0IF     ; cancella flag
     return

L' appartenenza all' alta o bassa priorità è programmabile: la maggior parte delle sorgenti (ma non tutte) dispone di un bit il cui nome termina per IP (Interrupt Priority), all' interno di un registro specifico che consente all' utente di attribuirgli uno dei due livelli.

Dunque, una gestione interrupt comprende varie fasi; per un interrupt senza priorità:

1 posizionare al vettore 0008h le routines di gestione, chiuse da un RETFIE
2 abilitare l' interrupt della periferica desiderata
3 abilitare l' interrupt generale e, se si tratta di interrupt periferico, abilitare anche questo genere di interrupt
4 all' evento, discriminare quale periferica ha generato attraverso il flag l' interrupt e gestirlo
5 prima di terminare la gestione, cancellare il flag della periferica

Nel caso di interrupt con priorità:

1 posizionare al vettore 0008h le routines di gestione dell' interrupt ad alta priorità
2 posizionare al vettore 0018h le routines di gestione della bassa priorità
3 attribuire una priorità all' interrupt della periferica
4 abilitare l' interrupt della periferica
5 abilitare gli switches generali dell' interrupt
6 all' evento, discriminare quale periferica ha generato attraverso il flag l' interrupt e gestirlo
7 prima di terminare la gestione, cancellare il flag della periferica

 


AVVERTENZA:

Una volta che una interruzione a priorità alta è in servizio, tutte le altre fonti di interruzione sono disabilitate fino al completamento della gestione.

Per contro, una interruzione con priorità bassa può essere interrotta a sua volta da una interruzione ad alta priorità.

Questo va considerato anche in relazione alla necessità di salvare i registri del contesto, dato che il FAST REGISTER STACK ha un solo livello di salvataggio.
Nelle pagine relative a questa funzione si trovano maggiori dettagli.

 

 

La doppia priorità è a sua volta selezionabile , in via generale, attraverso un bit IPEN (Interrupt Priority Enable) per cui è possibile scegliere se utilizzarla o meno; per default al POR la scelta è il modo senza priorità, il che rende compatibile la gestione con i processori mid-range. 

In tal senso è opportuno ricordare che il vettore è passato da 004H dei mid-range a 008H e nel sorgente sarà necessaria questa nuova definizione.
Volendo attivare la priorità, occorrerà portare IPEN = 1 (e, ovviamente, aver predisposto la gestione dei due vettori di interrupt).

In modalità senza priorità esiste ancora la differenziazione tra:

  • interrupt non periferici e

  • interrupt periferici

Sono interrupt non periferici quelli di:

  • TIMER0

  • PORTB Change

  • INT0, INT1, INT2

Sono "periferici" tutti gli altri, ad esempio

  • TIMER1, 2, 3

  • USART, MSSP

  • AD, Comparatori

  • HLVD

  • CCP. ECCP

  • ecc.

Nel caso di interrupt senza priorità, come abbiamo visto, la coppia GIE/PEIE ha funzioni analoghe a quelle prima descritte, comuni ai mid-range:

  • PEIE abilita il blocco degli interrupt periferici

  • GIE abilità l' intero sistema degli interrupt

La messa in servizio di un interrupt nell' ambiente senza priorità richiederà di :

1 disabilitare la priorità azzerando IPEN
2 abilitare la sorgente con il bit IE
4 abilitare l' interrupt generale con GIE e, se si tratta di un interrupt periferico, anche con PEIE

Se, invece, si utilizzano le priorità, la distinzione periferico - non periferico non è più valida e le sorgenti si distinguono tra di loro per il livello di priorità assegnato.

In questo caso i due bit di "interruttore generale" sono sempre gli stessi, ma prendono il nome di GIEH (per la priorità alta) e GIEL (per quella bassa). Il meccanismo però resta analogo: 

  • GIEH fa da "interruttore generale" per tutti i livelli di interrupt

  • GIEL agisce solo su quelli a livello basso. 

Quindi:

 

Modalità bit GIE bit PEIE
senza priorità abilitazione globale - GIE abilitazione interrupt periferici - PEIE
con priorità abilitazione globale - GIEH abilitazione priorità bassa - GIEL

 

La messa in servizio di un interrupt nell' ambiente a priorità richiederà di:

1 abilitare la priorità settando IPEN
2 attribuire alla sorgente una priorità con il bit IP
3 abilitare la sorgente con il bit IE
4 abilitare l' interrupt generale con GIEH e, se la priorità è bassa, anche con GIEL

Se questo non viene fatto, per default si ha un solo livello di priorità ed un funzionamento analogo (compatibile) con i mid-range.


 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 11/12/10.