Traitement d'une exception
Le Cortex s'attend à avoir en mémoire une table donnant pour chaque exception l'adresse du handler associé. C'est ce qu'on appelle la table des vecteurs d'interruption.
L'emplacement de cette table en mémoire est stocké dans le registre VTOR(voir la section 4.4.4 Vector table offset register (VTOR)
du Programming Manual).
Ce registre est accessible à l'adresse 0xE000ED08
.
Au reset, le VTOR
est chargé avec la valeur 0x00000000
, ce qui veut dire que la table des vecteurs d'interruption est en flash. Mais vous avez la liberté de construire une autre table en RAM contenant les adresses de vos propres handlers, et de faire pointer VTOR sur cette table.
Lors de l'arrivée d'une exception (pour plus de détails voir la section 2.3.7 Exception entry and return
du Programming Manual):
- Le processeur sauvegarde automatiquement sur la pile les registres
R0
àR3
,R12
,R14
,PC
, etxPSR
. - Il stocke dans
LR
une valeur spécialeEXC_RETURN
signifiant "retour d'exception" :0xfffffff1
,0xfffffff9
ou0xfffffffd
. - Il va chercher l'adresse du handler à exécuter à l'adresse suivante en mémoire :
VTOR + 4*exception_number
. - Il saute à cette adresse et exécute le code qui s'y trouve.
- À la fin de ce code, on trouve typiquement l'instruction
BX LR
, qui signifie "branchement àEXC_RETURN
". Le processeur recharge depuis la pile les registres sauvegardés, et reprend le cours normal de l'exécution du programme.
Le bit indiquant qu'une interruption est en train d'être traitée est clearé automatiquement lors de l'entrée ou de la sortie du handler.
Vous avez dû remarquer que le processeur sauvegarde sur la pile les registres caller saved (en plus du PC
et des xPSR
). Cela permet de coder les handlers d'interruption comme des fonctions C tout à fait normales ! Il suffit juste que le SP
soit positionné à une adresse correcte avant le déclenchement d'une exception.
Cela pose un problème pour la NMI qui n'est pas désactivable et peut se déclencher dès le boot avant que le SP
ne soit bien positionné. Pour cela, les Cortex disposent d'une fonctionnalité rusée. La table des vecteurs d'interruption est organisée ainsi :
Adresse | Vecteur (numéro d'exception) | Numéro d'IRQ externe ("position") | Description |
---|---|---|---|
Exceptions internes au Cortex M4 | |||
0x00000000 | 0 | - | SP initial |
0x00000004 | 1 | - | PC initial (Reset Handler) |
0x00000008 | 2 | - | NMI Handler |
0x0000000C | 3 | - | Hard Fault Handler |
0x00000010 | 4 | - | - |
… | … | … | … |
0x0000003C | 15 | - | SysTick Handler |
IRQ externes au Cortex M4 | |||
0x00000040 | 16 | 0 | WWDG |
0x00000044 | 17 | 1 | PVD_PVM |
0x00000048 | 18 | 2 | TAMP_STAMP |
0x0000004C | 19 | 3 | RTC_WKUP |
… | … | … | … |
Autrement dit :
- la première entrée est la valeur à laquelle positionner le
SP
au reset, - la deuxième entrée est la valeur à laquelle positionner le
PC
au reset (= le point d'entrée du programme).
Au reset, le processeur va positionner automatiquement le SP
et le PC
avec les deux premières entrées de la table. Une interruption peut donc survenir tout de suite, elle sera traitée correctement : le pointeur de pile sera bien positionné. Et sinon, c'est ce qui se trouve à l'adresse contenue dans PC
(le point d'entrée du programme, généralement _start
) qui sera exécuté.
Toutes les exceptions du STM32L275 sont disponibles en page 393 du manuel de référence du processeur et leur nom CMSIS dans le fichier stm32l475xx.h
en ligne 82.