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):

  1. Le processeur sauvegarde automatiquement sur la pile les registres R0 à R3, R12, R14, PC, et xPSR.
  2. Il stocke dans LR une valeur spéciale EXC_RETURN signifiant "retour d'exception" : 0xfffffff1, 0xfffffff9 ou 0xfffffffd.
  3. Il va chercher l'adresse du handler à exécuter à l'adresse suivante en mémoire : VTOR + 4*exception_number.
  4. Il saute à cette adresse et exécute le code qui s'y trouve.
  5. À 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 :

AdresseVecteur (numéro d'exception)Numéro d'IRQ externe ("position")Description
Exceptions internes au Cortex M4
0x000000000-SP initial
0x000000041-PC initial (Reset Handler)
0x000000082-NMI Handler
0x0000000C3-Hard Fault Handler
0x000000104--
0x0000003C15-SysTick Handler
IRQ externes au Cortex M4
0x00000040160WWDG
0x00000044171PVD_PVM
0x00000048182TAMP_STAMP
0x0000004C193RTC_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.