lundi 20 janvier 2014

introduction aux interruptions

Dans cet article j'explique ce que sont les interruptions et leur utilisation.

Un programme est une suite d'instructions qui s'exécutent l'une à la suite de l'autre et qui éventuellement boucle au début dans un cycle sans fin. Exemple:

; clignotement d'un LED branché sur GP0
; code assembleur pour MCU PIC baseline
; GP0 configuré en sortie
main
   bsf GPIO, GP0
   call delay    
   bcf GPIO, GP0
   call delay
   goto main ; boucle infinie
Une interruption est un mécanisme par lequel le déroulement normal d'un programme est interrompu pour exécuter une autre programme de durée limitée, après quoi l'exécution du programme principal se poursuis à l'endroit ou il a été interrompu. Le programme exécuté lors de l'interruption s'appelle une routine de service d'interruption par la suite je vais utiliser l'acronyme anglophone ISR pour Interrupt Service Rroutine.

Quel est l'utilité des interruptions?

  1. Besoin de répondre aux événements en un temps déterminé. real time
  2. Libérer le processeur du besoin de sonder les périphériques pour voir s'il y a un événement. polling
Une application doit souvent répondre à des événements externes asynchrones, c'est à dire que ces événements peuvent se produire à n'importe quel point de l'exécution du programme principal. Une broche d'entrée change d'état et on doit réagir à ce changement dans un délais minimum. Si on n'a pas d'interruption comme c'est le cas des PIC baseline on est obligé de sonder la broche à un intervalle régulier suffisamment court pour répondre aux contraintes de temps de réponse. Ça complique le programme principal comme on l'a vu dans cet article. Non seulement ça complique la structure du programme principal mais le temps consacré à ces coups de sonde est du temps perdu lorsqu'il n'y a aucun événement.

À partir de cette constatation l'idée de l'interruption est apparu rapidement dans l'histoire des ordinateurs. Il y a donc à l'intérieur des microprocesseurs et microcontrôleurs des circuits dont la tâche est de surveiller les événements programmés pour générer une interruption. Lorsqu'un tel événement se produit le gestionnaire d'interruption déclenche le mécanisme qui va interrompre le programme en cours pour exécuter l'interruption.

Du plus simple au plus complexe

Le dans le cas le plus simple il n'y a qu'un seul vecteur d'interruption. C'est le cas des mcu PIC 8 bits midrange et enhenced midrange. l'ISR doit-être installé à l'adresse 0x04. Par contre beaucoup de processeurs disposent d'une ou plusieurs tables de vecteurs d'interruptions. Chaque entrée de la table contient l'adresse (ou un instruction de saut vers) le début de la routine d'interruption correspondant à la source (périphérique interne ou événement externe) de l'interruption. Par exemple les mcu Atmel AtTiny13a possèdent une table de 10 vecteurs situé en début de mémoire flash. La première entrée de cette table, à l'adresse 0, n'est pas un vecteur d'interruption c'est l'adresse de la routine d'initialisation. Les autres vecteurs correspondent à des périphériques ou des interruptions externes (changement d'état sur une broche).

L'avantage d'avoir un vecteur pour chaque interruption est qu'il n'est pas nécessaire de vérifier la source de l'interruption. Dans le cas des PIC si plusieurs interruptions sont activés, il faut au début de l'ISR vérifier quel est la source de l'interruption en lisant les indicateurs booléen (interrupt flag) associés à chaque source d'interruption. Non seulement ça exige du code supplémentaire mais ça rallonge le délais de réponse. Un autre avantage est la priorisation des interruptions.

exemple: table des vecteur pour l'atTiny13a

Address Labels Code Comments
0x0000 rjmp RESET ; Reset Handler
0x0001 rjmp EXT_INT0 ; IRQ0 Handler
0x0002 rjmp PCINT0 ; PCINT0 Handler
0x0003 rjmp TIM0_OVF ; Timer0 Overflow Handler
0x0004 rjmp EE_RDY ; EEPROM Ready Handler
0x0005 rjmp ANA_COMP ; Analog Comparator Handler
0x0006 rjmp TIM0_COMPA ; Timer0 CompareA Handler
0x0007 rjmp TIM0_COMPB ; Timer0 CompareB Handler
0x0008 rjmp WATCHDOG ; Watchdog Interrupt Handler
0x0009 rjmp ADC ; ADC Conversion Handler

Priorité et multi niveaux

S'il y a plusieurs sources d'interruption. Celles-ci peuvent avoir des priorités différentes. Les interruptions de haute priorité doivent-être servies avant celles de plus basse priorité. Mais si une interruption de basse priorité est en cours d'exécution au moment ou survient une interruption de plus haute priorité comment faut-il gérer ça? Dans bien des cas on ne peut se permettre d'attendre la fin de l'exécution de l'ISR courante, il faut que cette première interruption soit interrompue pour céder la place à celle de plus haute priorité. C'est ce qu'on appelle le multi-niveaux. L'exécution d'une ISR est interrompue et reprendra lorsque celle de priorité supérieure se terminera. Certains processeurs possèdent des mécanismes de priorisation des interruptions, c'est le programmeur qui choisi la priorité de chaque interruption. Sur les PIC24/dsPIC30/dsPIC33 et PIC32MX il y a des registres spéciaux pour configurer la priorité de chaque interruption. Si 2 interruptions de même priorité se produisent au même instant celle qui a le plus petit numéro de vecteur est servie en premier. Dans le cas des AtTiny13a, la priorité est fixé par le fabriquant. C'est l'ordre du vecteur dans la table qui détermine sa priorité. Le vecteur 1 a la plus haute priorité et le 10 la plus faible. Sur les PIC midrange et enhenced midrange il n'y a pas de priorité puisqu'il n'y a qu'un seul vecteur d'interruption.

Interruptions en file

Si une interruption de priorité plus basse ou égale se produit pendant l'exécution d'une interruption on peut réduire le temps de réponse de l'interruption suivante si on évite de restaurer l'état initial avant d'exécuter l'interruption suivante. Certains mcu possèdent un mécanisme pour faire ça. Si ce mécanisme n'existe pas il y a du temps perdu à restaurer les états qui seront resauvegardés par l'interruption qui est en file d'attente.

Interruption non masquable

Certains processeurs possèdent une interruption non masquable (NMI). Ce type d'interruption est habituellement utilisé pour signaler une interruption critique ou une erreur non récupérable du système. Elle est dite non masquable parce qu'elle ne peut-être désactivée ou bloquée par une autre interruption. Par exemple sur un système fonctionnant sur pile on pourrait utiliser un moniteur d'état de la pile qui déclenche une NMI lorsque le voltage descend sous un certain seuil permettant à l'ISR de sauvegarder les états du système en eeprom ou autre media permanent avant de mettre celui-ci en mode sommeil.

délais de réponse et variabilité

Le délais de réponse à une interruption est un facteur important à considérer dans une application. A partir du moment ou un événement se produit et le moment où l'ISR commence à servir cette interruption détermine le de réponse de l'interruption (latency). D'abords lorsqu'un interruption se produit il faut sauvegarder les états du programme en cours, c'est à dire le pointeur ordinal et les autres registres qui sont susceptibles d'être altérés par l'exécution de l'ISR. Bien sur ces états doivent-être restaurés avant de quitter l'ISR. C'est états sont sauvegardés généralement sur la pile des retours ou parfois dans des registres qui sont des doubles des registres originaux (shadow registers). Les PIC enhenced midrange sauvegarde le PC sur la pile et les registres WREG,STATUS,FSRx dans des copies en fin de mémoire RAM (bank 31). Pour les PIC midrange à l'exception du PC tous les autres états doivent-être sauvegardés par programmation au début de l'ISR ce qui rallonge le temps de réponse. En effet la sauvegarde/restauration des états ne peut-être considéré comme une réponse à l'interruption, ce n'est qu'un préambule.

La variabilité (jitter) est la variation du temps de réponse d'une interruption à l'autre. Habituellement un MCU termine l'exécution de l'instruction en cours avant de répondre à une interruption. Si les instructions n'ont pas toutes la même durée d'exécution il y aura une certaine variation dans le temps de réponse. Dans les applications temps réel l'ingénieur doit-être en mesure d'évaluer cette variabilité et s'assurer qu'elle ne déborde pas des seuils de tolérance de l'application.

Bonnes pratiques

Comme chaque interruption suspend l'exécution du programme principal, il est de bonne pratique de réduire le temps passé dans l'ISR. Plus une ISR est courte mieux c'est, surtout si elle se produit fréquemment. Une interruption de haute priorité devrait duré encore moins longtemps car elle bloque aussi la réponse aux interruptions de plus basse priorité.

Dans les applications qui requiert la plus faible consommation d'énergie il est de bonne pratique de construire entièrement l'application sur des interruptions. Après la phase d'initialisation le mcu est placé en mode basse consommation et se sont les interruptions qui le réactive. Lorsqu'une interruption a terminée son travail elle remet le mcu en basse énergie en quittant. Prenons l'exemple des odomètres de vélo qui fonctionnent sur une petite pile au lithium. l'odomètre tombe en sommeil 1 minute après avoir détecté la dernier événement. Lorsque le capteur sur roue détecte une rotation ou que l'utilisateur presse un bouton l'odomètre se réactive pour afficher les données.

Aucun commentaire:

Enregistrer un commentaire