vendredi 30 août 2013

VPC-32, casse-tête avec les interruptions

Lors de ma dernière chronique j'écrivais que le code pour la lecture du clavier PS/2 devrait-être terminé dans la journée. Et bien c'est toujours plus long que je le crois au départ. Cette fois ci j'ai eu un sacré casse-tête à résoudre. Mon code vidéo seul fonctionnait bien, mon code clavier seul fonctionnait bien et j'ai ajouter une interruption pour le coretimer qui elle aussi fonctionnait bien seul. Mais lorsque l'interruption du TIMER 2 (vidéo) était active ni le clavier ni le coretimer ne fonctionnait correctement. Malgré une lecture et relecture de la documentation et des recherches dans l'internet je ne voyais toujours pas la solution.

Les registres de l'ombre.

Beau titre non? Ça fait roman d'espionnage. En fait je veux parler des Shadow register set. Le problème avec les micro processeurs qui possèdent un grand nombre de registres est que lors d'une interruption il faut sauvegarder de nombreux registres avant de pouvoir exécuter le code de la routine d'interruption ce qui augmente ce qu'on appelle en anglais interrupt latency. C'est à dire le temps entre le moment où une interruption est déclenchée et le moment ou le code de service de l'interruption est exécuté. Pour régler ce problème les concepteurs de ce type de micro processeur ont eu l'idée d'ajouter un second ensemble (ou plusieurs) de la general registers file de sorte que lorsqu'une interruption se produit le code de service de l'interruption utilise le second ensemble plutôt que l'ensemble des registres utilisé par le code normal. Du coup plus besoin de sauvegarder sur la pile et de restaurer à la fin de l'ISR.

Dans le cas du PIC32MX150F128B il n'y a qu'un seul ensemble de registres secondaire et c'est cette ensemble qu'on appelle Shadow register set. Cette ensemble n'est utilisé que pour les interruptions de priorité 7. Donc dans mon code puisque l'ISR du générateur vidéo NTSC doit avoir la priorité la plus élevé, je l'ai mis au niveaus 7 avec utilisation du Shadow register set. La déclaration est la suivante

void __ISR(_TIMER_2_VECTOR,IPL7SRS) tmr2_isr(void)

IPL7SRS indique au compilateur que cette interruption a le niveau de priorité 7 et utilise le Shadow Register Set (SRS). Il y a 2 autres options SOFT et AUTO. IPLxSOFT signifie que l'ensemble de registre normal est utilisé. IPLxAUTO signifie que le compilateur décide s'il peut utiliser le SRS sinon l'ensemble normal sera utilisé.

Il était évident que le problème que j'avais était causé par l'interruption vidéo, cependant n'ayant pas de débugger en circuit je n'arrivais pas à traquer le bug. Finalement il me vient à l'idée de modifier le code comme ceci pour voir.

void __ISR(_TIMER_2_VECTOR,IPL7AUTO) tmr2_isr(void)

Bingo bug réglé! Pourquoi la première version ne fonctionnait pas? Je n'ai pas eu le temps de fouiller ça mais je suis soulager qu'enfin ça fonctionne.

Beaucoup d'overhead

Pour vous donner une idée du surplus de code généré par le compilateur lorsqu'on choisi l'option IPLxSOFT voici les codes 'C' et assembleur de la première version de l'ISR du coretimer.

Le résultat en assembleur, ahoy! de toutes ces instructions seulement 8 résultent de la compilation du code écris en 'C', le reste c'est de l'overhead.

La documentation explique que lorsqu'une ISR appelle une sous-routine, UpdateCoreTimer() dans ce cas ci, le compilateur n'a pas d'autre choix que de sauvegarder l'ensemble complet des registres généraux sur la pile. Donc pour réduire l'overhead de cette ISR je n'avais d'autre choix que d'éliminer l'appel à UpdateCoreTimer(). J'ai donc modifié le code pour ceci:

Ce qui en assembleur améliore le choses mais ce n'est quand même pas gratuit.

En passant l'ajout de l'interruption pour le coretimer ajoute un faible bruit de fond au signal vidéo. J'ai donc ajouter dans le fichier HardwareProfile.h la ligne #define USE_CORE_TIMER. En mettant en commentaire cette ligne dans le fichier ça supprime l'interruption du coretimer et tout le code associé pour ceux qui voudraient un signal vidéo parfais. L'élimination de ce code signifie qu'il n'y a plus de compteur de millisecondes sys_tick dans le système. Ce compteur est utile pour calculer des délais et des intervalles de temps. Lorsqu'il est présent la routine delay_ms() utilise sys_tick sinon elle utilise la routine delay_us().

Avec tout ça mon code pour le clavier PS/2 n'est pas complété, il me reste encore quelques détails... Ouais! je croise les doigts!

Mise à jour sur https://github.com/Picatout/VPC-32.

Aucun commentaire:

Publier un commentaire