Mise en place
Création d'une table de vecteurs d'interruptions par défaut
Les tables de vecteurs d'exceptions sont généralement écrites en assembleur (exemple), mais dans le cas des Cortex il est possible de les écrire en C. C'est ce que nous allons faire.
❎ Dans un fichier irq.c
, créez une table de vecteurs d'interruptions, sur ce modèle :
void * const vector_table[] = {
// Stack and Reset Handler
&_stack, /* Top of stack (initial value of the SP register) */
_start, /* Reset handler (initial value of the PC register) */
// ARM internal exceptions
NMI_Handler, /* NMI handler */
HardFault_Handler, /* Hard Fault handler */
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
SVC_Handler, /* SVC handler */
0, /* Reserved */
0, /* Reserved */
PendSV_Handler, /* Pending SVC handler */
SysTick_Handler, /* SysTick hanlder */
// STM32L475 External interrupts
WWDG_IRQHandler, /* Watchdog IRQ */
PVD_PVM_IRQHandler, /* ... */
TAMP_STAMP_IRQHandler, /* ... */
...
};
Cette table est un tableau de pointeurs constants non typés (void * const
), qu'on peuple avec les adresses de handlers par défaut.
Pour respecter la convention CMSIS, appelez les handlers d'exceptions internes XXX_Handler
, et les handlers d'IRQ externes XXX_IRQHandler
(exemple : DMA1_Channel1_IRQHandler
).
Création des handlers d'interruptions par défaut
❎ Dans le fichier irq.c
, avant la table des vecteurs, définissez des handlers par défaut qui feront la chose suivante :
- désactiver toutes les interruptions
- faire une boucle sans fin
On pourra ainsi vite voir si on sait générer une interruption et si le bon handler est appelé.
Bien entendu, il est hors de question d'écrire 40 fois le même code ! Écrivez donc une macro MAKE_DEFAULT_HANDLER
, qui prend en argument un nom de handler (par exemple truc_IRQHandler
) et qui déclare et instancie la fonction truc_IRQHandler
.
Les handlers par défaut seront amenés à être surchargés par d'autres fichiers C, qui voudront mettre en place leur propre handler. Pour cela, faites en sorte que la définition des handlers inclue bien l'attribut weak
: void __attribute__((weak)) truc_IRQHandler(void) {...}
.
Initialisation des interruptions
❎ Toujours dans irq.c
, écrivez une fonction void irq_init(void)
, qui stocke dans VTOR
l'adresse de la table des vecteurs d'interruptions. Le registre VTOR
fait partie du System Control Block (SCB) dont vous trouverez la définition dans core_cm4.h
.
❎ Pensez à appeler irq_init
dans votre fonction main
…