samedi 5 mai 2012

le bogue se cachait dans un détail

Ce qui est complexe dans la programmation des MCU ce n'est pas d'apprendre l'assembleur mais plutôt de maîtriser tous les détails des périphériques. C'est pourquoi j'ai débuté ce blogue avec le MCU le plus simple possible en terme de périphérique. Mais avec le projet Micro Simon on monte d'un échelon en utilisant un PIC12F675, 2 timers, 1 convertissseur A/N, 1 comparateur et il supporte les interruptions. Pour le projet Micro Simon j'ai décidé d'utiliser le TIMER0 pour contrôler la fréquence de la note à jouer et le TIMER1 comme minuterie. Les 2 périphériques déclenchent une interruption. Ce matin j'ai donc écris la routine de service des interuptions en commençant avec quelque chose qui ressemblait à ceci, j'omets les détails non pertinent à la démonstration.

 org 4
isr ; interrupt service routine
; code pour la sauvegarde de W et STATUS ici
 btfsc INTCON, T0IF
 goto timer0_isr
timer1_isr
;code de gestion de l'interruption
; TIMER1 ici
 goto sortie_isr
timer0_isr
; code pour la gestion de l'interruption
; du timer0 ici
sortie_isr
; code de sortie interruption ici
; restauration de W et STATUS avant de sortir

J'ai écris la partie concernant le TIMER1 et je décide de tester pour voir ci ça fonctionne. Sans succès, je relis mon code, je cherche l'erreur, je ne trouve rien. Comment déboguer sans déboggeur? J'y parviens quand même en utilisant les DEL du jeux Micro Simon comme indicateurs de déroulement du code. Je constate que timer1_isr n'est jamais exécuté. Pour mes tests j'ai désactivé l'interruption du TIMER0 et mis T0IF à zéro donc l'instruction btfsc INTCON, T0IF devrait faire un saut vers timer1_isr. Ce n'est pas le cas, pourquoi? Et bien comme le diable des anglophones, les bogues se cachent parfois dans les détails. Il est important de bien lire la documentation et de la relire. La documentation fournie par Microchip est pourtant claire à ce sujet et je connaissais ce détail mais il n'était tout simplement pas présent à mon esprit dans ce contexte, car si j'avais écris le code pour servir l'interruption du TIMER0 le tout aurait fonctionné mais ce n'était pas le cas. Les indicateurs d'interruption des périphériques sont activés si une condition d'activation se présente même si l'interruption du périphérique concerné est désactivée. C'est même écris dans la documentation dans un encadré pour qu'on ne le manque pas. Donc même si l'interruption du TIMER0 était désactivée le TIMER0 continuait lui à incrémenter et lorsqu'il passait de 0xFF à 0x00 l'indicateur T0IF était mis à 1 même si aucune interruption n'était générée. Lorsque l'interruption du TIMER1 était déclenchée, le test sur T0IF en début était positif et au lieu d'exécuter timer1_isr s'était timer0_isr qui était exécutée. Et comme cette partie du code était vide le programme tombait directement sur la sortie d'interruption.

Ce qu'il faut retenir de cette anecdote c'est qu'il faut lire, relire et conserver à porté de lecture la documention du MCU sur lequel on travaille et si référer continuellement. Même lorsqu'on l'a déjà lu 10 fois plutôt qu'une.


NOTES
1) ICD pour In Circuit Debugger. Outil de déboguage en circuit comme le Microchip ICD2 ou ICD3.

Aucun commentaire:

Publier un commentaire