Vous êtes sur la page 1sur 32

MICROCONTROLEUR – LP SESAM :

Partie 4 – Exceptions & Interruptions

Version 2.1
Mise à jour oct. 2020
LibreOffice 5.2 - Debian
Exceptions et Interruptions

•Principe
Il existe des mécanismes pour stopper l’exécution « normale » d’un
programme afin que d’autres parties de code soient lancées lorsque
des « événements » se produisent

2 mécanismes principaux existent


–Si l’événement est physique (hardware, c'est à dire provenant
d'un périphérique), on parle d'interruption
Ex : arrivée d'un caractère sur UART, Ev. Timer, front montant GPIO...
–Si l’événement est logiciel (software), on parle d'exception
Ex : reset, exécution d'une instruction non autorisée, division par 0...

2
Comment ça marche ?

•« Quelque chose » prévient le cœur (CPU)


du Cortex M3 qu’il y a une interruption ou
une exception

•La CPU interrompt alors l’exécution du


programme « principal » pour exécuter le
code correspondant à l’interruption ou
l’exception signalée

•Une fois que ce code a été exécuté, la CPU


retourne au programme principal là où elle
s’était arrêtée
3
A quoi ça sert ?

•Intérêt 1 : le programme est dérouté « immédiatement » sur une partie


de code lorsqu’un événement se produit

Exemple : gestion d’un bouton d’arrêt d’urgence


•Si scrutation classique dans une boucle, le temps de
réaction peut être long (temps de boucle) … pourquoi ?

 Risque que le problème constaté s’amplifie avant que l'intervention ne


commence !
•Si interruption déclenchée par l’arrêt d'urgence, on
obtient une réaction « immédiate »

4
A quoi ça sert ?

•Intérêt 2 : le programme peut s’atteler à une tâche principale dans le main()


et basculer automatiquement sur une autre tâche seulement quand c’est
nécessaire

Exemple : TP de gestion des trains


–On attend que le train atteigne une certaine position pour avancer
dans la machine à états = scrutation permanente du port d’entrées
 le programme ne fait rien d’autre (scrutation la + rapide possible)
–Si interruption déclenchée sur le signal de capteur, on pourrait faire
autre chose dans le main (affichage sur LCD...) et gérer les
« changements » dans la fonction d'interruptions

5
Table d'exceptions ?

La CPU exécute le code principal et une interruption arrive...


Comment détourner l'exécution vers la bonne fonction d'interruption ?
(autrement dit : comment trouver l'adresse du code de la fonction IT ?)
Solution : une zone de mémoire est utilisée pour contenir les adresses de
toutes les fonctions d'exception/interruption

Code de la
Ex : le microcontrôleur sait que si l'on fonction « reset »
0x0000F412
appuie sur reset, l'adresse du code à
exécuter se trouve toujours à l'adresse
0x0000 0004 0x00000008 -------- @fonction IT

0x0000F412 @fonction reset


Cette zone d'adresses s'appelle la table 0x00000004

0x00000000 -------- @fonction IT


d'exception/interruption
6
Utilisation de la table d’exception
•Lorsqu’une source veut déclencher une interruption, la CPU est prévenue
et connaît la source grâce à un nombre appelé vecteur : Exception Number
ou IRQ Number

•La CPU va alors chercher l’adresse stockée dans la table d’exception, grâce
au numéro de vecteur. A cette adresse, on retrouvera la 1ère instruction de la
fonction d’interruption à lancer
→ la table d'exception n'est donc qu'une suite d’adresses, et ne
contient aucune instruction !

•La CPU bascule alors sur la fonction d’interruption et retournera dans le


programme principal une fois la fonction d’interruption terminée

7
Résumé mécanisme d’interruption

Instruction i
en cours
Interruption n

Sauvegarde RAM
PROGRAMME PRINCIPAL

du contexte :
registres et
@retour

Récupère @ fonction
d'interruption dans
table d'exception

Exécution des
instructions IT

FONCTION
Restauration D’INTERRUPTION
contexte et retour
programme princ.

Instruction MECANISME
i+1 D’INTERRUPTION

8
Table d'exception du LPC1768

•Notre µC LPC1768 possède :


- 15 sources d’exception (numérotées de -15 à -1)
- 35 sources d’interruption notées IRQ (périphériques)
numérotées de 0 à 34

•A chaque source est associée une adresse (32 bits = 4


octets) : c'est l’adresse de la 1ère instruction du code à
exécuter en cas d’interruption

•Toutes ces adresses (associées à chaque source) sont


placées dans la table d’exception
→ cette table débute à l’adresse 0x00000000 (ROM)
(emplacement de cette table modifiable)

9
Priorités

•Que se passe-t-il lorsque plusieurs sources d’exception/interruption veulent


générer une interruption au même moment ?
 Il y a un système de priorité

•Une priorité est assignée à chaque source. Il s’agit d’un nombre avec la
logique suivante :
« plus le nombre est petit, plus la source est prioritaire »
Ainsi une source avec une priorité 2 sera plus prioritaire qu’une autre source avec une
priorité 5

Pour notre cible LPC1768 (NXP), les priorités « utilisateur » disponibles sont
codées avec un nombre compris entre 0 et 31 (codage sur 5 bits)

10
Priorités
•Par défaut et hormis les exceptions systèmes (voir plus loin), toutes les
sources ont une priorité 0 (donc maximale)

•Si plusieurs sources ont la même priorité et tentent de générer une


exception/interruption en même temps, la source avec le plus petit
numéro d’IRQ est prioritaire (voir exemples suivants)

•Si une exception/interruption est en cours d’exécution et qu’une autre


source se déclenche, on a donc 2 possibilités :
–Si la nouvelle source est plus prioritaire (strictement), alors la CPU interrompt
l’interruption en cours pour exécuter la nouvelle  Préemption
–Si elle est moins prioritaire, elle est mise en attente et la CPU la traitera quand
il n’y aura rien de plus prioritaire à traiter avant  Tail-chaining

11
Priorités - Exemples

Exemple 1 :
IRQ 6 :
Actif
priorité 1

IRQ 0 :
Actif Actif
priorité 2

main

temps

Interruption Interruption
IRQ 0 IRQ 6

12
Priorités - Exemples

Exemple 2 :
IRQ 6 :
En attente Actif
priorité 5

IRQ 0 :
Actif
priorité 2

main

temps

Interruption Interruption
IRQ 0 IRQ 6

13
Priorités - Exemples

IRQ 4 :
En attente Actif
priorité 2

IRQ 6 :
En attente Actif
priorité 2

IRQ 0 :
priorité 2 Actif

main

temps

Interruption Interruption Interruption


IRQ 0 IRQ 6 IRQ 4
14
Quelques exceptions

•Reset : Priorité -3 (plus haute priorité possible – non modifiable)


–Lors du démarrage ou suite à un appui sur Reset, la CPU exécute une fonction
d’initialisation puis lance le main()

•UsageFault : Priorité programmable (de 0 à 31)


–Instruction non reconnue
–Accès non aligné (par exemple accéder à un int à l’@ 0x10000001 : impossible)
–Division par zéro (si activé)

•SysTick : Priorité programmable (de 0 à 31)


–Timer basique interne au Cortex M3 (souvent utilisé par les OSTR)

15
Interruptions du LPC1768

•Les exceptions sont gérées directement au niveau de la CPU

•Les interruptions, quant à elles, sont gérées par un contrôleur


d’interruptions nommé NVIC : Nested Vectored Interrupt Controller
–Nested indique la possibilité de préemption entre interruptions
–Vectored indique que la gestion des interruptions peut se faire à l’aide de
vecteurs (Interrupt ID dans le slide suivant)

•Toutes les sources sont masquées (=désactivées) par défaut


•Pour autoriser les interruptions dans le NVIC, il faut démasquer les
sources qui nous intéressent (après leur avoir affecté une priorité)

16
Interruptions du LPC1768


IRQ

17
Table d’interruption du LPC1768

•La table d’exception est déjà remplie


avec les adresses de fonctions Extrait du fichier startup_LPC17xx.s
d’interruptions
•Il faut définir ces fonctions si l’on
souhaite effectuer des actions
particulières lors des interruptions

•→ Les noms des fonctions


d’interruption sont donc imposés !
Il faut prendre exactement la syntaxe
présente dans cette liste
(sinon l'interruption ne fait… rien du tout!) Ex : pour une interruption Timer0, la fonction d'interruption
s’appellera void TIMER0_IRQHandler(void)

18
Configuration IT : Fonctions CMSIS

•Il existe des fonctions génériques pour tous les µC Cortex M :

Exemple : activer les interruptions du Timer 1 (IRQ 2) avec une priorité de 3


NVIC_SetPriority(TIMER1_IRQn,3); //Priorité de niveau 3 pour IRQ Timer 1
NVIC_EnableIRQ(TIMER1_IRQn); //Active (démasque) les interruptions Timer 1

19
Acquittement

•Lorsqu’un périphérique souhaite déclencher une interruption, il passe un


signal IRQ (Interrupt Request) à 1 au contrôleur NVIC
 On parle également de drapeau (ou flag en anglais)

•Le NVIC traite alors l’interruption si cette source est démasquée

•C’est à l’utilisateur de baisser le drapeau quand la CPU traite


l’interruption → Il faut donc de manière logicielle effacer cette requête
dans la fonction d’interruption : si ce n'est pas fait, l'interruption se
relancera en continu, et on ne revient plus jamais dans le main !

Généralement, on baisse le drapeau en début de fonction d’interruption

20
External Interrupt (EXT INT)

Application 1 : comment gérer une interruption venant d'un capteur TOR ?


→ P2.10 à P2.13 peuvent fonctionner en External Interrupt (EINT)

Attention :
Seulement EINT0
de câblé sur un BP
pour nos platines
de TP

21
External Interrupt (EXT INT)
•Ces interruptions EXT INT peuvent se déclencher selon 2 modes :
–Sur front : montant ou descendant
–Ou sur niveau : haut ou bas
Les choix se font à partir de registres :

LPC_SC->EXTMODE LPC_SC->EXTPOLAR

22
External Interrupt (EXT INT)

Initialisation = 3 étapes nécessaires avant d’utiliser un périphérique

Activer le périphérique
EXT INT activé par défaut : facultatif
INITIALISATION

Les broches doivent être configurées en mode EINTn


Configurer le mode des
broches (GPIO, Timer...) (n de 0 à 3)
 registres PINSEL (voir slide 21)

Configurer le périphérique
•EXTMODE et EXTPOLAR pour choisir le mode
•Priorité et démasquage dans le NVIC

Utiliser le périphérique

23
Exemple External Interrupt - Synthèse

•Exemple de cahier des charges :


–Lancer une interruption de priorité 6 sur front montant de EINT0 (P2.10)

int main(void)
{
LPC_PINCON->PINSEL4 = LPC_PINCON->PINSEL4 | (1<<20); //mode EINT0 pour P2.10

LPC_SC->EXTMODE = LPC_SC->EXTMODE | (1<<0); //déclenche sur front pour EINT0


LPC_SC->EXTPOLAR = LPC_SC->EXTPOLAR | (1<<0); //choix front montant

NVIC_SetPriority(EINT0_IRQn,6); //EINT0 (IRQ 18) en interruption de priorité 6


NVIC_EnableIRQ(EINT0_IRQn); //active les interruptions EINT0 (IRQ 18)

while(1); //boucle infinie avec le code du programme principal


return 0 ;
}

24
La fonction d'interruption EINT

•Le programme précédent lancera alors la fonction d’interruption


EINT0_IRQHandler() à chaque front montant sur EINT0

•Si l’on souhaite faire une action particulière, il faut écrire cette fonction
d’interruption EINT0_IRQHandler() :
–Il faudra baisser le drapeau correspondant à EINT0
–Puis intégrer le code à exécuter quand l'interruption arrive

•Attention, l'interruption n'est pas une boucle infinie : il faut pouvoir


retourner au programme principal

25
La fonction d'interruption EINT

Drapeau à baisser :
registre EXTINT

Exemple : baisser le drapeau correspondant à


EINT2

LPC_SC->EXTINT = LPC_SC->EXTINT | (1<<2);

26
La fonction d'interruption EINT - Synthèse

•Ex : inverser l’état d’une LED branchée sur P2.0 si front sur EINT0
void EINT0_IRQHandler(void) // Attention à bien nommer la fonction !

FONCTION
{
LPC_SC->EXTINT = LPC_SC->EXTINT | (1<<0); //acquittement

IT
LPC_GPIO2->FIOPIN = LPC_GPIO2->FIOPIN ^ (1<<0); //inverse l’état de P2.0
}

int main(void)
{
LPC_PINCON->PINSEL4 = LPC_PINCON->PINSEL4 | (1<<20); //mode EINT0 pour P2.10

PGM PRINCIPAL
LPC_GPIO2->FIODIR = LPC_GPIO2->FIODIR | (1<<0); //P2.0 configuré en sortie

LPC_SC->EXTMODE = LPC_SC->EXTMODE | (1<<0); //déclenche sur front pour EINT0


LPC_SC->EXTPOLAR = LPC_SC->EXTPOLAR | (1<<0); //choix front montant
NVIC_SetPriority(EINT0_IRQn,6); //EINT0 (IRQ 18) en interruption de priorité 6
NVIC_EnableIRQ(EINT0_IRQn); //active les interruptions EINT0 (IRQ 18)

while(1); // boucle infinie, vide ici, mais qui pourrait gérer le LCD...
return 0 ;
} 27
Interruptions sur Timer

Application 2 : comment exécuter une fonction à des moments bien précis ?

•Les Timers peuvent également générer des interruptions

•Cela est particulièrement utile pour effectuer des actions à des intervalles
réguliers
–Échantillonnage d'un signal d'entrée
–Clignotement régulier d'une alarme
–Mise à jour régulière d'une variable
–…

•Il suffit de configurer le Timer pour qu’il prévienne le NVIC lorsqu'un


événement “fin de comptage” arrive
28
Interruptions sur Timer

•Comment configurer le Timer pour qu'il envoie une requête au NVIC


lorsque son compteur TC atteint la valeur de « match » (MR) ?
 Bit de poids faible du registre (Timer) MCR à mettre à 1

(Ici pour MR0, sinon bits suivants)

Exemple : Reset Timer + IRQ au moment de l'événement MR0


LPC_TIM0->MCR = LPC_TIM0->MCR | (3<<0);

29
Interruptions sur Timer

•Acquittement
Pour baisser le drapeau d’interruption, il faut écrire dans le registre IR
 Bit MRm du registre IR mis à 1

Exemple : Acquittement IRQ TIMER0, match MR0


LPC_TIM0->IR = LPC_TIM0->IR | (1<<0);

30
Exemple IRQ Timer

Cahier des charges : faire changer toutes les 2 secondes l'état d'une LED
branchée à P2.0

→ on veut donc régler le Timer pour que toutes les 2 secondes il arrive en
fin de comptage et lance une interruption
•Calcul des PR et MR pour un comptage sur 2s (donc 0,5 Hz)

 PR = 0, MR = 50.106 - 1

31
Exemple IRQ Timer - Synthèse

void TIMER0_IRQHandler(void) // Attention à bien nommer la fonction !

FONCTION IT
{
LPC_TIM0->IR = LPC_TIM0->IR | (1<<0); //baisse le drapeau dû à MR0
LPC_GPIO2->FIOPIN = LPC_GPIO2->FIOPIN ^ (1<<0); //inverse l’état de P2.0
}

int main(void)
{
LPC_GPIO2->FIODIR = LPC_GPIO2->FIODIR | (1<<0); //P2.0 configuré en sortie

PGM PRINCIPAL
LPC_TIM0->PR = 0; // Prescaler PR à 0
LPC_TIM0->MR0 = 50000000 - 1; // valeur de MR
LPC_TIM0->MCR = LPC_TIM0->MCR | (3<<0); // RAZ du compteur + interruption
LPC_TIM0->TCR = 1 ; // Lancement Timer

NVIC_SetPriority(TIMER0_IRQn,0); // TIMER0 (IRQ1) : interruption de priorité 0


NVIC_EnableIRQ(TIMER0_IRQn); // active les interruptions TIMER0

while(1); //boucle infinie vide


return 0 ;
}
32

Vous aimerez peut-être aussi