«

»

Déc 27

Ada et les interruptions

Hello,

Pour tout ceux qui n’auraient pas lu le titre, nous allons parler aujourd’hui des interruptions. Vous vous demandez tous (ou bien vous le savez déjà) ce que peuvent bien être les interruptions. Voici la réponse !

Une interruption en informatique est un arrêt temporaire du programme par le microcontrôleur pour effectuer une série d’instructions. La cause de ce changement est externe au programme, sinon ce phénomène s’appelle une exception (comme en Java par exemple). Au déclenchement d’une interruption, le microcontrôleur enregistre toutes les données liées à l’exécution en cours (le contexte) et charge le programme adéquat. Pour cela, il va piocher dans le vecteur d’interruption qui est une table de correspondance entre l’interruption et la séquence correspondante.

A quoi les interruptions peuvent-elles servir ? Dans le cadre le l’UART, nous devions en permanence vérifier si oui ou non une donnée avait été reçue. Pour palier à cela, nous pouvons déclencher une interruption à la réception de données. Ainsi, plus besoin d’attendre : une donnée est traitée dès qu’elle est reçue.

Dans nos stm32f4, les interruptions sont gérées par le NVIC (Nested Vectored Interrupt Controller : le Contrôleur des Vecteurs d’interruption Emboîtés). Le NVIC propose un handler d’interruption (c’est à dire une manière de réceptionner les interruptions) très rapide. Le NVIC se charge de la sauvegarde et du rechargement des registres dans le microcontrôleur, accélère le passage d’une interruption à l’autre et permet de paramétrer 255 interruptions (dont 240 de provenance externe).

Pour initialiser le NVIC et le configurer, nous disposons d’une fonction :

procedure NVIC_Init (IRQn: IRQn_Type; Priority : IRQ_Priority);

Elle prend deux arguments. Le deuxième est de type IRQ_Priority qui est en fait un entier sur quatre bits, c’est-à-dire entre 0 et 15. Le premier est de type IRQn_Type et représente, à une constante près, le channel de l’interruption. Voici la liste des possibilités prédéfinies dans le code :

Par la suite, nous pouvons choisir de désactiver ou d’activer l’interruption. Pour cela, nous disposons de deux commandes :

procedure EnableIRQ (IRQn : IRQn_Type);

pour activer et

procedure DisableIRQ (IRQn : IRQn_Type);

pour désactiver. Enfin, on peut aussi savoir si l’interruption est activée ou non grâce à la fonction :

function GetPendingIRQ (IRQn : IRQn_Type) return Boolean;

Maintenant que nous savons configurer les interruptions, il faut apprendre à lier une interruption à une fonction. Pour cela nous allons utiliser le pragma fourni par Ada :

pragma Attach_Handler(fonction_a_appeler,
numero_de_l'interruption);

Le numéro de l’interruption correspond ici au IRQn_Type. La fonction à appeler doit être placée dans un protected et ne doit pas durer trop longtemps sous peine de poser des problèmes d’exécution du programme principal.

Voilà, vous savez maintenant configurer le traitement d’une interruption grâce au NVIC. Il vous faut maintenant apprendre à déclencher ces interruptions au niveau matériel. Pour cela, il vous faut vous référer au cours du matériel en particulier.

Prenons ici un exemple simple. Imaginons que nous souhaitions déclencher une interruption lorsque nous appuyons sur un bouton. Pour cela, nous aurons besoin de ce que l’on appelle les external interrupts (EXTI). Il s’agit d’interruptions qui sont déclenchées par des éléments externes, comme des évènements sur les pins (ici sur le bouton USER, connecté à PA0).

L’EXTI est composé de 23 lignes, chacune spécialisée dans un certain type d’évènement. Celle qui nous interressent ici sont celles connectées aux GPIOs, c’est à dire les lignes allant de 0 à 15. Chaque ligne peut être connectée aux numéros de pin correspondant. Par exemple, la ligne 0 peut être connectée à PA0, PB0, PC0,…,PI0. Par contre, elle ne peut être connectée qu’à une seule d’entrée à la fois.

Pour configurer l’EXTI, nous avons besoin du type EXTI_Params, dans le package Stm32.EXTI. C’est un record qui est composé des champs suivants :

  • EXTI : les lignes de l’exti à configurer, de type EXTI_Lines. Son fonctionnement est le même pour les pins d’un GPIO
  • Mode : Le mode de l’EXTI, au choix entre Mode_Interrupt (interruptions) et Mode_Event (évènement).
  • Trigger : L’évènement déclenchant de l’interruption, de type EXTI_Trigger. Nous avons le choix entre Rising (montant, on passe de GND à VCC), Falling (descendant, de VCC à GND) et Rising_Falling (montant et descendant).
  • LineCmd : L’activation du module, de type FunctionalState (dans Stm32.Defines). On a le choix entre Enable (activer) et Disable (désactiver).

Nous utilisons ensuite la fonction Config_EXTI prenant un EXTI_Params en paramètre pour appliquer les paramètres.

Il ne nous reste plus qu’à lier le GPIO à l’EXTI. Pour cela nous avons besoin du package Stm32.SYSCFG (SYStem ConFiG) et de la fonction Config_EXTILine. Cette fonction prend en paramètre un EXTI_Source. Il s’agit d’un record composé de deux champs :

  • Port : Le port du GPIO à connecter, de type Port_Source. On peut choisir un SYSCFG_GPIOx où x est la lettre de GPIO (A .. I).
  • Pin : le numéro de la pin, de type Pin_Source. On peut choisir un PinSourcex où x = 0 .. 15.

Voici le résultat final :

A+

Julien