la programmation des pic® par bigonoffread.pudn.com/downloads150/ebook/648143/part4-r4.pdf · 4.2...

155
LA PROGRAMMATION DES PIC® PAR BIGONOFF QUATRIEME PARTIE Les secrets des 16F87x(A) - In Circuit Debugging REVISION 4

Upload: vantuong

Post on 13-Sep-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

LA PROGRAMMATION DES PIC®

PAR BIGONOFF

QUATRIEME PARTIE

Les secrets des 16F87x(A) - In Circuit Debugging

REVISION 4

2

1. INTRODUCTION............................................................................................................................................. 5

1. LE DEBUGGER INTEGRE ............................................................................................................................ 7 1.1 REMARQUES PRELEMINAIRES IMPORTANTES.................................................................................................. 7 1.2 ROLE ET UTILITE DU DEBUGGER..................................................................................................................... 7

2. LE FONCTIONNEMENT HARDWARE ...................................................................................................... 9 2.1 LES REGISTRES ICKBUG ET BIGBUG .......................................................................................................... 9 2.2 COMMENT ÇA MARCHE ?.............................................................................................................................. 11 2.3 SIMPLICITE, OUI MAIS…............................................................................................................................... 14

3. LES DIFFICULTES RENCONTREES ........................................................................................................ 15 3.1 INTRODUCTION ............................................................................................................................................ 15 3.2 EXPLICATIONS ............................................................................................................................................. 15 3.3 L’ADRESSE DE SAUT (OU LA SAGA DE L’ADRESSE 0X2004) .......................................................................... 16 3.4 UN MOT SUR LE PROGRAMME PC ................................................................................................................. 21 3.5 L’ ICD® DE MICROCHIP® ........................................................................................................................... 21 3.6 LE POINT ...................................................................................................................................................... 23

4. LOGICIEL PIC® DE DTRA......................................................................................................................... 25 4.1 INTRODUCTION ............................................................................................................................................ 25 4.2 LE LOGICIEL DE COMMUNICATION ............................................................................................................... 25

5. LA PARTIE HARDWARE............................................................................................................................ 65 5.1 L’INTERFACE BIGOPIC2............................................................................................................................. 65 5.2 REALISATION DES SONDES ........................................................................................................................... 66

6. VERIFICATION DU FONCTIONNEMENT DE L’ENSEMBLE............................................................. 69 6.1 INTRODUCTION............................................................................................................................................. 69 6.2 LE SCHEMA .................................................................................................................................................. 69 6.3 L’INTERCONNEXION..................................................................................................................................... 69

7. CREATION DE LA ROUTINE DE DEBUGGAGE ................................................................................... 77 7.1 POURQUOI ? ................................................................................................................................................. 77 7.2 LE PROGRAMME DEVIENT ROUTINE.............................................................................................................. 77

8. NOTRE PREMIER VRAI DEBUGGAGE EN TEMPS REEL.................................................................. 79 8.1 CREATION DU PREMIER PROGRAMME........................................................................................................... 79 8.2 DANS LE VIF DU SUJET.................................................................................................................................. 84 8.3 RESUME DES PROCEDURES ........................................................................................................................... 92 8.4 QUELQUES REMARQUES ............................................................................................................................... 93 8.5 LES RESSOURCES UTILISEES ......................................................................................................................... 93 8.6 CONCLUSIONS ............................................................................................................................................. 94

9. LE DEBUGGER TEMPS REEL « CBDS » ................................................................................................. 97 9.1 LA DEMARCHE ............................................................................................................................................. 97

10. LE PROGRAMME PIC® DE CBDS.......................................................................................................... 99 10.1 LE CAHIER DES CHARGES ........................................................................................................................... 99 10.2 REALISATION DU PROGRAMME................................................................................................................... 99

11. LE PROGRAMME PC BIGOPIC_PRO.................................................................................................. 129 11.1 INTRODUCTION ........................................................................................................................................ 129 11.2 LE CAHIER DES CHARGES ......................................................................................................................... 130 11.3 LANCEMENT DE BIGOPIC_PRO .............................................................................................................. 131 11.4 CHARGEMENT DU FICHIER EXECUTABLE .................................................................................................. 132 11.5 EN ROUTE POUR LE DEBUGGAGE .............................................................................................................. 138

3

11.6 CONCLUSIONS.......................................................................................................................................... 149 CONTRIBUTION SUR BASE VOLONTAIRE ............................................................................................ 151

B. UTILISATION DU PRESENT DOCUMENT........................................................................................... 153

4

1. Introduction Ce livre est la suite logique du livre « la programmation des PIC® – troisième partie – Techniques du bootloader ». Il s’adresse donc aux utilisateurs expérimentés, qui ont lu et assimilés les 3 ouvrages précédents. Pour ceux qui n’en disposent pas, ils sont toujours disponibles sur mon site : http://www.abcelectronique.com/bigonoff. Je ne reviendrai donc pas sur les notions de base, cet ouvrage étant encore plus technique que les précédents. Attention, on entre ici dans un domaine très pointu. Je remercie de nouveau tous ceux qui m’ont témoigné leur confiance et leur soutien lors de la réalisation des précédents ouvrages. J’ai séparé cet ouvrage du précédent afin de permettre une mise à disponibilité plus rapide, et une mise à jour plus efficace, le thème abordé étant très spécifique et sortant de l’étude des PIC® en général.

Je suis toujours à l’écoute de tous, je réponds toujours au courrier reçu, et si la demande se fait sentir concernant certains chapitres, il me sera toujours possible d’ajouter explications complémentaires et exemples supplémentaires.

N’hésitez donc pas à me faire part de vos remarques et suggestions, et jetez de temps

en temps un œil sur mon site : www.abcelectronique.com/bigonoff pour voir si une nouvelle révision n’est pas disponible. Je décline toute responsabilité, directe ou indirecte, pour toute conséquence fâcheuse pouvant résulter de l’utilisation de cet ouvrage, des interfaces décrites, ou des logiciels. Tout est fournis « tel quel », et l’utilisation est soumise à votre seule et unique responsabilité.

Aucun recours ne pourra être engagé contre moi. Si vous n’êtes pas d’accord, merci d’effacer ce document, fichiers joints, et utilitaires, et de ne pas en tenir compte. Tous les droits sur le contenu de ce livre et ses annexes restent ma propriété. Je vous souhaite beaucoup de plaisir à la lecture de ce petit ouvrage sans prétention, et je vous le conseille : expérimentez, expérimentez, et expérimentez encore ! Remarque

A la date de la parution de ce document, la réalisation personnelle d’un debugger de ce type était tout à fait justifiée. En 2007 (date de cette remarque), il en va un peu autrement : L’arrivée de nouvelles versions de MPLAB® et de l’évolution de l’ICD2® permettent l’utilisation de ce dernier dans tous les cas possibles et pour tous les PIC®.

Néanmoins cette application demeure à mon avis d’un bon niveau didactique pour

l’enseignement, et également une solution opérationnelle efficace et très bon marché pour

5

l’amateur peu fortuné qui ne développe que sur les familles 16F, ou pour le professeur désirant équiper toute une classe d’outils de debuggage à prix ridicule.

Dans tous les cas, je pense que la lecture de cet ouvrage pour tous les utilisateurs de

PIC16F sera loin d’être inutile et montre en tout cas des exemples précis d’un besoin d’optimisation du code. … Et vive l’Internet libre ! BIGONOFF

6

1. Le debugger intégré 1.1 Remarques préléminaires importantes Le cours prend comme exemple le debuggage des 16F876. Les autres PIC® de ce groupe (16F87x) peuvent être utilisés sans problème.

A partir de la révision 3 de ce cours, Torium a ajouté la gestion des 16F87xA. Pour utiliser les versions « A », vous utiliserez le fichier « cbdsA.asm » présent dans le répertoire « fichiers » lorsque je parlerai dans les chapitres suivants du fichier « cbds.asm . Ce dernier doit être utilisé impérativement pour les versions « non A » des PIC®. Le logiciel BIGOPIC_Pro, à partir de sa révision 3 détecte automatiquement le type de PIC® connecté au debugger, mais si vous vous trompez de fichier, le debugger ne fonctionnera pas, les versions « A » et « non A » des PIC16F87x étant incompatibles au niveau de l’écriture en mémoire flash. 1.2 Rôle et utilité du debugger Il vous est probablement déjà arrivé de vous retrouver face à un programme qui refuse de fonctionner. Dans ce cas, vous vous êtes probablement lancés dans le debuggage en pas-à-pas à partir du simulateur de MPLAB®. Malheureusement, il n’est pas toujours facile, ni possible, de debugger de cette façon. En effet, lorsque le PIC® est placé sur sa carte d’application, il peut, par exemple, dialoguer avec son entourage. Une erreur dans les communications, et vous pouvez vous trouver dans une énorme difficulté de debuggage. Idem s’il s’agit de la lecture d’un composant I2C, d’une mesure analogique, ou toute autre réaction avec des composants physiquement présents. Pour résoudre ces cas de figure, il existe deux principales solutions. L’émulateur en temps réel, et le debugger intégré. L’émulateur en temps réel est un processeur capable de simuler en temps réel le fonctionnement de votre PIC®, avec une sonde lui permettant de se connecter sur votre carte d’application. Il simule donc non seulement la partie logicielle, mais également la partie matérielle du PIC®. Ce composant dialogue avec un programme sur PC de façon à vous permettre d’analyser le contenu de tous les registres simulés. C’est la solution la plus puissante, malheureusement l’émulateur coûte très cher et les sondes de connexion également. Une telle solution vous amène vite à des prix de plusieurs centaines d’euros. Si vous avez les moyens (et la possibilité d’amortissement), n’hésitez pas (jetez un œil sur l’ICE4000® de chez Microchip® par exemple). Cependant, je ne pense pas que ce soit le cas de tout le monde. Il existe heureusement, sur certains PIC® de la famille Mid-range, dont nos 16F87x(A), une seconde possibilité : Le debugger en temps réel, qui utilise le PIC® lui-même comme outil de debuggage.

7

On implémente dans le programme des instructions destinées à communiquer avec un programme sur PC. En l’absence de mécanisme spécifique (comme c’est le cas du 16F84), vous êtes contraints de placer des « call » vers votre routine de debuggage au sein de votre programme à debugger. Vous vous rendez cependant compte que si votre programme plante, vous ne pouvez deviner où, donc vous ne savez pas où placer les appels vers cette routine de debuggage. Un vrai debugger intégré doit donc pouvoir interrompre le PIC® (un peu comme une interruption), afin de permettre d’analyser les registres même si le programme principal (ou même une interruption) est planté. Un mécanisme interne explicitement prévu est donc nécessaire. Votre PIC16F87x(A) possède, câblé en interne, la possibilité de debugger vos programmes en temps réel de cette façon. L’utilisation d’un debugger en temps réel est de ce fait possible. Ce debugger s’active en utilisant l’option « _DEBUG_ON » au niveau des bits de configuration. Les pins RB6 et RB7 devront être utilisées en standard, au sein de votre routine de debuggage, pour établir une liaison entre le PIC® et votre programme de debuggage. Vous ne pouvez donc pas utiliser ces pins dans l’application à debugger. Ceci constitue une limite d’utilisation du debugger intégré. Elle est imposée par la construction même du PIC®, contrairement au bootloader pour lequel nous pouvions, moyennant un peu d’efforts, utiliser n’importe quelle pin du PIC® pour communiquer. Notez qu’il sera presque toujours possible de debugger votre application en vous arrangeant pour ne pas utiliser ces pins, quitte à ce que, une fois la partie du programme à debugger en ordre, remettre les pins RB6 et RB7 en service. Il est également possible de gérer l’électronique de façon à permettre non seulement l’utilisation des pins RB6 et RB7 par le debugger, mais également par l’électronique cible. Ceci sort cependant du cadre de cet ouvrage. Vous pouvez aussi vous arranger pour que les pins RB6 et RB7 ne commandent que des fonctions annexes (pilotage de leds). Ainsi, lors du debuggage, vous n’êtes pas ennuyés par l’absence de fonctionnement de ces pins. Une autre limite est que les routines de debuggage auront besoin d’une certaine quantité de mémoire de programme, et de quelques adresses dans une ou plusieurs zones de variables. Mais, étant donné la taille de ces zones sur les 16F87x(A), ceci ne devrait pas poser trop de problèmes. Vous perdez également un emplacement de pile, mais nous verrons que ce n’est pas génant. Pour résumer ce qui précède, votre PIC® dispose de la possibilité d’être interrompu par le debugger en temps réel. Cette interruption particulière connecte le PIC® sur une routine de debuggage, qui communique avec un programme sur PC en utilisant les pins RB6 et RB7. Nous allons maintenant voir en détails comment tout ceci fonctionne.

8

2. Le fonctionnement hardware 2.1 Les registres ICKBUG et BIGBUG Si vous vous précipitez sur votre datasheet, vous n’allez jamais trouver ces registres. En fait, ils y sont, mais sous la dénomination « réservé ». ICKBUG se trouve à l’adresse 0x18E, et BIGBUG en 0x18F, tous deux bien entendu en banque 3, comme l’indique leur adresse.

Notez que MPLAB® n’intègre pas leur définition, si vous les utilisez, vous devrez les déclarer vous-même : ICKBUG EQU 0x18E BIGBUG EQU 0x18F Notez que si vous écrivez un programme qui utilise ces registres, MPLAB® vous gratifiera d’un warning. En effet, ces registres ne sont pas accessibles durant le déroulement normal du programme. ICKBUG contient 3 bits qui gèrent le fonctionnement du debugger, à savoir : b7 : INBUG : program is IN routine deBUG flag bit b6 : FREEZ : On-chip debugger FREEZe mode enable bit b5 : SSTEP : Single STEP enable bit Ces bits ne sont pas non plus déclarés dans les fichiers include de MPLAB®. Pour les utiliser, vous devrez les définir vous-même : #DEFINE INBUG ICKBUG,7 #DEFINE FREEZ ICKBUG,6 #DEFINE SSTEP ICKBUG, 5 En effet, Microchip® ne cache pas ces informations (quoi que…), mais n’en fait pas étalage non plus. Il faut vraiment savoir ce que l’on cherche pour les trouver. L’aventure que j’ai menée avec ce mode m’a conduit à penser que l’exploitation efficace du mode debugger (j’entends par là, la réalisation personnelle des routines, pas leur utilisation) sans passer par les kits commercialisés n’est pas vraiment à la portée d’un débutant, et impose d’être vraiment têtu.

Mais attendez la fin… Le bit INBUG est positionné automatiquement lorsque le PIC® se connecte sur sa routine de debuggage, il s’efface automatiquement lorsqu’on en sort. Vous pouvez considérer qu’il fonctionne un peu à l’envers du bit GIE pour les interruptions, mis à part que vous n’avez pas à l’initialiser pour mettre le debugger en service. Vous n’avez donc pas à vous préoccuper vraiment de ce bit. Par contre, si vous arrivez à lire ce bit comme étant positionné à « 1 », cela constitue la preuve que vous êtes entrés en mode de debuggage.

9

Tant que INBUG reste positionné (c’est-à-dire tant que vous êtes dans la sous-routine de debuggage), les interruptions sont mises hors-service, indépendamment de la valeur de GIE.

Votre routine de debuggage a donc priorité absolue sur les autres interruptions, elle ne sera donc jamais interrompue. De plus, tant que INBUG reste positionné, vous ne pouvez interrompre le programme de

debuggage pour entrer de nouveau dans le mode de debuggage (tout comme une interruption ne peut interrompre la routine d’interruption). Le bit FREEZ détermine que lorsque vous arrêtez votre programme pour debugger, les timers TMR0 à TMR2, ainsi que leur prédiviseur s’arrête également de fonctionner.

Vous avez donc le choix entre continuer de compter (FREEZ = 0), ou arrêter les timers durant la période de debuggage (FREEZ = 1). La conversion analogique/numérique et les transferts via l’USART sont également gelés si FREEZ = 1. Vous comprenez que si vous positionnez « FREEZ », vous devriez obtenir une « photographie » de votre PIC® au moment où vous passez dans la routine de debuggage. Tout est gelé. Par contre, si vous utilisez une application temps réel (horloge par exemple), et que vous voulez regarder ce qui se passe sans perturber le fonctionnement du programme, vous aurez plutôt intérêt à placer FREEZ à 0. J’ai tenté d’utiliser cette option, je n’y suis jamais arrivé. J’ai donc écrit à Microchip® pour demander des explications supplémentaires, et voici la réponse dont j’ai été gratifié (après avoir du lourdement insister) : « The On-chip debugger specification is presented as a stand-alone document and no support is provided. »

« Le document concernant les spécifications du debugger intégré est un document isolé et aucun support n’est fourni » Autrement dit, Microchip® vante la possibilité de debugger en temps réel, mais se garde bien de répondre aux interrogations des utilisateurs concernant les anomalies de fonctionnement. Pas très élégant tout ça. Et le reste ne le sera guère mieux. Sachez déjà que vous pénétrez dans une propriété « chasse gardée ».

Vous verrez dans le chapitre suivant que ceci n’est que la partie visible de l’iceberg, et que Microchip®, non content de ne pas supporter la fonction, tente d’en interdire l’utilisation. Nous considérerons donc que l’impossibilité de « geler » les périphériques constitue une autre limite du debuggage en temps réel. Mais bon, ça ne veut pas dire que ce mode n’est pas intéressant, loin de là. D’autre part, il se peut fort bien que ce bug soit résolu dans les futures versions de PIC®. A vous donc de vérifier à ce moment (mais bon, j’en doute fort).

10

Le bit SSTEP permet, une fois positionné, d’entrer dans la routine de debuggage après exécution de chaque instruction. On a donc un fonctionnement en pas-à-pas, très utile dans le mode debuggage. Ces bits devront évidemment être positionnés par votre routine de debuggage. Vous voyez que vous n’avez pas beaucoup de bits à gérer pour vos debuggages. Jusqu’ici, tout est rose, l’avenir s’annonce bien. Il nous reste la possibilité d’introduire un « break » dans le programme à debugger, c’est-à-dire de définir qu’une fois arrivé à une certaine adresse, le programme utilisateur se connecte de lui-même sur la routine de debuggage. Il suffit pour cela d’entrer cette adresse, codée sur 13 bits, dans les bits restants de nos 2 registres. On entrera donc les bits 12 à 8 de cette adresse dans les bits 4 à 0 de ICKBUG, les bits 7 à 0 dans le registre BIGBUG. Notez que cette adresse ne sera remise automatiquement à « 0 » que sur une mise sous tension, une autre forme de reset (MCLR) n’affectera pas la valeur de cette adresse. Les bits représentant cette adresse sont numérotés de BKA12 à BKA0 (BreaK Adress bit xx). 2.2 Comment ça marche ? Et bien oui, voici la question principale, quels sont les mécanismes mis en œuvre dans ce mode de fonctionnement ? Tout d’abord, vous devez comprendre que la sous-routine de debuggage fonctionne comme une « super-interruption ». Seulement, cette fois, ce n’est pas l’adresse 0x04 qui sert d’adresse de départ, mais l’adresse 0x2004.

A cette adresse, vous écrirez donc un : « goto xx », avec « xx » comme adresse de départ de votre sous-routine de debuggage. Le saut s’effectuera toujours dans la dernière page du PIC®, c’est donc là que vous devez placer votre routine de debuggage. Lorsque vous mettez votre PIC® sous tension, avec le bit « debug » positionné, l’adresse de « break » dans les bits BKAxx est initialisée avec la valeur sur 13 bits de 0x0000. Cette adresse est la valeur de démarrage du programme, comme vous le savez déjà. La première instruction va être exécutée, PUIS, comme cette adresse correspond à celle placée comme adresse de break (0x0000 à la mise sous tension), le programme va sauter à l’adresse 0x2004, adresse qui contient un « goto » vers l’adresse de votre sous-routine.

Je répète que cette sous-routine devra se trouver dans la dernière page de la mémoire programme, par exemple à l’adresse 0x1F00, ceci parce que vous n’avez pas la possibilité d’entrer une valeur pour PCLATH. La page est donc gérée automatiquement par le PIC®, et sera automatiquement la dernière page disponible. Cette démarche est logique, car cela vous laisse le maximum de place pour écrire votre programme à debugger.

11

Une fois que le PIC® rencontre l’égalité d’adresse avec BKAxx, il exécute l’instruction de cette adresse, puis sauve son PC (pointeur de programme) sur la pile (adresse de retour), et dans les bits BKA12 à BKA0 (pour que la routine de debuggage sache où s’est arrêté le programme). Donc, si vous suivez, à la mise sous tension, voici ce qui se passe : - On exécute la première instruction du programme - Comme l’adresse de la première instruction = adresse de BKAxx = 0x00, - on sauve le PC (qui pointe sur l’instruction suivante) sur la pile et dans BKAxx - on saute en 0x2004 - L’adresse 0x2004 contient un « goto sous-routine debug » - On saute donc en « sous-routine debug »

A ce stade, les bits BKAxx contiennent l’adresse de l’instruction suivante à exécuter. Donc, votre routine de debuggage s’initialise après exécution de la première instruction de votre programme principal. Corollaire : dans un programme dont le mode DEBUG est validé, le programme est placé en mode de debuggage après exécution de la première instruction. Il est donc nécessaire, une fois le programme debuggé, de reprogrammer le PIC® SANS valider le mode DEBUG. Sans cela, votre carte ne pourrait fonctionner que connectée à votre interface de debuggage. Comme le premier arrêt s’effectuera automatiquement après l’exécution de la première instruction, il est conseillé de placer une instruction « nop » comme première instruction du programme. Ainsi, il vous sera possible de démarrer si besoin est l’intégralité de l’exécution du programme commençant à l’adresse 0x0001. ORG 0x00 ; début du programme nop ; nop sera « exécuté » avant l’initialisation du debugger goto start ; le programme commence réellement, debugger initialisé. Maintenant, voyons comment provoquer le premier point d’arrêt utile de votre programme. Vous avez 3 façons de provoquer un saut vers la routine de debuggage (« halt ») : - Lorsque l’adresse contenue dans BKAxx correspond à l’adresse en cours d’exécution. - Lorsque vous effectuez une transition de « 1 » vers « 0 » de la pin RB6. Cette pin est

utilisée comme pin de commande pour le debugger - Lorsque vous avez paramètré SSTEP, un « halt », autrement dit, l’exécution de votre

routine de debuggage, sera exécuté après l’exécution de chaque instruction (mode pas-à-pas).

Vous devez de plus savoir, ou vous rappeler que :

- A chaque « halt », l’adresse de l’instruction suivante est mémorisée dans BKAxx

12

- Tant que le bit INBUG est positionné, on ne peut générer un nouveau break (de la même façon que tant qu’on se trouve dans une routine d’interruption, on ne peut plus être interrompu).

- La routine de debuggage se termine par « return », ce qui permet de dépiler l’adresse du

PC, et donc, de revenir au programme principal - Tant que INBUG est positionné, aucune interruption ne peut avoir lieu - Si « FREEZ » est positionné, tant que INBUG est positionné, les timers sont gelés (en

théorie). Sinon, ces modules continuent de fonctionner. Dans la pratique, nous verrons que cela ne fonctionne pas. C’est vraiment dommage. Par contre, toute transmission (USART) s’arrête lorsque le PIC® est stoppé, indépendamment du bit FREEZ.

- Le watchdog continue de fonctionner normalement durant l’exécution de la sous-routine

de debuggage. A vous d’en tenir compte. - Les « reset » sont toujours pleinement opérationnels durant l’exécution de la sous-routine

d’interruption. Une action sur MCLR, par exemple, provoquera bien le redémarrage du programme (mais BKAxx resteront inchangés). Dans ce cas, le programme va démarrer et s’exécuter jusqu’au moment où il arrivera à l’instruction pointée par « BKAxx ». Il se connectera alors sur la routine de debuggage.

On peut déduire 2 corollaires de ces connaissances :

- Comme l’exécution d’une instruction « return » provoque la sortie du mode de debugger,

vous ne pouvez pas utiliser de sous-programmes dans votre programme de debuggage .J’ai vérifié, et, effectivement, ceci n’est pas possible (ben oui, je vérifie tout, c’est mon côté méfiant). Attention, je parle du programme DE debuggage, pas du programme A debugger, qui lui, évidemment, contient vos sous-programme.

- Comme, lors de l’entrée en mode debugger, l’adresse de l’instruction suivante est copiée

dans BKAxx, un « halt » automatique sera généré dès l’exécution de l’instruction correspondante.

De ce fait, un point d’arrêt dans une routine de ce type :

Routine nop goto $-1 provoquerait des arrêts automatiques répétés, puisqu’on repasserait sans cesse aux mêmes adresses, donc aux mêmes BKAxx.

La seule méthode pour éviter complètement tout point d’arrêt, est de placer l’adresse BKAxx à une valeur que n’atteindra jamais votre programme à debugger. La méthode la plus sûre est de placer BKAxx à une valeur qui pointe dans votre routine de debuggage (puisqu’à cet endroit, on ne peut pas être interrompu, BKxx est donc inefficace).

13

2.3 Simplicité, oui mais… Vous connaissez maintenant tous les mécanismes du debuggage, vous savez que RB6 sert à provoquer des sauts vers votre routine de debuggage (halt), vous savez initialiser vos registres, et vous savez comment travailler en mode pas-à-pas. Enfin, vous savez comment provoquer un arrêt de votre programme à une adresse spécifique (break-point). Maintenant, tout ceci est bien joli, mais il faut encore plusieurs éléments pour que tout cela fonctionne : - Il vous faut écrire votre routine de debuggage - Il vous faut placer « goto debug » à l’adresse 0x2004 - Il vous faut un programme sur votre PC pour communiquer avec votre routine de

debuggage.

Voyons tout ceci :

14

3. Les difficultés rencontrées

3.1 Introduction Je vais réaliser avec vous deux programmes de debuggage. Le premier, DTRA, vous permettra de communiquer en ASCII avec le logiciel BIGOPIC, version light ou pro, placé dans ce mode. Je verrai plus loin la seconde option. 3.2 Explications La pin RB6 sert à interrompre le programme principal, ceci est piloté par le hardware du PIC®. Une fois dans votre routine de debuggage, vous disposez des pins RB6 et RB7 pour dialoguer avec votre programme de debuggage qui tourne sur votre PC. Libre à vous d’en faire l’usage que vous voulez. Le PIC® ne gère RIEN à ce niveau, c’est donc à vous de créer votre routine de dialogue, en pilotant les pins concernées directement depuis votre programme de debuggage. Vous serez donc amenés à modifier les bits 6 et 7 de TRISB lors de cette routine. Afin de ne pas perturber votre programme principal, vous disposez d’un TRISB spécifique à votre routine de debuggage. Ce TRISB particulier se trouve à l’adresse 0x186, donc à la même adresse relative que le TRISB « normal », mais en banque 3. De façon identique, la manipulation des bits RB6 et RB7 se fera via un PORTB spécifique, à l’adresse 0x106, autrement dit à la même adresse relative que le PORTB « normal », mais en banque 2. Il faut en effet vous souvenir que les ports fonctionnent de la façon « lecture/modification/écriture », et donc, que même si vous effectuez un simple « bsf PORTB,7 », ceci pourrait avoir comme conséquence de modifier un autre bit de PORTB. Ceci donnera, par exemple : bsf STATUS,RP0 ; passer en banque 3 bsf STATUS,RP1 bcf TRISB,7 ; passer RB7 en sortie bcf STATUS,RP0 ; passer en banque 2 bsf PORTB,7 ; placer « 1 » sur RB7 Attention, n’utilisez pas « BANKSEL TRISB » ou « BANKSEL PORTB, car TRISB et PORTB sont déclarés comme étant en banques 1 et 0. Votre routine de debuggage devra prendre en charge la communication avec votre PC (comme expliqué dans le cours-part1 au niveau du chapitre sur l’ISO7816), sans utiliser le hardware spécifique, à moins que votre application ne laisse ces ressources libres. Vous avez donc le choix entre utiliser les ressources standard (RB6 + RB7) seules, ou de gérer d’autres ressources, comme l’USART, le MSSP etc. Dans ce dernier cas, ces ressources

15

ne seraient plus disponibles pour votre application principale. Les routines de debuggage écrites ne seraient alors plus universelles. Rien ne vous empêche, par exemple, d’écrire une petite routine de debuggage qui allume des LEDS sur des pins des PORTs en fonction de la valeur de certains registres. Vous voyez que tout ceci nécessite un travail assez important, mais pas du tout impossible. D’ailleurs, vous commencez à me connaître, je vais vous le démontrer (et même réaliser l’intégralité du projet). 3.3 L’adresse de saut (ou la saga de l’adresse 0x2004) Maintenant, nous devons écrire l’instruction goto à l’emplacement 0x2004 de la mémoire du PIC®. Or, la mémoire programme s’arrête à 0x1FFF. Les adresses à partir de 0x2000 sont réservées par le constructeur. Souvenez-vous que l’adresse 0x2007 contient les bits de configuration, l’adresse 0x2006 contient l’identification du composant, et, comme vous le savez maintenant, l’adresse 0x2004 la première instruction exécutée lors du passage en mode debugger. Je peux également vous dire que les adresses 0x2000 à 0x2003 peuvent être utilisées par l’utilisateur, par exemple pour mémoriser une version de programme, une identification personnelle, ou le checksum de vérification du programme. Il ne reste que l’adresse 0x2005 qui ne m’ait pas encore livré ses secrets (s’il y en a). Premier réflexe, vous allez utiliser la directive suivante (que je vous ai d’ailleurs donnée plus haut pour des raisons de facilité de compréhension) : ORG 0x2004 goto debug MPLAB® vous gratifiera d’un double warning du style : Message[306] chemin\DEBUG.INC 52 : Crossing page boundary -- ensure page bits are set. Warning[220] chemin\DEBUG.INC 52 : Address exceeds maximum range for this processor. Le premier parce que vous passez d’une page à l’autre (en effet, l’adresse 0x2004 est dans une page inexistante, considérée par MPLAB® comme étant la page 0), alors que vous l’écrivez à la suite de votre programme situé en page 3. Le second parce que vous tentez d’écrire une instruction hors de la mémoire programme du PIC®. En fait, ce n’est pas tout à fait vrai, puisqu’il est nécessaire d’écrire le « goto » à l’adresse 0x2004, mais Microchip® semble dissuader les utilisateurs de poursuivre dans cette voie, ce que confirme leur réponse à mon émail. Et vous allez voir que ce n’est pas fini. Cependant, l’instruction en question est bel et bien écrite dans le fichier « .hex » qui sera créé. Ce ne sont pas quelques warnings qui vont nous impressionner.

16

Maintenant, il faut pouvoir écrire cette valeur dans le PIC®, en même temps que le programme qui y sera placé. Hélas ! J’ai examiné plusieurs programmes connus permettant la programmation des PIC® (dont le célèbre IC-PROG), aucun ne permettait d’entrer une valeur à l’adresse 0x2004. J’en ai déduis que personne (??) n’avait eu l’idée d’exploiter cette possibilité (même mon programmateur professionnel ne permettait pas cette fonction. J’ai donc envoyé un petit mail à l’attention du célèbre créateur de IC-PROG, Bonny Gijzen, pour lui signaler que si son programme permet bien de mettre en service le mode « debug », en paramétrant le registre de configuration, il ne permet pas de l’utiliser. Je lui ai donc demandé s’il acceptait d’ajouter une fonction dans son programme permettant d’entrer l’adresse du saut. Bonny Gijzen a eu la grande gentillesse de me répondre le jour même, et, après un échange de correspondance qui a duré jusque 2 heures du matin, il m’a envoyé une version de IC-PROG qui permettait d’écrire l’adresse de saut à l’emplacement mémoire 0x2004. Je le remercie donc en votre nom à tous. Si vous utilisez cette fonction, donc tout ce qui suit dans ce chapitre, n’oubliez pas de lui envoyer un mail de remerciement (en anglais), ça ne coûte rien, et ça fait toujours plaisir. Précisez-lui que vous utilisez la fonction de debuggage à l’adresse 0x2004, ainsi, si nous avons encore besoin de lui dans le futur, il saura que son travail aura été utile. Si vos connaissances en anglais sont nulles, un simple « Hi Bonny, I use Bigonoff’s books. Thanks for access at 0x2004 address on PIC16F876 in IC-Prog » suffira.

Son adresse émail est : [email protected]

Dans la version que j’ai reçue, un clic droit dans la fenêtre principale fait apparaître un menu qui indique « edit debugger word ». Il reste à savoir quelle valeur doit figurer dans cette case. En fait, vous devez y inscrire un « goto debug », avec « debug » l’adresse de votre sous-routine contenue dans la dernière page de la mémoire programme. Notez qu’en principe, cette adresse se trouvant dans le fichier « .hex » créé par MPLAB®, la bonne valeur doit déjà y figurer. Dans ce cas, ceci fera office de vérification. Imaginons que nous désirions écrire notre routine en 0x1F00, ce qui nous laisse 256 octets pour écrire notre routine : Un « goto » est traduit en binaire par MPASM® en : B’10 1kkk kkkk kkkk ‘, avec k… représentant les 11 bits de poids faible de l’adresse de saut. Les 2 bits de poids fort étant dans PCLATH . Notre adresse de saut est 0x1F00, donc B’1 1111 0000 0000’. Si on conserve les 11 bits de poids faible, ceci nous donne B’111 0000 0000’. Le goto 0x1F00 sera donc traduit en : B’10 1111 0000 0000’, autrement dit : 0x2F00

17

C’est donc cette valeur que vous devrez entrer à l’adresse 0x2004 de votre PIC®. Il va de soi que nombre de personnes utilisent un programmateur avec logiciel spécifique. J’ai donc demandé à quelques constructeurs de modifier leur logiciel pour permettre à tous l’accès à cette fameuse adresse 2004. La réponse type qui m’a été fournie a été surprenante. « Nous suivons les recommandations officielles de Microchip® qui nous interdisent de programmer cette adresse ». En fait, effectivement, l’ordinogramme de programmation indique explicitement qu’il faut sauter l’adresse 2004, en évitant de la programmer. J’ai eu beau insister (vous me connaissez), rien à faire, j’obtenais alors comme réponse type : « Nous voulons un document de travail pour programmer cette adresse, contactez Microchip® ». C’est ce que j’ai fait, pensant qu’il s’agissait d’une erreur de Microchip®. Je me suis alors vu gratifier d’une charmante réponse : If you are asking Microchip to give you permission to violate the programming specification, I cannot accomodate your request. We retain the right to use the "reserved" program memory locations for our use at any time, which is why these locations are not available for general purpose storage and the programming algorithm clearly excludes their use. Further, the programming specification that is on our website is the very document that our internal software developer's use as well as all third parties. Traduction : « Si vous êtes en train de demander à Microchip la permission de violer les spécifications de programmation, je ne peux donner suite à votre requête. Nous retenons le droit d’utiliser l’adresse mémoire programme « réservée » pour notre propre usage, et aussi longtemps que nous le voulons, c’est pourquoi ces adresses ne sont pas disponibles pour une utilisation de stockage générale et que l’algorithme de programmation exclut clairement leur utilisation. Mieux, ces spécifications de programmation qui sont sur notre site sont les seules qu’utilisent nos développeurs internes, tout comme les développeurs des compagnies partenaires. » Autrement dit, Microchip® refuse catégoriquement de modifier son algorithme, prétendant que cette adresse lui est réservée.

Donc, cette société annonce en grandes pompes que ses PIC® permettent le debuggage en temps réel des programmes (il s’agit donc d’une information contractuelle, puisqu’incluse dans les datasheets officiels), mais en interdit de fait l’utilisation.

Si vous lisez les datasheets, on vous parle du bit _INDEBUG dans la configuration, on

vous parle de l’utilisation de RB6 et RB7 concernant les communications, mais on ne vous dit nulle part que l’utilisation de ce mode nécessite la programmation de l’adresse 0x2004.

18

L’utilisateur qui compare les datasheets de diverses marques, et qui se décide d’acheter un 16F87x suite à ces comparaisons, est donc convaincu de la possibilité d’utiliser le mode « in-debug ».

Cette information se trouve dans un autre datasheet, bien caché sur le site. Vous pensez

alors que tout va pour le mieux. Grossière erreur, un autre datasheet officiel, contenant les instructions destinées cette fois aux constructeurs de programmateurs précise explicitement qu’il est INTERDIT de programmer l’adresse 0x2004.

Autrement dit, l’utilisateur connaît l’existence de cette adresse, mais ne sait pas que les

programmateurs ne peuvent y accéder. Les constructeurs de programmateurs, eux, n’ont pas connaissance de l’utilité de cette adresse, ils suivent donc l’ordinogramme officiel qui précise explicitement qu’il faut sauter l’adresse 0x2004 lors de la programmation.

Pire, même une fois en possession de cette information (via l’utilisateur), ils se voient

signifier, par Microchip® l’interdiction de programmer cette adresse.

Ceci place donc l’utilisateur dans l’impossibilité d’utiliser une fonction pourtant annoncée comme une possibilité intrinsèque de ces circuits. J’estime donc qu’il y a tromperie et publicité mensongère. Je n’ai pas manqué de le faire savoir à Microchip®. Je n’ai donc pas manqué de me plaindre chez Microchip®, et leur demander s’ils étaient d’accord de me fournir un simple ordinogramme qui permettrait de programmer l’adresse en question. Il est en effet possible d’imaginer que tout ceci résulte d’une erreur, et non d’une volonté sournoise d’imposer leur debugger ICD®. La réponse que je vous ai traduite lève cependant tout ambiguïté à ce niveau. De plus, il est faux de prétendre que leurs programmeurs suivent exclusivement ces algorithmes, puisque leurs programmeurs ont réalisé ICD®, et que ICD® est bien forcé d’utiliser l’adresse 0x2004. J’ai alors décider de placer des pétitions sur différents forums, afin de faire savoir à Microchip® que son attitude était loin d’être élégante. Un participant a fini alors par recevoir le message suivant :

The PIC16F87X data sheet (DS30292) covers the operation of the device in the normal user mode. It does not describe how to use the device during programming nor when it is configured in the debugger mode. The programming specification (DS39025) describes how to program the device for operation in a normal user mode. It does not cover how to program the device for operation in the debugger mode. These documents were never intended to cover the operation of the debugger hardware on the PIC16F87X devices. In fact, the On-chip Debugger Specification (DS51242) was released significantly later in time after the data sheet and programming spec. The flow charts in the programming spec were designed only for programming the device, not debugger operation. The document DS51242 should be the repository for this type of information and I will make sure to forward your message to the appropriate individuals. To program address 2004, you simply need to increment the address until it reaches 2004 and issue the same type commands as used to program the config word. You can then increment the program counter to 2007 and program the config word.

19

Je vous traduis : « Le datasheet DS30292 du PIC16F87x concerne les opérations du composant dans son mode d’utilisation normal. Il ne décrit pas comment l’utiliser durant la programmation, ni en mode debugger. Le document DS39025 concernant la programmation, décrit comment programmer le composant dans son mode de fonctionnement normal. Il ne spécifie pas comment programmer le composant pour les opérations en mode debugger. Ces documents n’ont jamais été réalisés pour couvrir les opérations du debugger hardware du PIC16F87x. De fait, le datasheet concernant ce mode (DS51242) ont été réalisées significativement plus tard dans le temps que les 2 précédents documents. L’ordinogramme dans les spécifications de programmation a été construit seulement pour programmer le composant, pas pour les opérations de debuggage. Le document DS51242 devrait être repositionné pour ce type d’information et je m’assurerai de faire suive votre message vers les personnes concernées. » « Pour programmer l’adresse 2004, you avez simplement besoin d’incrémenter l’adresse jusqu’à ce qu’elle corresponde à l’adresse 2004, et exécuter la même commande que celle utilisée pour programmer le mot de configuration. Vous pouvez alors incrémenter le compteur de programme jusque 2007, et programmer le mot de configuration. » En d’autres termes, ils précisent que le document relatif au mode de debuggage a été écrit beaucoup plus tard que celui concernant la programmation, ce qui explique l’incohérence (en somme, ils tentent de se justifier). Ils expliquent également la procédure pour programmer cette fameuse adresse 2004. Notez que j’ai en ma possession un datasheet concernant le mode debugger daté de 2001, et que j’ai été cherché sur leur site le document relatif à la programmation daté de 2002, et donc postérieur. De plus, j’utilise un datasheet concernant les PIC® mid-range qui parle du mode debugger, mais qui date de 1999. Donc, Microchip® a eu tout le temps pour corriger. C’est de la mauvaise foi. Il va de soi que la procédure, nous la connaissions déjà, puisque Bonny Gijzen avait déjà modifié son programme en ce sens. Mais pour que cette information soit utile à tous, il fallait qu’elle devienne officielle. L’utilisateur en question a donc renvoyé un mail à Microchip® (qui, entre-temps, interrogeait les autres « pétitionneurs » pour savoir sur quels forums ils trouvaient ces informations), demandant une modification officielle de l’algorithme de programmation. Microchip® n’a plus jamais répondu à aucune requête concernant ce mode, malgré plus de 100 mails envoyés par les utilisateurs de plusieurs forums. Autrement dit, si vous avez un programmateur officiel, il vous faudra essayer de faire modifier le logiciel par son constructeur, pour avoir accès à l’adresse 0x2004, soit réaliser un petit programmateur piloté par IC-Prog. Je dispose d’un programmateur universel de plus de 1000 euros, et j’ai été contraint, suite au refus persistant de la société de construction, de me construire un petit programmateur supplémentaire : un comble.

20

3.4 Un mot sur le programme PC Il vous faut maintenant un programme sur PC qui permette de dialoguer avec le programme de debuggage placé dans votre PIC®. Pour l’application DTRA, BIGOPIC light fera très bien l’affaire, nous allons en reparler. Il ne vous restera « plus qu’à » inventer des procédures de communication pour entrer une adresse de « break » dans le PIC®, demander ou forcer l’état d’un registre, etc. Tout ceci reste du domaine du possible, mais nécessitera que vous acquériez beaucoup d’expérience au sujet des PIC®. Une alternative, bien plus pratique, serait d’utiliser le programme MPLAB®, qui intègre pareille gestion. Il suffit d’aller dans le menu « options->development mode », et de cocher la case « MPLAB ICD debugger ». ICD® signifie « In Circuit Debugger ». Le problème, c’est que je ne sais pas comment ce programme dialogue avec le PIC®, d’autant qu’une interface sert d’intermédiaire entre le PIC® et le PC. C’est donc pratiquement mission impossible à ce niveau, sans construire l’interface spécifique proposé par Microchip®.

A moins de faire du « reverse engineering » sur le soft de Microchip®, ce qui est interdit, et que je ne me risquerai pas de faire, surtout pour un ouvrage public. D’autant qu’après les tonnes de mails qu’à reçu Microchip® concernant le mode debugger, je suis probablement considéré comme l’ennemi public numéro 1. Il reste la possibilité que je vous réalise les dites routines, mais bon, vous croyez vraiment que c’est utile ?

Si vous pensez que oui, alors continuez la lecture de ce chapitre. 3.5 L’ ICD® de Microchip® Microchip® propose, pour environs 200 euros, une interface baptisée « ICD® », qui contient les éléments suivants : - L’interface ICD® à connecter sur le port série du PC, et à la platine du PIC®. - Une platine pour 16F876 et une pour 16F877 qui permet de placer le PIC®, d’insérer la

platine dans votre application, et qui dispose d’un connecteur pour relier la platine au module d’interface

- En option, une platine d’expérimentation complète pour 16F87x.

Cette interface ICD® est en même temps un programmateur ICSP® pour PIC® (In-Circuit Serial Programmer), c’est-à-dire un programmateur de PIC® qui permet de programmer celui-ci directement, sans enlever votre PIC® de la platine de debuggage. Pour rappel, la programmation utilise également les pins MCLR, RB6, et RB7, qui sont justement les pins mises en œuvre pour le debuggage.

21

Une fois en possession de ce module ICD®, vous placez votre PIC® sur sa platine d’interface, et la platine d’interface sur votre platine d’application. Vous connectez le tout au module ICD®.

A partir de ce moment, vous avez l’immense avantage, lorsque vous programmez votre PIC®, que MPLAB® envoie dans le PIC®, en même temps que votre programme, la sous-routine de debuggage complète pour communiquer avec MPLAB®, et, bien entendu, la programmation du saut correspondant à l’adresse 0x2004.

Tout devient donc totalement transparent pour vous, si ce n’est que vous devez laisser quelques adresses libres en RAM (utilisées par la sous-routine debug), et la partie haute de votre mémoire programme également (ce qui limite un petit peu la taille maximale des programmes possibles, mais bon, vous avez déjà écrit un programme qui remplit la totalité des 8K disponibles ?). Le fonctionnement de l’ICD® repose sur un software embarqué dans le PIC® présent sur L’ICD®, et du software chargé dans le PIC® de votre application. Ce dernier transfère de façon synchrone tous les registres vers le PIC® du module ICD® (donc en liaisons courtes). Celui-ci, à partir de ces informations brutes, effectue le dialogue avec MPLAB®.

Vous avez donc 2 couches de transmission, ce qui permet de diminuer la taille des routines embarquées dans la routine de debuggage J’ai été à 2 doigts (vraiment), de vous proposer la réalisation de cet interface. J’ai en effet tout à ma disposition pour le réaliser. Le prix de revient serait environ de la moitié, voire moins, du prix de l’interface fournie par MPLAB®. Au dernier moment, cependant, j’ai renoncé. Voici pourquoi :

A l’heure où j’écris ces lignes, la version ICD2® vient de sortir. Or, je ne possède pas le schéma de cette seconde version, ni le soft à placer dans le PIC® de l’interface pour le faire fonctionner.

De plus, il n’est actuellement compatible qu’avec les PIC18xxx dont je parlerai peut-être

dans un prochain ouvrage. Les PIC16Fxxx seront compatibles uniquement dans le courant de l’année.

Pour résumer la situation, complexe pour l’instant, voici ce qu’on peut dire à l’heure où

j’écris ces lignes : - ICD® est compatible avec MPLAB® V5.x et avec les PIC16F87x - ICD® n’est pas compatible avec le nouveau MPLAB® V6.x - ICD2® est compatible avec MPLAB V6.x mais n’est pas public

Si on part du principe que l’utilisateur qui décide de construire un interface ICD® est un

utilisateur motivé, qui, par définition, passera tôt ou tard à MPLAB V6.x, alors son interface ICD® sera bon pour la poubelle, et il n’aura aucune solution de remplacement.

Donc, le résultat ne prône pas, actuellement, en faveur de la construction personnelle de l’interface officielle.

22

Enfin, Microchip® tente d’imposer l’achat de son ICD® (2), excellente raison pour le court-circuiter sur son propre terrain (je n’aime pas ce qu’on tente de m’imposer). Ceci explique que je ne vous engage pas dans une voie sans issue. Néanmoins, si vous voulez absolument construire votre interface ICD® « officielle », vous trouverez les schémas sur le site de Microchip®. Vous verrez alors ce que signifie « information cachée », car j’ai trouvé l’information, essayez d’en faire de même par curiosité.

Quant au soft à placer dans le PIC® de l’interface, Microchip® affirme qu’il n’est pas public. Il se trouve cependant dans votre répertoire MPLAB®, décompacté automatiquement au moment de l’installation de MPLAB® . Il se nomme : « MPL876.HEX ». Mais bon, moi, je ne vous ai rien dit, pas vrai ? Encore une chose, n’oubliez pas que l’utilisation du mode debug nécessite la présence de ce mode dans le PIC® concerné. N’espérez donc pas debugger un 16F84 à l’aide de l’ICD®. 3.6 Le point Bon, je vois à tous votre tête d’ici. Vous vous répartissez actuellement probablement en plusieurs catégories : - Ceux qui ont déjà une interface ICD®, et qui donc ne sont pas concernés (pour l’instant). - Ceux qui ont une interface ICD2®, pour qui l’avenir est rose. - Ceux qui voudraient utiliser cet interface, et pour qui l’investissement (à répétition) ne

pose pas problème. - Enfin, ceux qui auraient bien voulu pouvoir utiliser cette fonction, et qui sont horriblement

déçus, car ils ne veulent pas investir pareil budget.

Pour ces derniers, qui doivent actuellement voir l’avenir en gris, je me suis dit : - Ils voudraient un debugger intégré - Et alors ? - Ils ne veulent pas le construire (assez complexe et cher) - Et alors ? - Ils ne veulent pas l’acheter (trop cher) - Et alors ? - Ils ne sont pas encore assez expérimentés pour tenter seuls l’aventure de la réalisation

personnelle - Et alors ? Et alors ? Et alors ?

Hé ! hé ! …. Zorro est arrivé, hé hé…

23

Oups, pardon, je me suis laissé emporté. Ben oui, rigoler de temps en temps permet de diminuer le stress et améliore la compréhension (ah bon, vous aviez déjà remarqué que je procède souvent de cette façon?). Bon, j’arrête là le suspens, je vais vous proposer deux solutions “clé en main” d’un debugger temps réel à mini-mini budget, et ultra-simple à réaliser. C’est pas beau, ça?

Je vous propose tout d’abord la première et la plus simple des 2 solutions. La suivante, beaucoup plus évoluée, sera proposée plus loin. Si vous voulez comprendre “comment ça marche”, je vous conseille de pratiquer dans l’ordre. On va réaliser tout ceci en 3 étapes : - La réalisation d’un programme de communication autonome simple. - La réalisation d’un debugger intégré qui dialogue en ASCII avec n’importe quel

programme de communication (DTRA) - La réalisation d’un super-debugger qui inclus solution PIC® et PC.

24

4. Logiciel PIC® de DTRA 4.1 Introduction Pourquoi DTRA? Tout simplement pour “Debugger en Temps Réel Ascii”. Pour paraphraser un ancien copain de forum, qui se reconnaitra j’en suis certain, je dirai que ce DTRA est l’ICD® pas cher, L’ICD® du pauvre. L’interface est celui étudié dans le précédent ouvrage consacré aux techniques de bootloader. Voici le cahier des charges que j’ai voulu appliquer : - Prix de revient très bas - Pas nécessaire de construire un circuit imprimé, une simple platine d’expérimentation

suffit - Composants très faciles à trouver. - Très simple d’utilisation - Ouverture complète, de façon à permettre la modification par l’utilisateur - Communication en asynchrone, permettant l’utilisation de distances convenables, et du

port COM du PC. - Communication uniquement en ascii, donc en “clair” permettant la création simple de

programmes PC personnels. Souvenez-vous que nous allons rencontrer des impératifs non compatibles, par exemple

l’impossibilité d’utiliser des sous-routines, et la nécessité d’économiser la place en mémoire programme.

Ceci pour vous expliquer qu’on sort ici de la programmation structurée classique, et qu’on

entre dans le domaine des astuces de programmation parfois un peu délicates à saisir. Pour les amateurs de “C” et de basic, essayez-donc de faire ces logiciels dans un langage évolué, par curiosité. 4.2 Le logiciel de communication Bon, comme expliqué plus haut, nous allons créer un programme “ordinaire” capable de réaliser toutes les fonctions utilises lorsque nous l’utiliserons comme debugger. Voici ce que je me suis imposé : - Possibilité d’interrompre à tout moment le programme principal - Possibilité de définir le prochain point d’arrêt

25

- Possibilité de lire n’importe quel registre (et de fait, variables programme) - Possibilité de modifier n’importe quel registre et variable - Possibilité de forcer le mode pas-à-pas - Possibilité de forcer le mode “FREEZE” (quoi que ne fonctionnant pas sur les PIC®

actuels) - Possibilité de retour au programme principal - Indication automatique des registres W,FSR, ainsi que de l’adresse d’interruption - Communications uniquement en ASCII, ce qui permet l’utilisation de n’importe quel

programme de communication.

Avec ça, je pense qu’il est déjà possible de debugger pratiquement l’intégralité des programmes. La contrainte principale demeure l’interdiction d’utiliser des sous-routines. Mais vous allez voir que j’ai plus d’une corde à mon arc… et que j’ai toujours autant d’imagination. Commencez donc par copier/coller votre fichier maquette, et renommez-le en “dtra.asm”. A partir de maintenant, si vous débutez, vous allez devoir vous investir à fond. Editons l’en-tête : ;***************************************************************************** ; SOUS-ROUTINE DE DEBUGGAGE POUR PIC 16F87X. * ; PERMET LE DIALOGUE AVEC LE PROGRAMME * ; Merci à Bonny Gijzen pour la modification de IC-Prog * ; * ;***************************************************************************** ; * ; NOM: DTRA * ; Date: 15/08/2002 * ; Version: 1.0 * ; Circuit: Interface BIGOPIC2 * ; Auteur: Bigonoff * ; http://wwwabcelectronique.com/bigonoff * ; Tous droits réservés, propriété intellectuelle de l'auteur * ; * ; Le présent logiciel ne peut être distribué sans le livre et * ; les fichiers auxquels il fait référence, à savoir : * ; "La programmation des PICS par Bigonoff - quatrieme partie - * ; In circuit debugger". Vous ne pouvez utiliser ce programme * ; qu'après avoir pris connaissance de cet ouvrage, et d'en avoir* ; accepté toutes les clauses et avertissements. * ; * ; Toute utilisation sur des circuits présentant des tensions * ; à risque létal ne pourra se faire qu'en respectant les * ; législations en vigeur. L'utilisateur à l'obligagion de se * ; renseigner et se conformer à ces législations. * ; * ; L'intégralité des fichiers est disponible uniquement sur le *

26

; site de Bigonoff. http://www.abcelectronique.com/bigonoff * ; Les webmasters sont autorisés à placer un lien sur leur site. * ; * ; Les droits relatifs à l'utilisation à des fins privées de * ; ce programme sont soumis aux mêmes conditions que celles * ; décrites dans l'ouvrage sus-mentionné. * ; * ; Toute utilisation commerciale est interdite sans l'accord * ; écrit de l'auteur. La modification de ce source n'est * ; autorisée qu'à des fins privées, toute distribution du code * ; modifié est interdite. * ; * ; L'auteur décline toute responsabilité quant aux conséquences * ; éventuelles résultant de l'utilisation de ce programme * ; et interfaces associées. * ;***************************************************************************** ; Fichier requis: P16F876.inc * ; * ;***************************************************************************** ; * ; Fichier à inclure dans le programme à debugger * ; Commandes acceptées : * ; "R" + 3 digits de l'emplacement (read) * ; "G" : retour au programme principal * ; "S" : inversion du mode STEP * ; "F" : inversion du mode freeze * ; "B" + 4 digits : Valeur du prochain break point (2*8 bits) * ; "M" + 3 digits de l'emplacement + "," +2 digits pour valeur * ; * ; Valeurs envoyées * ; 2 octets en réponse à la commande "R" (8 bits) * ; Les valeurs sont renvoyées en ascii, donc une valeur = 2 octets * ; * ;***************************************************************************** ; PARAMETRES * ; * ; FQUARTZ : fréquence du quartz en Hz * ; BAUDR : Debit en bauds * ; BAUDRL : correctif de débit * ; CBDS_HIGH : variables en 0x160/0x16F au lieu de 0x110/0x11F * ; DBGADD : adresse de départ bootloader (en banque 3) * ; * ;***************************************************************************** LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

Vous voyez que j’ai défini les commandes qui seront utilisées par le debugger. Ces commandes seront simplement tapées au niveau du programme de communication, terminées par l’appui sur la touche « return ». Le logiciel répondra suivant l’ordre requis.

J’expliquerai les commandes « au fur et à mesure » (avec les paroles, mais sans la musique, désolé). Maintenant, il faut se souvenir que nous travaillons en asynchrone, c’est-à-dire que nous devons établir une vitesse de communication. Cette vitesse, que nous devons définir, dépendra

27

également de la vitesse de travail du PIC® (donc de son quartz). En effet, à routines égales, plus on accélère le PIC®, plus vite se fera la transmission. Comme il n’est pas question de vous obliger à modifier les routines de debuggage une fois qu’elles seront opérationnelles, je prendrai tout en charge via des calculs et des macros internes. Les seules choses que nous aurons besoin de connaître, sont la fréquence de travail du PIC® et la vitesse de transmission souhaitée. Pour ceci, nous utiliserons 5 assignations dans le programme principal. Voici ces 5 assignations, que nous plaçons donc provisoirement dans notre programme de communication : ;FQUARTZ EQU D'20000000' ; fréquence quartz ;BAUDR EQU D'19200' ; débit en bauds ;BAUDRL EQU D'0' ; Permet de diminuer le taux d'erreur

; Augmente la taille du programme ; conserver la plus faible valeur ; possible. Ne pas dépasser D'5' ;CBDS_HIGH EQU 1 ; utilisation de la zone 0x160/0x16F DBGADD EQU 0x00 ; adresse du bootloader Je vous renvoie à la troisième partie du cours (techniques de bootloader) pour les explications détaillées des trois premières constantes. Tout y est expliqué en détails. La quatrième précise l’emplacement des variables RAM (j’y reviendrai), et la dernière l’adresse de chargement de la routine bootloader, L’adresse de la routine est pour l’instant 0x00, puisque nous la développons en tant que programme principal. Nous allons ajouter un message qui rappelle à l’utilisateur de couper le watchdog durant le debuggage : MESSG "DEBUGGER EN SERVICE, veuillez couper le watchdog" Si vous voulez utiliser le watchdog durant le debuggage, il ne vous reste qu’à inclure l’instruction « clrwdt » dans la routine de debuggage partout où c’est nécessaire, à vous alors de modifier les routines de temporisation et les calculs en conséquence.

Pour ma part, je conseille de toujours debugger sans utiliser le watchdog, qui risque de camoufler par récupération certaines erreurs du programme. Mais vous êtes libres de faire comme vous l’entendez. Partant du principe que les valeurs de 20Mhz et 19200 bauds seront utilisées dans la majeure partie des cas, nous allons déterminer ces valeurs comme étant celles par défaut. Pour ceci, nous allons utiliser la directive « IFNDEF », qui signifie « IF NO DEFINE ». Autrement dit, ce qui suit cette directive, et jusqu’au « ENDIF » sera exécuté si la constante citée en paramètre n’a pas été définie. Autrement dit, si vous omettez de préciser ces paramètres, le debugger travaillera avec ses valeurs par défaut, et un message vous avertira des paramètres au moment de l’assemblage de votre programme. IFNDEF DBGADD ; si adresse pas définie

28

DBGADD = 0x1B90 ; adresse par défaut MESSG "Adresse de debugger par défaut : 0x1B90" ; et message ENDIF IFNDEF FQUARTZ ; si fréquence non précisée FQUARTZ = D'20000000' ; alors fréquence = 20MHz MESSG "Fréquence de 20 Mhz prise par défaut" ; et message endif IFNDEF BAUDR ; si débit non précisé BAUDR = D'19200' ; alors débit = 19200 bauds MESSG "Débit de 19200 bauds pris par défaut" ; et message endif IFNDEF BAUDRL ; si BAUDRL non précisé BAUDRL = 0 ; BAUDRL = 0. Message possible endif ; en cas d'erreur importante Ensuite, nous définissons les pins d’entrée et de sortie. Comme je l’ai expliqué, il n’est pas question de les modifier. ;***************************************************************************** ; ASSIGNATIONS * ;***************************************************************************** #DEFINE TXPIN PORTB,7 ; pin pour l'émission (ne pas modifier) #DEFINE RXPIN PORTB,6 ; pin pour la réception (ne pas modifier)

Je vous explique tout ceci en détail de façon à vous permettre de créer votre propre programme de debuggage si vous en ressentez le besoin. Vous savez que je ne laisse rien dans l’ombre, j’explique le maximum de choses. Mon but n’est pas en effet de me faire « mousser », mais de vous expliquer qu’il n’y a rien de magique, et, qu’une fois compris, les mécanismes sont simples et utilisables par tous. Tant que nous y sommes, nous allons déjà placer notre « goto » qui se trouvera à l’adresse 0x2004 de notre PIC®. Nous n’en avons pas besoin pour notre programme principal (qui lui, n’utilise pas le DEBUG, puisqu’il l’est lui-même). ORG 0x2004 ; vecteur du debuggage goto DBGADD ; sauter sur la sous-routine En procédant de la sorte, la simple modification de l’assignation DBGADD (DeBuG ADDress) modifie à la fois l’adresse d’assemblage (nous le verrons plus loin), et l’adresse du saut à l’adresse 0x2004. Je vais maintenant calculer le nombre de boucles qui seront nécessaires au niveau de mes temporisations pour établir un temps d’attente de la durée d’un bit (n’oublions pas que nous gérons la liaison bit par bit, sans timer, sans sous-routine, et sans hardware spécifique). ; Calcul de la constante de temporisation ; --------------------------------------- CBDS_1B EQU (((FQUARTZ/4)/BAUDR)-D'9')/(3+BAUDRL) CBDS_1B5 EQU (((FQUARTZ*3/8)/BAUDR)-D'9')/(3+BAUDRL)

29

De nouveau, ces calculs ont été expliqués dans l’ouvrage précédent. Seules changent les valeurs « D9 ». Je donne simplement un petit rappel :

Le temps d’une instruction vaut le quart d’un temps d’oscillation (Tosc), donc la vitesse d’exécution des instructions vaut le quart de la vitesse du quartz, d’où le « FQUARTZ / 4 »

Le nombre d’instructions que dure un bit est égal à la vitesse d’exécution des instructions

divisée par le débit souhaité. Par exemple, si vous travaillez à 20.000.000 Hz (20Mhz) et que vous avez besoin d’un débit de 19200 bauds (bits par seconde), chaque bit durera : ((20.000.000 /4) instructions/s) / (19200 bits/s) = 260 instructions par bit. Maintenant, nous ne devons pas attendre 260 instructions à chaque entrée dans la boucle, mais 260 instructions entre chaque bit. Or, entre 2 passages dans la boucle, un certain nombre d’instructions seront exécutées pour préparer le bit, l’envoyer, paramètrer la boucle de temporisation etc. De la façon dont nous allons créé nos routines, 10 cycles seront utilisés entre deux entrées consécutives dans la boucle de temporisation. Il faut donc soustraire ces 10 cycles de la durée à attendre dans la routine de temporisation. La routine de temporisation en elle-même sera de la forme : Wait defsz cmpt ; décrémenter compteur nop ; autant de « nop » que l’indique BAURDL (de 0 à 0xD) goto Wait ; pas 0, suivant Une telle boucle prend (3 cycles + BAUDRL) tant que cmpt est supérieur à 0. Une fois à 0, la boucle ne prend que (2 cycles + BAUDRL) (decfsz = 2 cycles, goto non exécuté).

Donc, on doit donc diviser le nombre total d’instructions à attendre par (3 + BAUDRL), après avoir décompté le cycle qui ne sera pas pris en compte lors de la dernière boucle.

Ceci correspond à considérer qu’on n’a pas perdu 10 cycles entre 2 passages, mais 9,

puisqu’on en gagne 1 lors de la dernière boucle. Nous aurons également besoin d’une durée de 1.5 bits, mais nous ne pouvons pas multiplier la durée calculée par 1.5, car les 9 cycles perdus sont, eux, constants. Nous effectuons donc un second calcul sur base d’un temps de cycle à attendre multiplié par 3/2, ce qui revient à multiplier (FQUARTZ/4) par 3/2. Bon, ce n’est pas tout, encore faut-il s’assurer que la valeur maximale obtenue tiendra dans une variable de 8 bits. Nous ajouterons donc deux directives : IF CBDS_1B5 < 0 MESSG "Impossible d'établir le débit, diminuez BAUDRL" MESSG "Si déjà à 0, diminuez le débit" ENDIF If CBDS_1B5 > 0x100 MESSG "Augmentez le baudrate, modifiez la routine de temporisation" MESSG "ou augmentez la valeur de BAUDRL" Endif

30

La première enverra un message dans la fenêtre des résultats si la valeur obtenue est

inférieure à 0, autrement dit, si on n’a pas le temps de tout faire entre la réception de 2 bits.

La seconde procède de l’inverse. On s’assure qu’un temps d’attente correspondant à 1,5 bits (3/2) nécessitera un nombre de boucles inférieur ou égal à 256. Dans le cas contraire, soit vous augmenterez la vitesse de transmission , soit vous augmentez BAUDRL, ce qui revient à allonger les boucles de temporisation. Attention, n’exagérez pas dans les valeurs, car cela allonge la longueur du programme. La limite à ne pas dépasser est D’10’. Et de plus, nous devons nous assurer que l’erreur obtenue sera inférieure à, disons 4%. Si on se souvient que l’erreur est donnée par la formule |Débit réel – Débit théorique| / débit théorique (avec | | = valeur absolue), on aura : ; calcul du débit réel et de l'erreur obtenus ; ------------------------------------------- CBDS_BR EQU FQUARTZ/((((3+BAUDRL)*CBDS_1B)+9)*4) CBDS_ERR EQU (BAUDR-CBDS_BR)*100/BAUDR On obtient alors l’erreur en %, mais avec son signe. Il suffit donc de détecter si l’erreur est >4 ou <-4 pour envoyer un message d’avertissement (le symbole « | » signifie « OR »): IF (CBDS_ERR>4 | CBDS_ERR <-4) MESSG "Erreur de baudrate trop importante" MESSG "Essayez de modifier la valeur de BAURL" ENDIF

Notez qu’un débit de 19200 bauds pour une fréquence de 20Mhz ne pose aucun problème. A 10Mhz, utilisez 9600 bauds, et en dessous, les vérifications ci-dessus vous avertirons si la vitesse désirée est compatible ou non avec le débit choisi. Vous disposez de suffisamment de possibilités pour éviter tout problème. Il vous est même possible de doubler ces vitesses. J’ai également décidé de vous proposer 2 emplacements pour les variables du debugger. - Soit, par défaut, dans la zone 0x110 à 0x11F (donc dans la zone banque 2 dénommée :

GENERAL PURPOSE REGISTER), - Soit dans la zone 0x160 à 0x16F, autrement dit, tout en fin de la zone en banque2. Je vais de nouveau, pour ceci, définir une constante en fonction de votre choix, avec, par défaut, le choix de la zone 0x110/0x11F. Si vous désirez placer les variables dans la zone 0x160/0x16F, vous devrez préciser la ligne suivante dans votre programme : CBDS_HIGH EQU 1 ; utilisation de la zone 0x160/0x16F Vous serez averti par un message de la zone utilisée (et donc réservée). ; sélectionner emplacement des variables ; --------------------------------------

31

IFNDEF CBDS_HIGH CBDS_HIGH EQU 0 ; valeur par défaut ENDIF IF CBDS_HIGH CBDS_OFF EQU 0x50 ; variables 0x50 emplacements plus loin MESSG "zones RAM 0x160/0x16F + 0x7E/0x7F réservées" ELSE CBDS_OFF EQU 0x00 ; offset des emplacements variables MESSG "zones RAM 0x110/0x11F + 0x7E/0x7F réservées" ENDIF Passons maintenant aux macros. C’est ici que nous allons avoir du boulot. Commençons par le commencement : ;***************************************************************************** ; MACROS * ;***************************************************************************** SUBRS macro adresse ; pseudo sous-routine simple LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour goto adresse ; sauter ICI ; adresse de retour Endm Je vous ai déjà informé qu’on ne pouvait pas utiliser de sous-routines dans notre routine de debuggage. Cependant, si on s’en tient là, on va très vite se retrouver confronté à un programme d’une taille monstrueuse. En effet, chaque réception ou chaque émission d’un bit va nécessiter l’utilisation d’une macro de réception et d’émission.

Or, ces macros seront assez longues, étant donné qu’on doit traiter bit par bit, avec inclusion d’une durée de temporisation. De ce fait, il m’apparaissait indispensable de disposer d’un mécanisme équivalent à une sous-routine. Ma réflexion a donc été la suivante : qu’est-ce donc qu’un appel à une sous-routine ?

L’expliquer permet déjà de trouver la solution : il s’agit d’un saut à une portion de code qui se termine en renvoyant le programme à l’adresse qui suit l’appel. Vu comme ça, et à condition de se limiter à un seul niveau de sous-routine (car on n’a pas accès à la pile), la solution apparaît subitement (mais si, mais si). J’ai nommé la sous-routine ainsi créée « pseudo sous-routine ». Voyons le principe… Il faut tout d’abord vous souvenir de la façon dont travaille PCLATH. Pour le cas d’un saut, l’adresse du saut, codée sur 11 bits, est complétée par les bits 3 et 4 de PCLATH. Or, notre routine de debuggage tient en intégralité dans la même page (la dernière). Autrement dit, les bits 3 et 4 resteront identiques au niveau de la pseudo sous-routine et de l’emplacement de l’appel.

32

Par contre, lorsqu’on manipule directement PCL, qui ne comporte que 8 bits, l’adresse effective de saut sera PCL complété par les bits 0 à 4 de PCL. Nous allons donc devoir gérer les bits 0 à 2. Analysons la macro en détail, je l’ai appelée SUBRS pour SUB Routine Simple. Simple parce qu’un seul niveau, pas vraiment parce que c’est simple à comprendre. LOCAL ICI Définit une adresse locale « ICI ». La directive « LOCAL » est nécessaire, car chaque utilisation de la macro va définir sa propre adresse « ICI ». Autrement dit, sans la directive, vous auriez plusieurs étiquettes « ICI » situées à des emplacements différents, ce dont MPASM® ne va pas manquer de se plaindre, à juste titre d’ailleurs. movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH Nous prenons la partie haute de l’adresse « ICI », qui est l’adresse de retour de la pseudo sous-routine et nous la plaçons dans PCLATH. Ceci n’influencera que les opérations sur PCL, et non les opérations de type « goto », puisque les bits 3 et 4 sont identiques tout au long de notre routine de debuggage (je vous avais averti que ce n’était pas vraiment simple). movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour Dans cette partie, nous mémorisons les 8 bits de poids faible de l’adresse de retour dans une variable, en nous souvenant que les 5 autres bits ont déjà été mémorisés dans PCLATH. L’adresse de retour est donc complète. goto adresse ; sauter Avec cette instruction, nous sautons à l’adresse effective « adresse » codée sur 11 bits, complétée par les bits 3 et 4 de PCLATH. Ces bits sont ceux de l’adresse de retour, mais comme pseudo sous-routine et appel sont dans la même page, ils seront identiques. Nous sautons donc effectivement à l’adresse de notre pseudo sous-routine. ICI ; adresse de retour endm Avec cette étiquette, tout simplement, nous indiquons quel sera le point de retour de notre pseudo sous-routine. Ce point de retour devra être l’instruction qui suit la macro d’appel, ce qui justifie l’emplacement de notre étiquette « ICI ». Bien entendu, il nous faut maintenant le mécanisme de retour correspondant à notre mécanisme d’appel, un simple « return » ne fonctionnera bien évidemment pas. Voyons comment procéder : RET macro ; retour de pseudo sous-routine movf cbds_pcl,w ; adresse de retour movwf PCL ; dans PCL endm

33

Cette macro récupère les 8 bits de retour sauvegardés dans la variable, et les place dans PCL. On génère de la sorte un saut à l’adresse donnée par PCL (8 bits), complété par les bits 0 à 4 de PCLATH. Comme PCLATH a été initialisé lors de l’appel et n’a pas été modifié par notre programme, le retour s’effectuera au bon endroit. Par cette méthode, nous avons créé un appel de pseudo sous-routine, sans utiliser la pile du PIC®, et sans mettre en œuvre les mécanismes classiques de sous-routines. Pour appeler une pseudo sous-routine « subrout », il nous suffira donc d’écrire : SUBRS subrout ; appel de pseudo sous-routine Cette pseudo sous-routine se terminera par : RET ; retour de pseudo sous-routine Vous voyez que c’est un peu compliqué à expliquer, mais que c’est par contre très simple à utiliser. Maintenant, appeler une sous-routine, c’est très bien, mais encore faut-il pouvoir passer un paramètre. Imaginons par exemple l’appel de sous-routine classique suivant : movf mavariable,w ; charger mavariable dans W call subrout ; appeler sous-routine avec [mavariable] dans W. Si vous utilisez la procédure suivante : movf mavariable,w ; charger mavariable dans W SUBRS subrout ; appeler pseudo sous-routine avec [mavariable] dans W. Ca ne fonctionnera jamais. Pourquoi ? Et bien tout simplement parce que la macro SUBRS modifie le contenu de W. Le paramètre est donc perdu. Il faut donc créer une autre macro qui permette de charger la variable avant d’effectuer le saut. Rien de plus simple, il suffira d’ajouter une ligne, et de passer le paramètre à la macro. J’ai appelé cette macro SUBRV pour SUB Routine avec Variable. SUBRV macro adresse,vari ; pseudo sous-routine avec variable LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour movf vari,w ; charger variable dans w goto adresse ; sauter ICI ; adresse de retour endm Vous voyez qu’on passe l’adresse de la variable à la macro, celle-ci se chargera de charger la variable juste avant le saut. De même, si on désire passer une constante, on utilisera SUBRC (inutile, je pense, de vous expliquer le pourquoi du nom) : SUBRC macro adresse,cst ; pseudo sous-routine avec constante

34

LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour movlw cst ; charger constante dans w goto adresse ; sauter ICI ; adresse de retour endm Voici déjà notre mécanisme de pseudo sous-routine au point. Nous allons ensuite créer une macro qui appelle une pseudo sous-routine de réception d’un octet, et qui place l’octet récupéré dans la variable passée en paramètre. cbdsR macro save ; lit un octet, le sauve dans save LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour goto cbds_rec ; lire un octet ICI ; adresse de retour movf cbds_byte,w ; charge octet reçu movwf save ; le sauve dans save endm Notez qu’ici, la sauvegarde de la valeur récupérée s’effectue après le retour de la sous-routine (on sauve le résultat), et donc se situe après l’étiquette « ICI ». cbds_byte est la variable dans laquelle se trouve le résultat de la lecture, et « save » l’emplacement où le résultat sera définitivement sauvegardé. cbds_rec est la pseudo sous-routine de lecture d’un octet. Notez que toutes les étiquettes, adresses, variables etc., contiennent « cbds ». Ceci vous assure qu’une étiquette utilisée dans la routine de debuggage ne fera pas double emploi avec celles utilisées dans votre programme à debugger (ou alors vous le faites exprès). Nous avons vu que nous communiquons en ASCII. Autrement dit, en utilisant des caractères qu’on peut imprimer et écrire. Si on prend un nombre hexadécimal de 8 bits, par exemple « 85 », vous voyez que pour l’écrire, il m’a fallut 2 digits : « 8 » et « 5 ». Pour écrire « 85 » sur un programme d’affichage, nous devrons envoyer le code ASCII de « 8 », puis le code ASCII de « 5 ». Chaque digit étant codé sur 1 octet, l’écriture d’un octet hexadécimal va nécessiter l’envoi de 2 octets ASCII. La macro suivante appelle les différentes pseudo sous-routines concernées. C’est donc une macro qui intègre des macros. cbdsA2 macro ; 2 bytes pour un nombre d'1 chiffre movwf cbds_byte ; valeur à convertir SUBRS cbds_ascii ; convertir en 2 octets SUBRV cbds_send,cbds_byte ; envoyer SUBRV cbds_send,cbds_byteL ; envoyer endm

35

Vous constatez que cbds_byte est une pseudo sous-routine qui convertit un octet hexadécimal en 2 octets ASCII. Les 2 octets ASCII (digits) se retrouvent dans cbds_byte et cbds_byteL, et seront envoyés vers le PC grâce aux pseudo sous-routines cbds_send, en précisant l’adresse du paramètre. Vous voyez que ça se complique un peu, mais ça reste simple d’utilisation. Il suffit en effet d’écrire « cbdsA2 » pour convertir un octet hexadécimal et envoyer le résultat sous forme de 2 digits vers le PC. Maintenant, nous allons trouver notre macro de temporisation : cbdsT macro cbds_dur ; délai d'après la durée LOCAL ICI VARIABLE i movlw cbds_dur ; charger durée movwf cbds_tempo ; dans compteur de boucles i = 0 ; compteur de boucles ICI WHILE i < BAUDRL ; tant que i < BAUDRL nop ; ajouter nop i+=1 ; incrémenter i ENDW

decfsz cbds_tempo,f ; décrémenter compteur goto ICI ; pas 0, recommencer endm Et oui, on joue encore allègrement des directives. La directive « WHILE » crée une boucle qui exécute tout ce qui suit, jusque la directive « ENDW » TANT QUE la condition donnée en argument n’est pas remplie. On peut donc traduire cette boucle par : TANT QUE i est inférieur à la constante BAUDRL (qui définit le nombre de « nop »)

Ajouter l’instruction « nop » à la macro Incrémenter i BOUCLER Il va de soi que les directives WHILE, ENDW, i+=1, sont utilisées en interne par MPASM® (DIRECTIVES), et donc ne seront pas traduites en instructions. Les lignes surlignées en bleu seront donc les seules à faire partie du programme assemblé. A titre d’exemple, si vous avez déclaré que BAUDRL valait « 0 », vous obtiendrez dans votre programme :

movlw cbds_dur ; charger durée movwf cbds_tempo ; dans compteur de boucles

ICI decfsz cbds_tempo,f ; décrémenter compteur goto ICI ; pas 0, recommencer Si, par contre, BAUDRL vaut « 3 », vous obtiendrez :

movlw cbds_dur ; charger durée movwf cbds_tempo ; dans compteur de boucles

ICI nop nop nop

36

decfsz cbds_tempo,f ; décrémenter compteur goto ICI ; pas 0, recommencer Concernant le fonctionnement, on charge simplement la durée passée en paramètre dans un compteur, et on décrémente ce compteur. La boucle en elle-même prend 3 cycles incrémentés du nombre de « nop », donc de la valeur de BAUDRL.

L’exception est pour la dernière boucle, qui nécessite un cycle de moins, du fait qu’on saute l’instruction « goto », donc un cycle de plus pour le saut de « decfsz », et 2 de moins pour l’absence d’exécution du « goto ». Il faut de plus 2 cycles pour initialiser la boucle.

Nous avons pris en compte dans nos calculs de temporisation que la routine de temporisation durait « nombre de boucles * (3 + BAUDRL) ». Or, ce n’est pas tout à fait exact, il nous faudra donc corriger.

Tout d’abord, les 2 premières lignes qui initialisent le compteur de boucles, nous

consomment 2 cycles « non prévus ». C’est donc un retard supplémentaire qu’il nous faudra soustraire de la durée à perdre dans la boucle.

Mais, la boucle en elle-même ne répond pas tout à fait à la formule, puisque le dernier

passage dans cette boucle prendra un cycle de moins que prévu. Autrement dit, on perd 2 cycles, et on en gagne 1. Au final, 1 cycle de plus que désiré sera consommé par notre routine de temporisation. Le savoir permet d’en tenir compte.

L’utilisation de cette macro se fera en précisant le nombre de boucles à attendre. Par

exemple : cbdsT CBDS_1B ; attente pour 1 bit cbdsT CBDS_1B5 ; attente pour 1 bit et demi Il ne nous reste plus qu’une macro à étudier. En fait, c’est une macro particulière, puisqu’elle sera utilisée dans 3 pseudo sous-routines. Il s’agit en fait d’une macro qui est un morceau de pseudo sous-routine. Elle est longue, mais ne sera pas utilisée en grand nombre d’exemplaires. RECEIVE macro ; réception d'un octet LOCAL REC1 ; étiquette locale btfsc RXPIN ; pin réception = 0? goto $-1 ; non, attendre cbdsT CBDS_1B5 ; attendre 1,5 bit clrf cbds_byte ; effacer octet reçu movlw 0x08 ; pour 8 bits movwf cbds_cmptb ; dans compteur de bits REC1 bcf STATUS,C ; par défaut, bit = 0 btfsc RXPIN ; bit reçu = 1? bsf STATUS,C ; oui, positionner carry nop ; pour correction du temps rrf cbds_byte,f ; faire entrer bit reçu cbdsT CBDS_1B ; attendre 1 bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto REC1 ; pas dernier, suivant endm

37

Que fait cette portion de code ? - Elle attend l’apparition du début du start-bit, qui est donc le positionnement à « 0 » de la

pin d’entrée (RB6 ou RXPIN). - Elle attend une durée correspondant à 1,5 bits. On se retrouve donc au milieu du premier

bit reçu (1 bit = start-bit + ½ bit). - Ensuite, on lit chaque bit, à l’intervalle d’une durée de 1 bit

Le «nop » est la pour que la durée séparant 2 lectures de bit soit la même que pour leur envoi.

Comme la routine d’envoi comportait un cycle de plus, j’ai ajouté un « nop » dans cette

macro-ci. Si vous vous positionnez sur la ligne en gris (la macro de temporisation), vous allez

compter les cycles « perdus » entre 2 exécutions de cette macro. decfsz cbds_cmptb,f ; décrémenter compteur de bits Donc, 1 cycle, puisqu’on ne saute que lorsque c’est terminé, et donc lorsque la macro de temporisation ne sera plus exécutée.

goto REC1 ; pas dernier, suivant Soit 2 cycles, comme pour tous les sauts. bcf STATUS,C ; par défaut, bit = 0 soit 1 cycle btfsc RXPIN ; bit reçu = 1? bsf STATUS,C ; oui, positionner carry Toujours 2 cycles, car soit on ne saute pas et on exécute 2 instructions à un cycle, soit on saute et on exécute un saut de 2 cycles. nop ; pour correction du temps rrf cbds_byte,f ; faire entrer bit reçu Encore 2 cycles Et on arrive à notre macro, laquelle « perd » encore 1 cycle supplémentaire en plus du temps effectivement perdu dans la boucle, comme expliqué plus haut Le total est donc de 1 + 2 + 1 + 2 + 2 + 1 = 9. Soit 9 cycles qu’il ne nous faudra pas perdre dans notre boucle de temporisation.

38

Voici donc l’origine de nos « -9 » dans le calcul de nos CBDS_1B et CBDS_1B5. Maintenant, vous devriez bien comprendre. Vous comprenez surtout que faire ce genre de gymnastique n’est pas toujours aisé. Notez que ceci a peu de chance de « tomber juste », du fait de la division, mais l’erreur a été calculée par nos directives de début de programme. Si vous ne recevez pas de message d’avertissement, vous ne devriez pas rencontrer de problème. Dans le cas contraire, vous pouvez modifier BAUDR et/ou BAUDRL pour obtenir un fonctionnement sans problème. Bon, nous en avons terminé avec nos macros. Tout va maintenant devenir plus simple. Nous allons avoir besoin de variables en RAM. Bien évidemment, vous ne pourrez plus utiliser ces variables dans votre programme à debugger. J’ai donc limité ces variables au maximum. Nous en avons 2 dans la zone de variable commune, qui est précieuse et que j’ai donc économisée. En effet, lors de l’étude du bootloader, nous avions vu que les emplacements RAM ne posaient pas problème, puisque le bootloader ne servait que lorsque le programme principal ne tournait pas. Il en va tout autrement ici, puisqu’il ne s’agirait pas que le debugger modifie des variables qui sont utilisées par le programme interrompu. Il m’était cependant impossible de m’en passer, car il faut bien sauvegarder les registres W et STATUS avant de modifier les banques, et donc sauvegarder en banque commune. Vous verrez qu’en fait, lors de la version améliorée du debugger (CBDS), on peut encore faire mieux. Mais à chaque jour suffit sa peine, et à chaque chapitre son tube d’aspirines. ;***************************************************************************** ; VARIABLES ZONE COMMUNE * ;***************************************************************************** w_CBDS EQU 0x7F ; Sauvegarde registre W status_CBDS EQU 0x7E ; sauvegarde registre STATUS J’ai placé volontairement ces variables en dernière position, car, en général, vous commencerez par utiliser les adresses à partir de la plus faible dans votre programme à debugger (ce sera d’ailleurs automatique si vous utilisez les directives CBLOCK comme je vous l’ai toujours conseillé. Donc, souvenez-vous que si vous debuggez un programme, vous ne disposez plus que de 14 emplacements en mémoire commune au lieu de 16.

Restent d’autres variables, pour lesquelles je vous ai laissé le choix entre 2 positions (0x110 à 0x11F par défaut, ou 0x160 à 0x16F si vous précisez « CBDS_HIGH EQU 1 ». Ces 2 zones se situent en banque 2.

Ce choix s’explique parce que nous allons travailler principalement en banque 2 (du fait de l’utilisation constante du second registre PORTB à l’adresse 0x106, et donc en banque 2). ;***************************************************************************** ; VARIABLES BANQUE 2 * ;***************************************************************************** PCLATH_CBDS EQU 0x110 + CBDS_OFF ; sauvegarde PCLATH FSR_CBDS EQU 0x111 + CBDS_OFF ; sauvegarde FSR

39

INTCON_CBDS EQU 0x112 + CBDS_OFF ; sauvegarde INTCON PIR1_CBDS EQU 0x113 + CBDS_OFF ; sauvegarde PIR1 PIR2_CBDS EQU 0x114 + CBDS_OFF ; sauvegarde PIR2 cbds_tempo EQU 0x115 + CBDS_OFF ; compteur pour temporisation cbds_byte EQU 0x116 + CBDS_OFF ; byte reçu ou envoyé cbds_cmptb EQU 0x117 + CBDS_OFF ; compteur de bits cbds_byteL EQU 0x118 + CBDS_OFF ; second octet pour conversion hex/ascii cbds_car1 EQU 0x119 + CBDS_OFF ; message reçu ou à envoyer cbds_car2 EQU 0x11A + CBDS_OFF cbds_car3 EQU 0x11B + CBDS_OFF cbds_car4 EQU 0x11C + CBDS_OFF cbds_car5 EQU 0x118 + CBDS_OFF ; même adresse que byteL cbds_pcl EQU 0x11D + CBDS_OFF ; adresse de retour cbds_break2 EQU 0x11E + CBDS_OFF ; adresse du prochain break LSB cbds_break EQU 0x11F + CBDS_OFF ; adresse du prochain break MSB Comme 2 variables ont la même adresse (variables locales), nous utiliserons donc 16 emplacements dans la zone RAM banque 2. De même, ces emplacements ne pourront pas être utilisés par votre programme principal. Dans l’immense majorité des cas, ce ne sera pas un problème. Remarquez que j’ai sauvegardé FSR et PCLATH dans cette banque, en économisant la banque commune. En effet, une fois STATUS sauvegardé, il était possible de changer de banque pour ces sauvegardes. Il vaut mieux sacrifier un emplacement en banque 2 qu’en zone commune. Excepté pour ces 2 dernières variables, la modification de l’emplacement des autres variables peut nécessiter l’ajout de changements de banques, donc la modification des durées de temporisation. Ce n’est donc pas une opération simple, mais c’est parfaitement possible, étant donné que je vous donne tous les renseignements sur la construction de ce programme. Nous entrons maintenant dans notre routine de debuggage. Tout comme pour une routine d’interruption, il nous faut commencer par sauvegarder nos registres, afin de pouvoir retourner à notre programme principal sans que celui-ci s’aperçoive de l’interruption. ;***************************************************************************** ; SAUVEGARDER REGISTRES * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Sauvegarde les registres utilisés par la routine de debuggage ;----------------------------------------------------------------------------- org DBGADD ; Adresse de la routine de debuggage

;sauvegarder registres ;--------------------- movwf w_CBDS ; sauver registre W swapf STATUS,w ; swap status avec résultat dans w movwf status_CBDS ; sauver status swappé movf INTCON,w ; charger INTCON BANKSEL FSR_CBDS ; passer banque2 movwf INTCON_CBDS ; sauver INTCON bcf STATUS,RP1 ; passer banque1 movf PIR1,w ; charger PIR1 bsf STATUS,RP1 ; passer banque 2 movwf PIR1_CBDS ; sauver PIR1 bcf STATUS,RP1 ; passer banque1

40

movf PIR2,w ; charger PIR2 bsf STATUS,RP1 ; passer banque 2 movwf PIR2_CBDS ; sauver PIR1 movf FSR , w ; charger FSR movwf FSR_CBDS ; sauvegarder FSR movf PCLATH , w ; charger PCLATH movwf PCLATH_CBDS ; le sauver PAGESEL DBGADD ; pointer sur page actuelle Vous remarquez qu’on sauve W et STATUS, en banque commune, ensuite on bascule en banque 2, et on sauve PCLATH, FSR, INTCON, PIR1 et PIR2. La directive PAGESEL positionne PCLATH sur la page de l’adresse passée en paramètre. Il faut savoir, en effet, que le programme de debuggage sera lancé en page haute, mais que PCLATH ne sera pas automatiquement positionné sur cette page. Ce mécanisme est impératif, afin de vous permettre de sauvegarder PCLATH et de permettre ainsi le retour au programme interrompu, quelle que soit la page où il a été interrompu. PAGESEL permet donc de sauter à l’intérieur de notre routine de debuggage. Maintenant, vous pouvez vous demander la raison de la sauvegarde de ces registres. Pour certains d’entre eux, c’est évident : W : sera modifié par la routine de debuggage, donc la sauvegarde est impérative STATUS et FSR : idem Reste le cas des registres contenant les flags d’interruption (INTCON,PIR1, et PIR2). Cette sauvegarde peut être utile à cause du bug du mode FREEZE. Imaginons par exemple que vous entriez dans votre routine de debuggage. Imaginons qu’à cet instant, le timer 0 tourne et que le flag T0IF ne soit pas positionné. Le temps que vous entriez votre commande de lecture de INTCON, il y a fort à parier que votre timer 0 aura débordé. Ceci induit que lorsque vous interrogerez INTCON, vous aurez le bit T0IF positionné, alors qu’il ne l’était pas au moment de l’interruption de votre programme à debugger. La mémorisation immédiate de ces flags permet de minimiser ce type de problème (pensez tout de même que quelques cycles auront permis la modification de ces registres, entre le moment du « halt » de votre programme à debugger, et la sauvegarde des registres d’interruption. Il m’est impossible de contrer plus efficacement les bugs du debugger intégré. (Notez qu’un bug dans un debugger, il fallait quand même oser, non ?). Si vous construisez l’ICD® de Microchip®, vous verrez qu’ils ne se préoccupent pas du tout de ce bug, vous n’avez qu’à vous débrouiller avec. Maintenant, nous allons configurer nos pins RB6 et RB7 pour un fonctionnement correct en mode debugger. ;***************************************************************************** ; Entrer dans le mode debugger * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Envoi message d'accueil, puis registres de debuggage ;-----------------------------------------------------------------------------

41

cbds_start ; initialiser

; ----------- bsf TXPIN ; préparer sortie à 1 bsf STATUS,RP0 ; passer banque 3 bcf TXPIN ; passer pin émission en sortie bsf RXPIN ; passer pin réception en entrée bcf STATUS,RP0 ; repasser banque 2 SUBRS cbds_endrec ; attendre fin de réception éventuelle Rien que du classique, notez qu’on travaille sur le TRISB de la banque 3, comme conseillé. Notez aussi qu’à partir de cet instant, on pointera par défaut sur la banque 2, contrairement à nos habitudes.

Donc, les appels de pseudo sous-routines se feront à partir de la banque 2, les retours également. Ceci se justifie puisque toutes nos variables sont dans cette banque, et que le seul registre hardware que nous utiliserons (PORTB) se trouve également dans cette banque. La sous-routine cbds_endrec permet d’attendre que la ligne RB6 soit stabilisée à un niveau haut (absence de réception de données) pour continuer. En effet, pour provoquer un « halt » du programme à debugger, il nous faudra envoyer au moins une impulsion haut vers bas sur RB6. Comme RB6 sert dans notre routine de debuggage comme entrée d’informations, il suffira donc, pour provoquer un « halt » de notre programme principal, d’envoyer n’importe quoi sur la liaison série (je vous ai dit : « simple et bon marché »). La routine de debuggage sera donc appelée dès le start-bit de ce que vous avez envoyé détecté. Avant de poursuivre, il convient donc d’attendre que la fausse information que vous avez envoyée soit terminée, d’où l’appel de cette pseudo sous-routine. Maintenant, en tant qu’utilisateur, vous serez content d’avoir au minimum un message qui vous indique que vous êtes bien entré en mode debuggage. Nous appellerons donc une pseudo sous-routine d’envoi de caractère, à laquelle nous passerons en argument, en tant que constante, le caractère à envoyer. Si vous avez tout compris, c’est donc la macro SUBRC qui sera utilisée ici :

; message d'accueil ; ----------------- SUBRC cbds_send,"[" ; envoyer message SUBRC cbds_send,"D" ; envoyer message SUBRC cbds_send,"T" ; envoyer message SUBRC cbds_send,"R" ; envoyer message SUBRC cbds_send,"A" ; envoyer message SUBRC cbds_send,"]" ; envoyer message SUBRC cbds_send,":" ; envoyer message Le message de bienvenue sera donc : [DTRA] : Maintenant, on va y ajouter des informations pratiques, et tout d’abord sur le fonctionnement du debugger en lui-même. Nous allons donc lire le registre ICKBUG (en banque 3) pour déterminer quelle sont les valeurs des bits FREEZ et SSTEP. S’ils sont

42

positionnés, on indiquera respectivement les lettres « F » et « S » à côté de notre message d’accueil.

; registres de debuggage ; ---------------------- bsf STATUS,RP0 ; passer en banque3 btfss 0x0E,6 ; tester si mode freeze goto cbds2 ; non, sauter bcf STATUS,RP0 ; repasser banque 2 SUBRC cbds_send,"F" ; oui, indiquer "F" SUBRC cbds_send," " cbds2 bsf STATUS,RP0 ; passer banque 3 btfss 0x0E,5 ; tester si mode step by step goto cbds3 ; non, sauter bcf STATUS,RP0 ; repasser banque 2 SUBRC cbds_send,"S" ; oui, indiquer "S" SUBRC cbds_send," " Notez que j’ai utilisé l’adresse 0x0E, et non 0x18E. Si vous utilisez 0x18E, ça ne changera strictement rien (puisque de toute façon vous pointez sur la bonne banque), mais MPASM® vous gratifiera d’un superbe warning du style : Warning[219] chemin\DEBUG.ASM 276 : Invalid RAM location specified. Vous constatez par vous-même que Microchip® n’apprécie pas vraiment qu’on tente d’écrire soi-même un programme de debuggage, puisqu’il vous dit en substance « Touche pas à ça, petit c… ». Bon, c’est vrai que je métaphore un peu, mais bon, il me semble que c’est bien l’idée qui se dégage de ce message. Une autre information indispensable est de savoir à quel endroit le programme à debugger a été arrêté. Nous disposons de ces informations dans les bits BKAxx. La partie haute de l’adresse est contenue dans les 5 bits de poids faible de ICKBUG, les 8 bits restants dans BIGBUG. Chacune de ces valeurs nécessite 2 digits ASCII pour être affichée. Nous utiliserons donc à chaque fois notre macro « cbdsA2 ». cbds3 bsf STATUS,RP0 ; passer banque 3 movf 0x0E,w ; charger registre ICKBUG andlw 0x1F ; garder partie haute adresse bcf STATUS,RP0 ; repasser banque 2 cbdsA2 ; envoyer adresse haute en ascii bsf STATUS,RP0 ; repasser banque 3 movf 0x0F,w ; charger adresse basse dans BIGBUG bcf STATUS,RP0 ; repasser banque2 cbdsA2 ; envoyer adresse basse en ascii Nous avons maintenant notre message libellé de la sorte : [DTRA] : F S 0001

Avec F et S optionnels, et 0001 l’adresse du point d’arrêt du programme. Au premier lancement, je rappelle que BKAxx contiennent l’adresse 0x00, donc le premier arrêt

43

interviendra après exécution de l’adresse 0x00, le pointeur de programme, et donc BKAxx pointera donc sur l’adresse 0x0001 : logique si la première instruction est bien un « nop ».

Notez qu’à la mise sous tension, F et S ne seront pas positionnés, et donc n’apparaîtront

pas dans le message de bienvenue. Maintenant, on peut se dire que c’en est fini du message d’accueil. Cependant, il faut bien penser à tout. Vous aurez besoin de connaître l’état du registre « W » lors du debuggage. Or, ce registre est modifié par votre routine de debuggage. Il en va de même de FSR et de STATUS. Une lecture de l’adresse 0x03 vous donnera, non pas le registre STATUS tel qu’il était lors de l’arrêt de votre programme, mais le registre STATUS tel qu’il est actuellement, ce qui n’a aucun intérêt. Il faut alors se souvenir que ces registres sont sauvegardés dans nos variables de sauvegarde. Plutôt que d’imposer à l’utilisateur de retenir ces emplacements, j’ai choisi d’envoyer d’office ces valeurs, de plus très souvent utilisées. On commence donc par faire un saut de ligne, puis on affiche « W : » suivi de sa valeur au moment de l’arrêt du programme à debugger : ; envoyer registres sauvegardés ; ----------------------------- SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"W" ; W SUBRC cbds_send,":" ; : movf w_CBDS,w ; charger regitre "W" sauvegardé cbdsA2 ; envoyer valeur en ascii On continue avec STATUS (STAT: ), FSR (FSR: ), INTCON (INT : ), PIR1 (PIR1 : ) et PIR2 (PIR2 : ) SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"S" ; STATUS SUBRC cbds_send,"T" ; SUBRC cbds_send,"A" ; SUBRC cbds_send,":" ; : swapf status_CBDS,w ; charger registre STATUS sauvegardé swappé cbdsA2 ; envoyer valeur en ascii SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"F" ; FSR SUBRC cbds_send,"S" ; SUBRC cbds_send,"R" ; SUBRC cbds_send,":" ; : movf FSR_CBDS,w ; charger registre FSR sauvegardé cbdsA2 ; envoyer valeur en ascii SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"I" ; INTCON SUBRC cbds_send,"N" ; SUBRC cbds_send,"T" ; SUBRC cbds_send,":" ; :

44

movf INTCON_CBDS,w ; charger registre INTCON sauvegardé cbdsA2 ; envoyer valeur en ascii SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"P" ; PIR1 SUBRC cbds_send,"I" ; SUBRC cbds_send,"R" ; SUBRC cbds_send,"1" ; SUBRC cbds_send,":" ; : movf PIR1_CBDS,w ; charger registre PIR1 sauvegardé cbdsA2 ; envoyer valeur en ascii SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRC cbds_send,"P" ; PIR2 SUBRC cbds_send,"I" ; SUBRC cbds_send,"R" ; SUBRC cbds_send,"2" ; SUBRC cbds_send,":" ; : movf PIR2_CBDS,w ; charger registre PIR2 sauvegardé cbdsA2 ; envoyer valeur en ascii Comme je vous ai dit, une fois les macros écrites, le reste est simple, n’est-ce pas ? On entre alors dans la boucle principale du programme qui peut se résumer comme suit : - On attend une commande - On répond à la commande - On recommence

Etant donné qu’après chaque réponse, il sera bon d’aller à la ligne, on va intégrer ce passage à la ligne dès le début de la boucle :

;***************************************************************************** ; BOUCLE PRINCIPALE * ;***************************************************************************** ;----------------------------------------------------------------------------- ; On attend la commande ; dès que reçue, on teste pour voir de laquelle il s'agit ;----------------------------------------------------------------------------- cbds_boucle SUBRC cbds_send,0x0D ; return SUBRC cbds_send,0x0A ; line-feed SUBRS cbds_rec ; attendre et recevoir commande bcf cbds_byte,7 ; passer commande en majuscule Notez la dernière ligne, qui passe la commande en majuscule. Ainsi, vous pourrez indifféremment utiliser les commandes en majuscules ou en minuscules. Une minuscule possède la même code ASCII qu’une majuscule, excepté que le bit 7 de son code ASCII vaut « 1 ». Attention, par contre, les nombres Hexadécimaux devront rester en majuscules (10F et non 10f par exemple) Maintenant, on va traiter commande par commande. On a reçu le premier octet entré par l’utilisateur via la pseudo sous-routine cbds_rec. L’octet lu se trouve dans cbds_byte. On teste si cet octet vaut « R ». Dans ce cas, on traite la commande, dans le cas contraire, on teste s’il s’agit de la commande suivante. Le même test se répétera pour chaque commande traitée.

45

Toute erreur de syntaxe dans une commande se traduit par un message d’erreur. La commande « R » permet de lire le contenu d’un registre ou d’une variable RAM. La syntaxe est la suivante :

Rxxx avec xxx = adresse, obligatoirement sur 3 chiffres, du registre dont on veut connaître le

contenu. Toute commande doit obligatoirement se terminer par un appui sur la touche <RETURN>, qui se traduit par l‘émission des 2 octets 0x0D et 0x0A. ;***************************************************************************** ; TRAITER COMMANDE "R" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; S'il s'agit d'une commande "R", on reçoit la banque puis l'adresse. ; on attend ensuite le 0x0D puis 0x0A, et ensuite, on envoie la réponse ;----------------------------------------------------------------------------- cbds_comR

; tester si reçu "R" ; ------------------ movf cbds_byte,w ; charger octet reçu xorlw "R" ; comparer avec commande "R" btfss STATUS,Z ; tester si égalité goto cbds_comS ; non, tester commande suivante

; réception des caractères ; ------------------------ cbdsR cbds_car3 ; lire digit 1 adresse cbdsR cbds_car1 ; lire digit 2 adresse cbdsR cbds_car2 ; lire digit 3 adresse SUBRS cbds_end ; vérifier fin de message SUBRS cbds_ashex ; convertir ASCII en hexa

; lire valeur demandée ; -------------------- movf cbds_car2,w ; charger valeur convertie movwf FSR ; dans pointeur indirect bcf STATUS,IRP ; par défaut, banque 0 et 1 btfsc cbds_car3,0 ; bit 9 = 1? bsf STATUS,IRP ; oui, alors banque 2 et 3 movf INDF,w ; charger valeur demandée cbdsA2 ; convertir et envoyer goto cbds_boucle ; commande suivante On distingue très nettement les différentes parties. Tout d’abord le test de la commande reçue, ensuite la réception des 3 digits de l’adresse, stockés aux emplacements précisés dans les macros cbdsR. La pseudo sous-routine cbds_end vérifie que le message se termine bien par l’appui sur la touche return, à l’exception de tout autre caractère. La sous-routine cbds_ashex converti les 2 caractères stockés sous leur forme ASCII aux emplacements cbds_car1 et cbds_car2 en un nombre hexadécimal de 8 bits. Le résultat de la conversion sera sauvé en cbds_car2 par la pseudo sous-routine. Si vous examinez ce qui précède, vous avez reçu :

46

R abc , avec abc adresse du registre « a » a été conservé tel quel sous sa forme ASCII à l’emplacement cbds_car3 « bc » a été converti en un nombre hexadécimal contenu dans cbds_car2 Or « a » représente le 9ème bit de l’adresse du registre concerné, il ne peut donc valoir que « 0 » ou « 1 » en ASCII, soit la valeur 0x30 ou 0x31 en hexadécimal. Autrement dit : cbds_car2 contient les 8 bits faibles de l’adresse du registre concerné, cbds_car3 indique s’il s’agit d’un registre en banques 0/1 ou en banques 2/3. Imaginons par exemple, que nous avons tapé « R132 ». A l’issue de la conversion demandée, nous aurons cbds_car2 = 0x32, et cbds_car3 = 0x31 (caractère « 1 », donc banque 2 ou 3). Il nous suffit alors simplement de charger cbds_car2 dans le registre d’adressage indirect FSR, et de positionner le bit IRP en fonction de la valeur de cbds_car3, pour pointer sur le registre réclamé par l’utilisateur. Une simple lecture par « movf INDf,W » lira la valeur de ce registre. Il ne reste plus alors qu’à convertir cette valeur hexadécimale de 8 bits en 2 caractères ASCII, et à l’envoyer vers le PC, ce que fait la macro CBDSA2. Une fois la commande traitée, on reprend depuis le début de la boucle principale dans l’attente de la commande suivante. Vous voyez que le mécanisme est extrêmement simple, et ressemble d’ailleurs au mécanisme utilisé pour la norme ISO7816 (attente d’une commande, réponse, puis retour au début). Maintenant, s’il ne s’agit pas d’une commande « R » qui a été entrée, nous allons voir, exactement de la même façon, s’il s’agit d’une commande « S ». La commande « S » ne nécessite aucun paramètre. Elle inverse l’état actuel du bit « SSTEP », et donc autorise ou pas le fonctionnement du debugger en pas à pas. L’utilisateur est informé de l’état actuel par le message [ON ] ou [OFF] selon que le bit est positionné ou pas. ;***************************************************************************** ; TRAITER COMMANDE "S" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; inversion du mode pas à pas ; on répond par le nouvel état du bit SSTEP ;----------------------------------------------------------------------------- cbds_comS

; tester si reçu "S" ; ------------------ movf cbds_byte,w ; charger commande reçue xorlw "S" ; comparer avec commande "S" btfss STATUS,Z ; tester si égalité goto cbds_comF ; non, tester commande suivante SUBRS cbds_end ; vérifier fin de message

; début du message ; ---------------- SUBRC cbds_send,"[" ; message commencera par [0

47

SUBRC cbds_send,"O" ; O

; tester bit "S" ; -------------- bsf STATUS,RP0 ; passer en banque 3 btfss 0x0E,5 ; tester si on était en pas-à-pas goto cbds_coms2 ; non, sauter

; SSTEP OFF ; --------- bcf 0x00E,5 ; couper mode pas-à-pas bcf STATUS,RP0 ; passer banque 2 cbds_moff SUBRC cbds_send,"F" ; message [OFF] SUBRC cbds_send,"F" SUBRC cbds_send,"]" goto cbds_boucle ; commande suivante

; SSTEP ON ; -------- cbds_coms2 bsf 0x0E,5 ; positionner mode pas-à-pas bcf STATUS,RP0 ; passer banque 2 cbds_mon SUBRC cbds_send,"N" ; message [ON] SUBRC cbds_send,"]" goto cbds_boucle ; commande suivante De nouveau, c’est très simple, on se contente d’inverser le bit « SSTEP » du registre ICKBUG . Comme dans [ON] et dans [OFF], on a le début commun « [O », alors on commence par l’envoyer, ça évite de répéter, et donc économise de la place. Notez les étiquettes cbds_mon et cbds_moff, qui seront utilisées par la commande suivante, afin, de nouveau, d’éviter les répétitions. Traitons maintenant le cas de la commande « F », qui s’utilise également sans paramètre, et qui inverse le bit « FREEZ » de la même façon que pour le bit « SSTEP ». La réponse sera la même que pour le bit précédent, ce qui permet d’utiliser les portions de code déjà écrites pour la commande « S » concernant l’écriture de la fin des messages. Ceci explique les « goto cbds_mon » et « goto cbds_moff). Souvenez-vous seulement que la fonction FREEZE ne fonctionne pas sur les PIC® actuels. Cependant, j’utiliserai cette option en interne pour limiter un peu la « casse » à ce niveau. Nous en reparlerons plus loin. ;***************************************************************************** ; TRAITER COMMANDE "F" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; inversion du Freeze ; on répond par le nouvel état du bit FREEZ ;----------------------------------------------------------------------------- cbds_comF

; tester si reçu "F" ; ------------------ movf cbds_byte,w ; charger commande reçue xorlw "F" ; comparer avec commande "F" btfss STATUS,Z ; tester si égalité goto cbds_comB ; non, tester commande suivante

48

SUBRS cbds_end ; vérifier fin de message

; début du message ; ---------------- SUBRC cbds_send,"[" ; message commencera par [0 SUBRC cbds_send,"O" ; O

; tester bit "F" ; -------------- bsf STATUS,RP0 ; passer en banque 3 btfss 0x0E,6 ; tester si on était en FREEZE goto cbds_comf2 ; non, sauter

; SSTEP OFF ; --------- bcf 0x00E,6 ; couper mode freeze bcf STATUS,RP0 ; passer banque 2 goto cbds_moff ; message [OFF]

; SSTEP ON ; -------- cbds_comf2 bsf 0x0E,6 ; positionner mode pas-à-pas bcf STATUS,RP0 ; passer banque 2 goto cbds_mon ; message [ON] Nous allons maintenant nous intéresser à la commande « B » qui définit le prochain point d’arrêt (ou break-point) de notre programme. La syntaxe sera la suivante : Babcd Avec « abcd » l’adresse du point d’arrêt impérativement codée sur 4 digits. ;***************************************************************************** ; TRAITER COMMANDE "B" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Placer adresse du prochain break-point ;----------------------------------------------------------------------------- cbds_comB

; tester si reçu "B" ; ------------------ movf cbds_byte,w ; charger commande reçue xorlw "B" ; comparer avec commande "B" btfss STATUS,Z ; tester si égalité goto cbds_comM ; non, tester commande suivante

; Lire les data ; ------------- cbdsR cbds_car1 ; lire digit 1 adresse cbdsR cbds_car2 ; lire digit 2 adresse cbdsR cbds_car3 ; lire digit 3 adresse cbdsR cbds_car4 ; lire digit 4 adresse SUBRS cbds_end ; vérifier fin de message ; sauver adresse ; -------------- SUBRS cbds_ashex ; convertir ASCII en hexa MSB movf cbds_car2,w ; charger MSB demandé movwf cbds_break ; sauver MSB

49

movf cbds_car3,w ; charger caractère 3 reçu movwf cbds_car1 ; dans caractère 1 movf cbds_car4,w ; charger caractère 4 reçu movwf cbds_car2 ; dans caractère 2 SUBRS cbds_ashex ; convertir ASCII en hexa MSB movf cbds_car2,w ; charger LSB demandé movwf cbds_break2 ; sauver LSB SUBRC cbds_send,"[" ; [ SUBRC cbds_send,"O" ; O SUBRC cbds_send,"K" ; K SUBRC cbds_send,"]" ; ] goto cbds_boucle ; commande suivante On commence donc par recevoir les 4 digits, qu’on mémorise dans les emplacements cbds_car1 à cbds_car4. On converti alors les 8 premiers bits de l’adresse (cbds_car1 et cbds_car2) en hexadécimal, et on sauve l’octet obtenu dans cbds_break. On transfère ensuite les 2 derniers digits reçus dans cbds_car1 et cbds_car2, on converti en hexadécimal, et on sauve le poids faible de l’adresse obtenu dans cbds_break2. On répond ensuite par le message [OK]. Vous pourriez vous demander pourquoi on n’écrit pas l’adresse demandée directement dans les bits BKAxx des registres ICKBUG et BIGBUG. Mais, dans ce cas, en cas d’arrêt de votre programme pour une autre raison (action sur RB6) l’adresse de break-point serait perdue, puisque écrasée par le mécanisme de debuggage, qui copierait l’adresse de l’instruction suivant l’arrêt dans ces bits.

De plus, à chaque arrêt, BKAxx pointerait sur l’adresse qui suit l’adresse de l’arrêt, et donc, une fois de plus, votre point d’arrêt serait continuellement modifié. Les variables « break » et « break2 » ne sont pas initialisées au démarrage, et contiennent donc n’importe quelle valeur. A vous, lors du démarrage du debugger, de placer l’adresse qui vous convient à l’aide de la commande « B ». Notez que si vous ne désirez pas utiliser de break-point, il vous suffit de placer l’adresse à l’intérieur de la routine de debuggage. Ceci peut s’effectuer par exemple par : B1FFF Nous arrivons maintenant à la commande « M » pour « Modify ». Cette commande attend 2 paramètres, séparés par une virgule. Le premier est l’adresse du registre à modifier, codée sur 3 digits, comme pour la commande « R ». Le second est la valeur à écrire dans le registre (ou la variable), sous forme d’un octet, donc de 2 caractères ASCII . La syntaxe est donc : Mabc,de Avec « abc » l’adresse du registre, et « de » la valeur à y inscrire. ;*****************************************************************************

50

; TRAITER COMMANDE "M" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; on reçoit la commande, puis l'adresse du registre concerné (sur 3 digits) ; ensuite le symbole ",", puis la valeur sur 2 digits ;----------------------------------------------------------------------------- cbds_comM

; tester si reçu "M" ; ------------------ movf cbds_byte,w ; charger commande reçue xorlw "M" ; comparer avec commande "M" btfss STATUS,Z ; tester si égalité goto cbds_comG ; non, tester commande suivante

; réception des caractères ; ------------------------ cbdsR cbds_car3 ; lire digit 1 adresse cbdsR cbds_car1 ; lire digit 2 adresse cbdsR cbds_car2 ; lire digit 3 adresse SUBRS cbds_rec ; recevoir octet movf cbds_byte,w ; charger octet reçu xorlw "," ; comparer avec "," btfss STATUS,Z ; tester si identique goto cbds_err ; non, alors erreur cbdsR cbds_car4 ; lire digit 1 data cbdsR cbds_car5 ; lire digit 2 data SUBRS cbds_end ; vérifier fin de message

; pointer sur registre concerné ; ----------------------------- SUBRS cbds_ashex ; convertir digits 2 et 3 en hexa movf cbds_car2,w ; charger octet transformé movwf FSR ; dans pointeur indirect bcf STATUS,IRP ; par défaut, banque 0 et 1 btfsc cbds_car3,0 ; bit 9 adresse = 1? bsf STATUS,IRP ; oui, alors banque 2 et 3

; placer valeur demandée ; ---------------------- movf cbds_car4,w ; charger digit1 valeur reçue movwf cbds_car1 ; sauver movf cbds_car5,w ; charger digit2 valeur reçue movwf cbds_car2 ; sauver SUBRS cbds_ashex ; convertir en hexa movf cbds_car2,w ; charger octet converti movwf INDF ; placer valeur dans registre demandé movf INDF,w ; charger valeur réelle cbdsA2 ; convertir et envoyer goto cbds_boucle ; commande suivante Je n’entrerai plus trop dans les détails, vous devriez commencer à bien comprendre. L’adresse du registre est détectée comme pour la commande « R ». Ensuite, on vérifie la présence de la virgule, puis on lit la valeur. Après conversion de tout ceci, on écrit la valeur, puis on procède à la lecture du registre dans lesquels on vient d’écrire, et on renvoie la valeur effectivement lue.

51

On répond donc à l’utilisateur par la valeur effectivement présente dans le registre après sa modification, et non par la valeur qu’il a voulu y placer. Ceci est pratique, par exemple, si vous tentez de forcer un bit en lecture seule, la valeur renvoyée vous montrera que ce bit n’a pu être affecté (ce qui n’est pas le cas dans le simulateur de MPLAB®, qui vous autorise toutes les fantaisies, même irréalistes). Il nous reste la commande « G » pour « GO », qui termine la routine de debuggage, et relance le déroulement du programme à debugger. On commencera par copier nos valeurs de break-point dans les bits BKAxx, afin de programmer l’adresse du prochain arrêt, puis on envoie le message [GO] à l’utilisateur, et enfin on relance la restauration des registres avant la sortie du mode debugger. ;***************************************************************************** ; TRAITER COMMANDE "G" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Retour au programme principal ; on répond par [GO] ;----------------------------------------------------------------------------- cbds_comG

; tester si reçu "G" ; ------------------ movf cbds_byte,w ; charger commande reçue xorlw "G" ; comparer avec commande "G" btfss STATUS,Z ; tester si égalité goto cbds_err ; non, alors commande inconnue SUBRS cbds_end ; vérifier fin de message

; envoyer message ; --------------- SUBRC cbds_send,"[" ; [ SUBRC cbds_send,"G" ; G SUBRC cbds_send,"O" ; O SUBRC cbds_send,"]" ; ] SUBRS cbds_endrec ; attendre fin de réception éventuelle

; positionner prochain Break ; -------------------------- movlw 0xE0 ; masque pour ICKBUG bsf STATUS,RP0 ; passer banque 3 andwf 0x0E,f ; effacer MSB adresse bcf STATUS,RP0 ; repasser banque2 movf cbds_break,w ; charger MSB demandé bsf STATUS,RP0 ; passer banque 3 iorwf 0x0E,f ; placer MSB demandé

; traiter LSB ; ----------- bcf STATUS,RP0 ; passer banque2 movf cbds_break2,w ; charger LSB break bsf STATUS,RP0 ; passer banque 3 movwf 0x0F ; positionner LSB bcf STATUS,RP0 ; passer banque 2 La restauration des registres ne pose aucun problème, et se termine par la seule instruction « return » de notre programme, qui met fin à notre mode de debuggage, et renvoie le PIC® au programme à debugger.

52

;***************************************************************************** ; RESTAURER REGISTRES * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Restaure les registres modifiés par la routine de debuggage ; Restaure les registres INTCON,PIR1, et PIR2 si FREEZ est positionné ;----------------------------------------------------------------------------- cbds_restore

; Restauration registres interruption ; ----------------------------------- bsf STATUS,RP0 ; passer banque 3 btfss 0x0E,6 ; bit FREEZ mis? goto cbds_restore2 ; non, sauter bcf STATUS,RP0 ; passer banque 2 movf PIR2_CBDS,w ; charger PIR2 sauvegardé bcf STATUS,RP1 ; passer banque 0 movwf PIR2 ; restaurer PIR2 bsf STATUS,RP1 ; passer banque 2 movf PIR1_CBDS,w ; charger PIR1 sauvegardé bcf STATUS,RP1 ; passer banque 0 movwf PIR1 ; restaurer PIR1 bsf STATUS,RP1 ; passer banque 2 movf INTCON_CBDS,w ; charger INTCON sauvegardé movwf INTCON ; restaurer INTCON

; restauration autres registres ; ----------------------------- cbds_restore2 bcf STATUS,RP0 ; passer banque2 movf PCLATH_CBDS,w ; recharger ancien PCLATH movwf PCLATH ; le restaurer movf FSR_CBDS,w ; charger ancien FSR movwf FSR ; restaurer FSR swapf status_CBDS,w ; swap ancien status, résultat dans w movwf STATUS ; restaurer status swapf w_CBDS,f ; Inversion L et H de l'ancien W swapf w_CBDS,w ; Réinversion de L et H dans W return ; retour au programme principal Vous constatez que je vous ai laissé le choix du fonctionnement des registres d’interruption. - Soit vous laissez le bit « FREEZ » à 0, dans ce cas, les flags d’interruption qui auront été

positionnés durant la routine de debuggage resterons positionnés lors du retour dans le programme d’interruption.

- Soit vous forcez le bit FREEZ à « 1 », via la commande « F », et dans ce cas, les registres

INTCON,PIR1, et PIR2 seront placés à leur valeur indiquée en entrée dans le mode debug avant de sortir.

Vous obtenez donc 2 modes de fonctionnement.

Avec FREEZ = 0 (par défaut) - Sur l’entrée dans la routine de debuggage, les registres sont sauvegardés, et affichés - Lors de la sortie, ils ne sont pas restaurés.

53

Ceci implique que si un événement survient durant le debuggage (par exemple,

débordement d’un timer) , le retour dans le programme à debugger prendra en compte cet événement.

De plus, vous pouvez modifier sans problème INTCON, PIR1, ou PIR2, la modification

sera effective au retour dans le programme principal. Avec FREEZ = 1 (action de la commande « F ») - Sur l’entrée dans la routine de debuggage, les registres sont sauvegardés, et affichés - Lors de la sortie, ils seront restaurés.

Ceci implique que si un événement survient durant le dialogue de debuggage, il ne sera pas pris en compte lors du retour dans le programme à debugger, puisque le flag sera restauré tel quel à la sortie du mode debugger.

Par contre, si vous tentez de modifier PIR1, PIR2, ou INTCON, la modification sera

annulée au moment de sortir, puisque les valeurs seront automatiquement restaurées.

L’astuce, dans ce cas, sera de modifier les valeurs sauvegardées, donc celles qui seront restaurées avant la sortie du mode de debuggage. Si vous utilisez les adresses variables par défaut, les adresses sont les suivantes : INTCON = 0x112 PIR1 = 0x113 PIR2 = 0x114 Si vous utilisez les adresses hautes, les adresses sont les suivantes : INTCON = 0x162 PIR1 = 0x163 PIR2 = 0x164 Je résume, pour voir si vous avez suivi. Vous désirez placer GIE dans INTCON à « 1 » avant de sortir du debugger. Si vous n’avez pas activé le bit « FREEZ », vous écrirez M00B,80<RETURN> Si, par contre, vous l’avez activé, vous écrirez : M112,80<RETURN> Ou M162,80<RETURN>

54

Selon que vous aurez indiqué CBDS_HIGH ou non dans votre debugger. Bien entendu, la même technique pourra être appliquée aux registres qui seront automatiquement restaurés (ne dépendent pas de FREEZ), je pense à W, FSR, PCLATH, et STATUS. Les adresses sont les suivantes : W = 0x7F STATUS = 0x7E PCLATH = 0x110 ou 0x160 FSR = 0x111 ou 0x161 Nous avons besoin également d’une routine chargée d’afficher un message d’erreur en cas de mauvaise commande, ou de syntaxe erronée : ;***************************************************************************** ; TRAITER COMMANDE ERRONEE * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Si commande inconnue, ou si paramètres incorrects, alors erreur ;----------------------------------------------------------------------------- cbds_err SUBRS cbds_endrec ; attendre fin de réception éventuelle SUBRC cbds_send,"[" ; [ SUBRC cbds_send,"E" ; E SUBRC cbds_send,"R" ; R SUBRC cbds_send,"R" ; R SUBRC cbds_send,"]" ; ] goto cbds_boucle ; commande suivante Remarquez que le message [ERR] est suivi d’un retour au début de la boucle, et donc de l’attente d’une nouvelle commande. Nous en avons fini avec notre programme principal, nous allons maintenant étudier les sous-routines dont nous avons besoin. Commençons par la routine qui converti un nombre hexadécimal en 2 caractères ASCII. ;***************************************************************************** ; Conversion Hexa vers ASCII * ;***************************************************************************** ;----------------------------------------------------------------------------- ; L'octet est reçu dans cbds_byte ; Le poids fort est renvoyé dans cbds_byte, le poids faible dans cbds_byteL ; entrée et sortie en banque 2 ;----------------------------------------------------------------------------- cbds_ascii

; convertir poids faible ; ---------------------- movf cbds_byte,w ; charger octet reçu andlw 0x0F ; garder poids faible addlw 0x30 ; ajouter 0x30 pour les chiffres 0 à 9 movwf cbds_byteL ; sauver dans poids faible sublw 0x39 ; comparer avec zone des chiffres movlw 0x07 ; différence entre ascii 3A et ascII 41 (A) btfss STATUS,C ; il s'agit d'une lettre (A-F)? addwf cbds_byteL,f ; oui, corriger code ascii

55

; convertir poids fort ; -------------------- swapf cbds_byte,w ; charger poids fort swappé andlw 0x0F ; garder poids faible addlw 0x30 ; ajouter 0x30 pour les chiffres 0 à 9 movwf cbds_byte ; sauver dans poids fort sublw 0x39 ; comparer avec zone des chiffres movlw 0x07 ; différence entre ascii 3A et ascII 41 (A) btfss STATUS,C ; il s'agit d'une lettre (A-F)? addwf cbds_byte,f ; oui, corriger code ascii RET ; et retour Comment tout ceci fonctionne-t-il ? Et bien pour le savoir, il faut savoir ce qu’est un caractère ASCII. Ce standard permet d’attribuer à chaque caractère « imprimable » un code (une valeur hexadécimale) qui permet de l’identifier. Par exemple, si vous voulez imprimer, ou afficher, le caractère « A », vous devrez envoyer la valeur «0x41 » ou D’65’. On dira que 0x41 est le code ASCII de « A ». Nous, aurons besoin de pouvoir afficher des nombres qui arrivent sous forme hexadécimale, et de les afficher dans le programme tournant sur le PC, et qui, lui, comprend les caractères ASCII. Les nombres hexadécimaux comprennent 16 « chiffres », représentés par les « chiffres » 0 à 9, et par les « lettres » A à F. Nous avons donc besoin d’un programme qui convertisse ces chiffres en caractères ASCII. Voici les codes ASCII de ces 16 « chiffres » : 0 0x30 1 0x31 2 0x32 3 0x33 4 0x34 5 0x35 6 0x36 7 0x37 8 0x38 9 0x39 A 0x41 B 0x42 C 0x43 D 0x44 E 0x45 F 0x46 Imaginons, pour l’exemple, que nous lisions la valeur « 0x5E » dans un registre, et que nous désirions l’envoyer.

56

Vous voyez tout de suite que vous avez à l’origine un octet (0x5E) et que vous allez devoir envoyer 2 octets (le code ASCII de « 5 » et le code ASCII de « E »). Prenons le digit de poids faible. Si vous faites un masque de 0x5E avec 0x0F, vous conservez 0x0E, donc uniquement le digit de poids faible. Pour le digit de poids fort, vous commencez par faire un swap de 0x5E, ce qui vous donne 0xE5, puis vous faites de nouveau un masque avec 0x0F, ce qui vous donne 0x05. Voici les 2 digits isolés chacun dans une variable. Remarquez maintenant que pour les chiffres de 0 à 9, le code ASCII correspond à une simple addition de 0x30 à la valeur du digit. Commençons donc par ajouter 0x30 à chacun des digits. Nous obtenons alors : Digit 1 : 0x05 + 0x30 = 0x35 Digit 2 : 0x0E + 0x30 = 0x3E. Maintenant, si on regarde la table précédente, on s’aperçoit que ce qui fonctionne pour les chiffres de 0 à 9, ne fonctionne pas pour les « chiffres » de A à F. En effet, pour ces derniers, c’est 0x37 qu’il convient d’ajouter, et non 0x30. On commence donc par tester le code ASCII obtenu par la première addition. Si le résultat est supérieur à 0x39, alors il s’agit d’un « chiffre » supérieur à 9, donc A à F. Il convient alors d’ajouter les 0x07 manquants pour obtenir le bon code ASCII. Si on applique ceci à notre exemple, on aura : Digit 1 : inférieur ou égal à 0x39, pas de correction : résultat = 0x35 Digit 2 : supérieur à 0x39, on ajoute 0x07, ce qui donne : 0x3E + 0x07 = 0x45 Si vous regardez dans la table ASCII précédente, vous voyez que 0x35 est bien le code ACII de « 5 », et 0x45 le code ASCII de « E ». Nous avons donc converti 0x5E en « 5 » + « E », qui pourront alors être affichés sans problème. Notez la macro RET qui termine cette pseudo sous-routine. Nous savons maintenant convertir un nombre hexadécimal issu de notre programme, en deux nombres ASCII destinés à notre PC. Comme notre PC nous envoie des caractères ASCII, il nous faut pouvoir les convertir en nombres hexadécimaux utilisables par notre programme. Voici donc la procédure inverse : ;***************************************************************************** ; CONVERSION ASCII VERS HEXA * ;***************************************************************************** ;----------------------------------------------------------------------------- ; transforme les digits contenu dans cbds_car1 et cbds_car2 en 1 nombre hexa ; contenu dans cbds_car2 ; entrée et sortie en banque 2 ;----------------------------------------------------------------------------- cbds_ashex

57

; convertir premier digit ; ----------------------- movlw -0x07 ; écart entre lettre et chiffre btfsc cbds_car1,6 ; tester si code ASCII = 4x addwf cbds_car1,f ; oui, soustraire 7 du code ASCII movlw -0x30 ; 30 à soustraire addwf cbds_car1,f ; obtenir valeur

; convertir second digit ; ---------------------- movlw -0x07 ; écart entre lettre et chiffre btfsc cbds_car2,6 ; tester si code ASCII = 4x addwf cbds_car2,f ; oui, soustraire 7 du code ASCII movlw -0x30 ; 30 à soustraire addwf cbds_car2,f ; obtenir valeur ; concaténation ; ------------- swapf cbds_car1,w ; charger digit fort swappé iorwf cbds_car2,f ; ajouter au digit faible RET ; et fin Je vais également détailler le mécanisme, car il y a fort à parier qu’un jour ou l’autre vous aurez besoin de pareilles routines dans une de vos applications. Imaginons que nous recevions les caractères « 4 » et « C », destinés à nous envoyer une valeur hexadécimale. Les 2 octets que nous allons recevoir sont donc, suivant la table ASCII : Car1 : 0x34 Car2 : 0x43 On commence par tester si le bit 6 du caractère reçu vaut 1. Si oui, il s’agit d’un chiffre de A à F, et donc on retire 7 (autrement dit, on ajoute –7). Attention, il ne faut pas utiliser l’instruction sublw, qui ne retire pas 7 de w, mais qui retire w de 7. C’est pourquoi j’utilise une addition de la valeur –7, ce qui équivaut à une soustraction de 7 (vous suivez toujours ?).

On obtient donc : Car1 : bit 6 vaut 0, donc Car1 inchangé = 0x34 Car2 : bit 6 vaut 1, donc Car2 = 0x43 – 7 = 3C. Il reste maintenant à soustraire 0x30 de chaque caractère, ce qui donne : Car1 = 0x34 – 0x30 = 0x04 Car2 = 0x3C – 0x30 = 0x0C. On aurait également pu faire un masque pour ne conserver que les seconds quartets. On « swappe » ensuite le premier caractère, ce qui nous donne 0x40, et on le fusionne avec une instruction « ou » avec le second, ce qui donnera au final 0x4C, qui est bien la valeur dont nous avions besoin. Sachez qu’il y a des tas d’autres façons de procéder, si ça vous intéresse, vous pouvez en imaginer d’autres. Voyons maintenant la pseudo sous-routine qui attend la fin de l’activité sur la pin RB6 :

58

;***************************************************************************** ; Attendre fin du trafic RS232 * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Attend que le PC n'émette plus avant de sortir ; ON effectue 20 mesures à intervalles d'un demi-bit. Si toutes valident le ; repos, alors on sort ; on entre sur n'importe quelle banque et on sort sur la banque 2 ;----------------------------------------------------------------------------- cbds_endrec movlw D'20' ; pour 20 lectures movwf cbds_cmptb ; dans compteur cbds_endrecl btfss RXPIN ; lire si pin entrée est au repos goto cbds_endrec ; non, on recommence cbdsT CBDS_1B/2 ; tempo d'une durée d'1/2 bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto cbds_endrecl ; pas dernière lecture, suivante RET ; pas de réception en cours Que fait-on dans cette routine ? Tout simplement, on s’assure, à intervalle d’un demi-bit, que la ligne RB6 reste bien à l’état haut pendant une durée supérieure à la durée d’un octet, augmenté d’un temps de sécurité correspondant à l’écart réaliste maximum présumé entre la réception de 2 octets. Autrement dit, si on entre dans cette routine alors que rien n’est en cours de réception, on attendra un temps équivalant à 10 bits avant de décréter qu’il n’y a plus d’activité sur RB6. Toute activité (réception d’un octet) impose de nouveau une durée d’attente sans activité de 10 bits (20 demi-bits). On reste bloqué dans cette routine durant tout le temps qu’il faudra à la ligne RB6 pour cesser de recevoir des informations. Intéressons- nous maintenant à l’émission d’un octet sur RB7 : ;***************************************************************************** ; Envoi d'un octet * ;***************************************************************************** ;----------------------------------------------------------------------------- ; envoie l'octet contenu dans w ; on entre en banque2, on sort en banque2 ;----------------------------------------------------------------------------- cbds_send

; envoyer start-bit ; ----------------- movwf cbds_byte ; sauver octet à envoyer bcf STATUS,RP0 ; repasser en banque 2 bcf TXPIN ; générer start-bit cbdsT CBDS_1B ; attendre 1 bit movlw 0x08 ; 8 bits à envoyer movwf cbds_cmptb ; dans compteur de bits nop ; 1 cycle en plus

; envoyer 8 bits de data ; ---------------------- cbds_sl rrf cbds_byte,f ; lire bit poids faible btfss STATUS,C ; tester si bit = 0

59

bcf TXPIN ; oui, envoyer 0 btfsc STATUS,C ; tester si bit = 1 bsf TXPIN ; oui, envoyer 1 cbdsT CBDS_1B ; attendre durée d'un bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto cbds_sl ; pas dernier, suivant

; envoyer stop-bit ; ---------------- nop ; attendre fin délai bit 7 nop nop nop nop nop bsf TXPIN ; générer stop-bit cbdsT CBDS_1B5 ; attendre 1,5 bit par précaution RET ; et sortir Nous allons commencer par la boucle qui envoie les 8 bits en séquences. Si vous démarrez de la ligne surlignée en vert, la macro de temporisation, vous avez en nombre de cycles : decfsz : 1 cycle, car on ne saute que lorsque c’est fini goto : 2 cycles rrf : 1 cycle btfss + bcf : toujours 2 cycles, comme expliqué pour la macro de réception btfss + bsf : toujours 2 cycles cbdsT : 1 cycle, comme expliqué pour la macro de réception Soit un total de 9 cycles. Ceci explique le « nop » que nous avons du ajouter à notre routine de réception, pour que les macros de temporisation soient identiques pour émission et réception (ceci explique de nouveau le « -9 » du calcul de CBDS_1B) Vous constatez qu’on ne fait que simplement décaler l’octet à envoyer, le bit qui « tombe » dans le carry, sera le bit envoyé. Intéressons-nous maintenant à la génération de notre start-bit :

Une fois le start-bit positionné (RB7 = 0), il doit durer également 1 bit. Si vous comptez à partir de la routine de temporisation (en bleu), vous vous apercevez que la fin du start-bit sera donnée au moment de l'exécution de la ligne bsf (RB7 repasse à 1).

Si vous comptez les cycles, vous en compterez également 9, ce qui explique le « nop »

présent. Notez que si le premier bit qui suit le start-bit vaut 0, on ne verra pas la fin du start-bit, mais sa durée sera exacte, puisque 9 cycles séparent son début de la routine de temporisation en vert, qui compte la durée du bit suivant.

60

Notez que j’ai poussé à l’extrême le calcul des cycles, mais c’est la seule vraie façon de procéder. Si nous nous intéressons à la génération du stop-bit (RB7 = 1), nous comptons le nombre de cycles que doit durer le bit 7 (dernier émis). Comme la boucle ne sera pas réalisée pour ce bit, nous comptons, à partir de la routine de temporisation en vert : decfsz : 2 cycles, car on ne traitera pas le goto nop : 6 nop, donc 6 cycles bsf : 1 cycle. Donc, de nouveau, grâce aux « nop », on aura une durée égale à la durée de temporisation plus 9 cycles. La durée du stop-bit doit être égale à 1 bit, mais, comme il n’est pas interdit d’introduire une pause entre l’émission de 2 octets, et que, d’autre part, il se peut qu’on obtienne une légère erreur, on générera un stop-bit d’une longueur approximative de 1.5 bit. Ainsi, on se met à l’abri de tout problème. La réception d’un octet va être très simple, puisqu’une partie de son code a déjà été écrite dans la macro RECEIVE : ;***************************************************************************** ; Réception d'un octet * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Reçoit un octet, le retourne dans cbds_byte ; On entre en banque 2, on sort en banque 2 ;----------------------------------------------------------------------------- cbds_rec RECEIVE ; reçoit 1 octet movlw 0x0A ; valeur de line-feed xorwf cbds_byte,w ; comparer avec octet reçu btfsc STATUS,Z ; tester si identique goto cbds_err ; oui, alors erreur RET ; retour Notez ici que, si j’ose m’exprimer ainsi, l’avantage de l’inconvénient de nos pseudo sous-routines. En effet, si on détecte un caractère de fin de message au lieu du caractère « normal » attendu, on saute dans la routine d’erreur, sans devoir exécuter le RET. Ceci est rendu possible par le fait qu’on n’a pas empilé l’adresse de retour sur la pile, et donc que rien ne nous oblige à dépiler, donc à exécuter de return. On peut donc ici revenir de la sous-routine à un endroit différent de la ligne de l’appel, sans que cela pose le moindre problème. Je ne vais pas me gêner pour profiter de cet avantage. Cette routine ne fait rien d’autre que de recevoir un octet dans cbds_byte (voir macro), et de revenir si tout s’est bien passé. Si par contre, l’octet reçu indique une fin prématurée du message reçu, on enverra le message [ERR] Il nous reste à détecter les 2 octets de fin de message. Ces octets sont 0x0D et 0x0A. Si on reçoit autre chose alors que le message est sensé être reçu complètement, on attendra la fin de la réception de ces données, puis on enverra le message [ERR]

61

;***************************************************************************** ; RECEPTION DE FIN DE MESSAGE * ;***************************************************************************** ;----------------------------------------------------------------------------- ; teste si on reçoit 0x0D puis Ox0A ; Si oui, retour, sinon, erreur ;----------------------------------------------------------------------------- cbds_end RECEIVE ; reçoit 1 octet movlw 0x0D ; valeur de return xorwf cbds_byte,w ; comparer avec octet reçu btfss STATUS,Z ; tester si identique goto cbds_err ; non, alors erreur RECEIVE ; reçoit 1 octet movlw 0x0A ; valeur de line-feed xorwf cbds_byte,w ; comparer avec octet reçu btfss STATUS,Z ; tester si identique goto cbds_err ; non, alors erreur RET ; retour END ; directive fin de programme On termine bien entendu par la directive de fin de programme.

Lancez l’assemblage par <F10>. Vous allez avoir pleins de warnings, étant donné que vous travaillez sans arrêt en banque2. De plus, en début de la fenêtre de résultat, vous serez gratifié d’un warning qui vous prévient que votre « goto » placé à l’adresse 0x2004, se situe hors de la zone d’adressage du processeur.

Comme, à terme, ce programme sera destiné à être intégré dans les programmes à

debugger, ces messages risquent d’être gênants. Nous allons donc utiliser une directive de MPASM®.

Cette directive se nomme « errorlevel ». Elle permet de définir quels sont les messages

dont vous autorisez ou n’autorisez pas l’affichage. Chaque « warning » est accompagné d’un numéro qui le caractérise. Examinons les 2 premiers messages de notre fenêtre de résultat : Warning[220] chemin\DEBUG.ASM 63 : Address exceeds maximum range for this processor. Message[302] chemin\DEBUG.ASM 231 : Register in operand not in bank 0. Ensure that bank bits are correct. Vous constatez que le warning de l’adresse est un warning « 220 », et que tous les warnings de banque sont des warnings « 302 ». Il n’est pas question d’interdire les autres messages (dont nos messages d’alerte en cas de problème de débit), mais nous allons interdire spécifiquement ces 2 types de warnings. La directive « errorlevel » peut être suivie du signe « - », puis du numéro du warning dont vous ne désirez pas l’affichage. Entrez donc les 2 lignes suivantes au début de votre programme, juste après la directive « _CONFIG » : errorlevel -302 ; supprime les warnings de banque errorlevel -220 ; supprime le warning d'adresse

62

Relancez l’assemblage, plus de warnings. Maintenant, allez tout en fin de programme, et, juste avant la directive « END », remettez les warnings en service en utilisant le signe « + » errorlevel +302 ; relance les warnings de banque errorlevel +220 ; relance le warning d'adresse Ceci est indispensable, car, lorsque nous intégrerons la routine de debuggage dans notre programme à debugger, il ne s’agira pas de nous cacher les warnings de notre programme à debugger. Nous ne verrons donc que ceux de notre programme principal, et non ceux de notre routine de debuggage (à l’exception des messages volontairement envoyés). Nous allons procéder à quelques essais concernant ces messages. Editez la ligne concernant BAUDRL, et entrez la valeur « 13 » : BAUDRL EQU D'13' ; Augmenter permet de diminuer le débit Relancez l’assemblage, vous voyez maintenant le message : Message[301] chemin\DEBUG.ASM 87 : MESSAGE: (Erreur de baudrate trop importante) Message[301] chemin\DEBUG.ASM 88 : MESSAGE: (Essayez de modifier la valeur de BAUDRL) En effet, avec les 13 nop que nous venons d’ajouter dans la routine de temporisation, il n’est plus possible d’obtenir (suite à la division par 16) une valeur suffisamment précise. Remettez BAUDRL à 0, et modifiez la valeur du quartz à 100Khz : FQUARTZ EQU D'100000' ; fréquence quartz Lancez l’assemblage, vous obtenez : Message[301] chemin\DEBUG.ASM 72 : MESSAGE: (Impossible d'établir le débit, diminuez BAUDRL) Message[301] chemin\DEBUG.ASM 73 : MESSAGE: (Si déjà à 0, diminuez le débit) Il est donc impossible d’obtenir une communication à 19200 bauds avec une fréquence de quartz de 100Khz. Remettez la fréquence à 20Mhz, et baissez le débit à 9600 bauds : FQUARTZ EQU D'20000000' ; fréquence quartz BAUDR EQU D'9600' ; débit en bauds Vous obtenez : Message[301] chemin\DEBUG.ASM 77 : MESSAGE: (Augmentez le baudrate,modifiez la routine de temporisation) Message[301] chemin\DEBUG.ASM 78 : MESSAGE: (ou augmentez la valeur de BAUDRL)

63

Le débit est donc trop faible pour la vitesse du quartz. Qu’à cela ne tienne, il suffit d’augmenter BAUDRL pour insérer des « nop » supplémentaires. Entrez donc : BAUDRL EQU D'5' ; Augmenter permet de diminuer le débit Relancez l’assemblage, plus d’erreur, tout est OK. Vous voyez que ce programme est pensé pour être universel. Replacez les valeurs d’origine : FQUARTZ EQU D'20000000' ; fréquence quartz BAUDR EQU D'19200' ; débit en bauds BAUDRL EQU D'0' ; Augmenter permet de diminuer le débit Programmez votre PIC® avec ce fichier.

64

5. La partie hardware 5.1 L’interface BIGOPIC2 J’avais voulu utiliser pour notre debugger l’interface utilisée pour le bootloader. Il s’avère que cette interface rencontre un problème sur pas mal de PC dans son fonctionnement dans ce mode. En effet, l’impédance de la ligne RS232 assez élevée fait que, lorsqu’on envoie un bit à 0 (donc +12V) sur la ligne TD, ceci provoque une remontée du niveau de la ligne RTS, via D4,R3,U3. Ceci peut donc provoquer la réception inopinée d’un start-bit sur la ligne RD, en empêchant le forçage à –12V via U2. En mode booloader, ceci n’avait pas d’importance (quoi que si sur certains PC), puisque nous recevions simultanément ce que nous émettions. Ici, cependant, ce n’est pas le cas.

L’interface risque donc de nous gratifier d’erreurs, même si, dans le debugger DTRA, cette interface fonctionne la plupart du temps correctement. Il n’en sera pas de même dans le debugger CBDS. Aussi, puisque nous ne rencontrons pas de problème d’isolation galvanique (puisque, sur une carte en cours de debuggage, on peut éliminer toute tension dangereuse, vu qu’on ne se trouve pas « sur site), j’en reviens à un schéma plus classique. Pour le bootloader, gardez la préférence au schéma précédemment étudié, car l’opto-isolation reste indispensable pour une utilisation sur site. Si, cependant, vous rencontrez des problèmes avec l’interface1, utilisez l’interface 2, quitte à la modifier pour y ajouter des optocoupleurs.

65

Attention, je rappelle que ce montage ne peut être utilisé que sur une platine d’application non reliée au secteur. Il vous incombe de prendre toutes les mesures de sécurité utiles, partant du fait que la masse de votre PC et de l’interface sont reliées à la masse de votre platine d’application. Une fois de plus, l’interface nécessaire se résume à bien peu de choses. Vous disposez de plus déjà du matériel, que vous avez utilisé dans la seconde partie du cours lors de l’étude du chapitre sur les liaisons série asynchrones. 5.2 Réalisation des sondes Nous allons maintenant passer à la réalisation des sondes. Pour pouvoir communiquer avec notre PIC®, nous insérerons celui-ci sur le support de la sonde, celle-ci étant elle-même placée dans le support du PIC® sur la carte d’application. De cette façon, nous pouvons utiliser notre debugger sur toutes les platines, sans devoir prévoir explicitement son utilisation, et sans devoir adapter la carte d’application. Passons donc à la réalisation pratique de la sonde pour 16F876(A). Comme d’habitude, il s’agira d’une réalisation économique.

66

Commencez par prendre un support 28 pins (de type « tulipe ») pour le PIC16F876(A). Coupez les pins 1, 27, et 28 de ce support, en ne laissant que la longueur nécessaire pour effectuer une soudure (coupez la partie la plus fine).

Insérez ce support, soit dans un autre support dont vous aurez coupé le morceau correspondant de chaque côté, soit dans 2 barrettes sécables en support tulipe. Voici ce que cela donne :

Une fois le support inséré sur les barrettes sécables, ou sur le support coupé, vous obtenez ceci :

Soudez ensuite les 5 fils qui viennent du connecteur pour contacts à barrettes de l’interface BIGOPIC2. Faites-les passer par le milieu du support. Vous obtenez ceci :

Il vous reste à figer tout ça par un peu de silicone ou de colle. Ajoutez un nouveau support 28 pins au dessous du tout (c’est-à-dire au dessus, lorsque vous regardez de la façon précédente).

67

Et vous voici en possession d’une superbe sonde low-cost. Vous n’avez plus qu’à placer la sonde à la place du PIC® dans votre carte d’application, et à placer le PIC® contenant le programme dans le support supérieur de la sonde. Vous pouvez alors debugger en temps réel. Je présume que vous pourrez faire la sonde pour 16F877 sans moi ? Les noms des pins restent identiques (Mclr, Vdd, Vdd, RB6,RB7). Seuls changent les brochages. Pour Vdd et Vss, vous choisissez chaque fois une des 2 pins disponibles, elles sont sensées être interconnectées sur votre platine d’application, et, de toutes façons, le sont à l’intérieur du PIC®. Il ne vous reste plus qu’à insérer votre connecteur dans l’interface BIGOPIC2.

68

6. Vérification du fonctionnement de l’ensemble 6.1 introduction Nous allons maintenant vérifier que tout fonctionne comme prévu. La première étape est de placer notre PIC® avec sa sonde sur une platine de test, et vérifier que l’ensemble communique correctement. Il est important de comprendre qu’à ce stade nous testons le programme de debuggage comme un programme classique. Nous ne sommes donc pas en train d’exécuter un debuggage. 6.2 Le schéma Nous allons utiliser le schéma de base d’une application à base de PIC16F876, c’est-à-dire un schéma qui n’utilise rien du tout, simplement pour vérification.

6.3 L’interconnexion Maintenant, nous allons interconnecter tout ça, comme pour un debuggage réel.

69

Au niveau du PIC®, vous avez un sandwich, composé, en partant du bas : - Du support pour PIC® de la platine PIC® - De la sonde constituée des 3 supports superposés - Du PIC®

Si en plus, comme moi, lors de la phase de debuggage, vous placez votre PIC® sur un support supplémentaire pour ne pas l’abîmer, cela vous donne une hauteur de 5 supports plus le PIC®. Rassurez-vous, ceci ne pose aucun problème.

Si ce n’est pas encore fait, allez sur mon site charger le logiciel BIGOPIC light et installez-le. Les explications que je donne ici sont relatives à la version light. La version pro fonctionne également sans problème avec le debugger DTRA. Lancez l’alimentation du montage, lancez BIGOPIC_light, et allez dans le menu « mode » pour placer le logiciel en mode « DTRA ».

70

Je ne reviens pas en détails sur l’utilisation de BIGOPIC light, voyez, pour ceci, la troisième partie du cours. Je vais simplement expliquer ce qui concerne ce mode particulier. Vous notez que vous disposez de 2 fenêtres, librement redimentionnables et positionnables. Vous pouvez par exemple, si vous le désirez, les placer une au dessous de l’autre, au lieu de côte à côte. Les paramètres seront conservés à la prochaine ouverture. Je vous rappelle que pour revenir aux réglages par défaut, il suffit de quitter le programme, puis d’effacer le fichier « BIGOPICl.cfg » présent dans votre répertoire d’installation (BIGOPICp.cfg pour la version pro). La fenêtre « Depuis le PIC® » affiche le contenu ASCII de ce qu’envoie le PIC®. Cette fenêtre dispose d’un seul bouton : <Effacer>, qui, comme son nom l’indique, permet d’effacer le contenu de cette fenêtre. La fenêtre « Vers le PIC® » est la fenêtre dans laquelle vous allez taper les caractères qui seront envoyés au PIC®. Tous les dialogues, dans ce mode, se font en ASCII, il n’est pas possible d’envoyer ou de recevoir des valeurs hexadécimales. J’ajouterai éventuellement une fonction ultérieurement. Cette fenêtre comprend au maximum 4 boutons. Le premier est le bouton <Effacer> qui permet d’effacer le contenu de la fenêtre d’envoi.

71

Ensuite, nous trouvons un bouton intitulé <Envoi continu>. Si l’envoi continu est en service, les 2 boutons inférieurs disparaissent. Dans ce mode, tout caractère tapé dans la fenêtre est envoyé au fur et à mesure de la frappe. Si vous n’êtes pas en mode d’envoi continu, l’envoi ne s’effectuera qu’une fois le bouton <Envoyer> ou <Envoyer + effacer> sera pressé. Ces 2 boutons se distinguent par leur mode de fonctionnement. Tous deux envoient l’intégralité de ce qui se trouve dans la fenêtre, et non la dernière ligne tapée. Le premier envoie simplement le contenu, tandis que le second efface la fenêtre après l’envoi, permettant d’entrer une nouvelle commande. Nous allons travailler dans cet exercice en mode « envoi continu ». Pressez donc le bouton correspondant, les 2 boutons inférieurs disparaissent. Naturellement, dans ce mode, impossible de corriger une erreur de frappe, puisque les caractères sont envoyés dès leur frappe. La pression de la touche <Return> envoie 2 octets vers le PIC®, à savoir 0x0D (retour chariot), suivi de 0x0A (passage à la ligne).

72

Configurez maintenant le port série (icône « ? »). Réglez le numéro de votre port, le débit de 19200 bauds, pas de parité, 1 stop-bit, 8 bits de donnée. Connectez le port série (première icône, qui représente alors 2 fiches jointes), puis effectuez un reset en cliquant sur l’icône « R ». Si tout s’est bien passé, que votre interface fonctionne et que le programme est correctement chargé, vous obtenez quelque chose comme ceci :

Les valeurs des registres peuvent être différentes, ce n’est pas important. Vous voyez que DTRA vous a renvoyé les informations suivantes : [DTRA] :0000 ; Le debugger est en service, pas de mode « S », pas de mode « F », adresse

de break 0000 Pour pouvoir nous y retrouver, je surligne en jaune ce que vous tapez (fenêtre de droite), et en vert ce que le PIC® envoie (fenêtre de gauche). Les valeurs entre <> sont des touches ou des boutons à presser.

73

Remarquez simplement que l’adresse de break est : « 0000 », ce qui est normal, puisque nous ne sommes pas en mode debuggage (nous simulons), et donc, notre PIC® ne peut accéder aux registres de debuggage, disponibles seulement en mode debuggage. Ces registres sont donc lus comme étant toujours à « 0x00 ». Voici les valeurs renvoyées des registres tels qu’ils étaient au moment de l’entrée dans la routine de debuggage : W:EF ; registre « W » = 0xEF STA :A1 ; registre « STATUS » = 0xA1 FSR :02 ; registre FSR = 0x02 INT :01 ; registre INTCON = 0x01 PIR1 :00 ; registre PIR1=0x00 PIR2 :00 ; registre PIR2=0x00 Nous allons maintenant commencer le dialogue. Dans la fenêtre de saisie, tapez : R001<RETURN>

Ceci équivaut à demander le contenu du registre à l’adresse 0x00, qui est TMR0 (le timer 0). Le PIC® vous répond : FF Autrement dit : le timer contient la valeur 0xFF. Un œil sur le datasheet (tableau 2-1 page 15) vous montre que le contenu de ce registre est indéterminé au démarrage. Et bien, cette indétermination vaut 0xFF sur le PIC® que j’ai utilisé. Je constate de plus qu’à chaque mise sous tension, cette valeur est la même. Il se peut que la valeur soit différente chez vous, vous ne vous inquiéterez pas, si vous avez compris ce qui précède.

Notez ici une différence très importante entre le simulateur et l’émulateur ou le debugger. Dans le simulateur MPLAB®, le timer vaudrait 0x00, ainsi que emplacement d’une variable. Puisque le contenu est indéterminé, MPLAB® y place la valeur 0x00 par défaut.

Ici, vous lisez la valeur véritable contenue dans votre propre PIC®. Aussi, si vous oubliez

d’initialiser une variable, vous ne le verrez pas dans le simulateur, mais vous le verrez parfaitement ici. Vous pouvez même comparer les différences de contenu entre différents PIC® lors de la mise sous tension. Tapez ensuite : M001,55<RETURN>

74

Vous demandez donc la modification de TMR0, et indiquez que vous voulez que sa valeur devienne 0x55. Le PIC® vous répond : 55 Qui est la valeur lue par le PIC®. Tapez, pour vérification, R001<RETURN>. Le PIC® vous répond : 55 Tapez une seconde fois R001 <RETURN>. 55

Le PIC® vous répond de nouveau par la valeur 55. Vous pensez que cette seconde manipulation est évidente, mais, si vous réfléchissez, ceci vous indique que votre timer0 est à l’arrêt. Si vous consultez le datasheet, vous constatez que, à la mise sous tension, le registre OPTION_REG vaut 0xFF. Vérifions-le en tapant . R081<RETURN> FF Or, cela signifie que le bit TOCS vaut « 1 », autrement dit, le timer0 est placé en mode compteur, et donc est à l’arrêt en tant que timer, puisque la pin RA4/TOCKI n’est pas connectée dans cette application. Nous allons donc mettre le timer en service, avec un prédiviseur de 1, ce qui s’effectue en écrivant, par exemple, B’00001000’ dans OPTION_REG. Tapez donc M081,08<RETURN> 08 Examinons maintenant le contenu de notre timer0 en tapant R001<RETURN> 10 (par exemple). Tapez plusieurs fois R001<RETURN>, et vous verrez que le PIC® répond chaque fois avec une valeur différente : le timer0 fonctionne maintenant en mode timer. Vous devez maintenant vous trouver avec une fenêtre du type :

75

Nous venons de vérifier que nous sommes capables de lire et de modifier un registre dans l’emplacement RAM disponible. Si vous tapez « S » ou « F », vous vous apercevrez que l’état des bits ne change jamais, et pour cause, le registre ICKBUG n’est pas accessible. La commande « G », qui va exécuter un « return », alors que nous n’avons aucun appel de sous-programme, va provoquer un redémarrage du PIC® (nouveau message de bienvenue). Testez ceci en tapant « G ».

Voici le genre d’expérimentation que ne permet pas le simulateur de MPLAB®. Autrement dit, un return reçu alors que la pile est vide, renvoie à l’adresse 0x00. Intéressant, non ? Je vous déconseille tout de même d’utiliser ceci en pratique dans vos programmes, rien ne garantit que ce fonctionnement est permanent, et, du reste, ça ne présente aucun intérêt.

76

7. Création de la routine de debuggage 7.1 Pourquoi ? C’est la question que vous allez probablement poser. En fait, il faut vous souvenir que nous venons d’utiliser DTRA en temps que programme autonome, exécuté en mode normal de fonctionnement, ce qui ne présente aucun intérêt. En effet, ce qui nous intéresse, c’est d’obtenir un fichier d’inclusion à intégrer dans nos programmes à debugger, et de travailler en mode debuggage. Voyons donc comment procéder. 7.2 Le programme devient routine Maintenant que notre programme semble fonctionner, nous allons donc le modifier afin de l’utiliser réellement comme routine de debuggage. Effectuez une copie de votre fichier « dtra.asm », et nommez cette copie « dtra.inc ».

Editez le fichier à l’aide d’un éditeur (par exemple, celui de MPLAB®, en sélectionnant « file->open » avec « type de fichiers = *.inc ». Une fois ouvert, analysons notre fichier. La première chose à faire est de supprimer les lignes suivantes : LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC En effet, ces lignes feront partie de notre programme à debugger, il ne faut donc pas les répéter ici. Maintenant, nous allons placer un « ; » devant les assignations des valeurs de débit et de fréquence. Ces paramètres seront précisés dans le programme à debugger, puisqu’ils dépendent de l’application concernée. En principe, si vous n’avez tenté aucune expérience à ce niveau, ceci devrait déjà être fait, excepté pour l’adresse. ;FQUARTZ EQU D'20000000' ; fréquence quartz ;BAUDR EQU D'19200' ; débit en bauds ;BAUDRL EQU D'0' ; Augmenter permet de diminuer le débit et

; modifier le taux d'erreur. Conserver la plus ; faible valeur possible. Ne pas dépasser D'13'

;CBDS_HIGH EQU 1 ; utilisation de la zone 0x160/0x16F ;DBGADD EQU 0x1B90 ; adresse du bootloader

En procédant de la sorte, si vous oubliez la syntaxe, il vous suffira de jeter un œil dans votre fichier « debug.inc ».

77

Il nous reste à effacer la directive END en fin de notre routine : END ; directive fin de programme Il nous faut encore expliquer pourquoi j’ai mis 0x1B90 comme adresse de chargement par défaut de notre debugger. Comme nous le placerons tout en haut de la mémoire, il nous faut déterminer la place qu’il occupe. Plaçons tout d’abord, dans debug.asm, la valeur D’5’ pour BAUDRL, de cette façon, nous allongeons la taille de notre programme au maximum. BAUDRL EQU D'5' ; Permet de diminuer le taux d'erreur

Lançons donc l’assemblage de notre « debug.asm », et regardons dans la mémoire programme (windows->program memory). Faites défiler le programme, et vous constatez que celui-ci s’arrête en adresse D’1134’, ou 0x46D.

En effet, directement après, vous trouvez les 0x3FF qui indiquent une mémoire inutilisée.

Arrondissons donc à 0x470, ce qui indique que, la zone programme se terminant à l’adresse 0x1FFF, nous pourrons charger notre routine à l’adresse 0x2000-0x470 = 1B90. Voici donc l’origine de cette valeur. Attention, si vous voulez utiliser un autre type de PIC®, contenant moins de mémoire (16F873), il vous faudra changer cette valeur. De même si vous voulez debugger un programme qui utilise déjà cette portion de mémoire. Attention cependant que vous devez toujours placer votre routine de debuggage dans la dernière page existante du PIC® utilisé. Je vous rappelle que cette contrainte n’est pas de mon fait, elle est imposée par la conception même du PIC®. Sauvez le fichier « debug.inc » obtenu, la routine de debuggage est terminée. Maintenant, vous disposez d’une routine capable de debugger tous les programmes d’une taille inférieure à 7K, ce qui n’est pas mal (en avez-vous déjà créé de pareils ?). Exceptés la non utilisation de RB6 et RB7, ainsi que de 18 emplacements en RAM, vous n’avez pas d’autres contraintes théoriques. Vous verrez cependant qu’on peut faire beaucoup mieux. Mais, pas d’impatience.

78

8. Notre premier vrai debuggage en temps réel 8.1 Création du premier programme Bon, nous allons commencer par créer un programme à debugger. Créez un nouveau projet, dénommé « Led_tmrD », et créez le fichier « Led_tmrD.asm » suivant. Il est joint au cours sous la dénomination « Led_tmrD1.asm » pour vous éviter de le taper, n’oubliez pas le suffixe « 1 ». Le plus simple est donc d’effectuer une copie de « Led_trmD1.asm » et de renommer cette copie en « Led_trmd.asm ». ;***************************************************************************** ; Exercice pour l'utilisation du debugger temps réel * ; On inclus le debugger au programme original * ; Le programme principal fait clignoter une LED sur RB0 * ; La routine de debuggage est en adresse 0x1E0, la valeur placée à * ; l'adresse 0x2004 du PIC sera donc : 0x2E00 * ;***************************************************************************** ; NOM: Led_tmrD * ; Date: 12/08/2002 * ; Version: 1.0 * ; Circuit: interface BIGOPIC * ; Auteur: Bigonoff * ;***************************************************************************** ; Fichiers requis: P16F876.inc * ; Debug.inc * ;***************************************************************************** LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ;***************************************************************************** ; ASSIGNATIONS SYSTEME * ;***************************************************************************** ; REGISTRE OPTION_REG (configuration) ; ----------------------------------- OPTIONVAL EQU B'10100111' ; RBPU b7 : 1= Résistance rappel +5V hors service ; PS2/PS0 b2/b0 valeur du prédiviseur ; 111 = 1/256 ;***************************************************************************** ; DEFINE * ;***************************************************************************** #DEFINE CMPTVAL D'35' ; valeur de recharge du compteur ;***************************************************************************** ; VARIABLES BANQUE 0 * ;***************************************************************************** ; Zone de 80 bytes ; ---------------- CBLOCK 0x20 ; Début de la zone (0x20 à 0x6F) cmpt : 1 ; compteur de passage

79

ENDC ; Fin de la zone ;***************************************************************************** ; VARIABLES ZONE COMMUNE * ;***************************************************************************** ; Zone de 16 bytes ; ---------------- CBLOCK 0x70 ; Début de la zone (0x70 à 0x7F) w_temp : 1 ; Sauvegarde registre W status_temp : 1 ; sauvegarde registre STATUS FSR_temp : 1 ; sauvegarde FSR (si indirect en interrupt) PCLATH_temp : 1 ; sauvegarde PCLATH (si prog>2K)

ENDC ; //////////////////////////////////////////////////////////////////////////// ; I N T E R R U P T I O N S ; //////////////////////////////////////////////////////////////////////////// ;***************************************************************************** ; DEMARRAGE SUR RESET * ;***************************************************************************** org 0x000 ; Adresse de départ après reset goto init ; Initialiser ;***************************************************************************** ; ROUTINE INTERRUPTION * ;*****************************************************************************

;sauvegarder registres ;--------------------- org 0x004 ; adresse d'interruption movwf w_temp ; sauver registre W swapf STATUS,w ; swap status avec résultat dans w movwf status_temp ; sauver status swappé

; Interruption TMR0 ; ----------------- BANKSEL 0x0 ; passer en banque 0 decfsz cmpt , f ; décrémenter compteur de passages goto restorereg ; pas 0, on ne fait rien movlw B'00000001' ; sélectionner bit à inverser xorwf PORTB , f ; inverser LED movlw CMPTVAL ; pour CMPTVAL nouveaux passages movwf cmpt ; dans compteur de passages

;restaurer registres ;------------------- restorereg swapf status_temp,w ; swap ancien status, résultat dans w movwf STATUS ; restaurer status swapf w_temp,f ; Inversion L et H de l'ancien W swapf w_temp,w ; Réinversion de L et H dans W retfie ; return from interrupt ; //////////////////////////////////////////////////////////////////////////// ; P R O G R A M M E ; //////////////////////////////////////////////////////////////////////////// ;*****************************************************************************

80

; INITIALISATIONS * ;***************************************************************************** init

; initialisation PORTS (banque 0 et 1) ; ------------------------------------ BANKSEL PORTB ; sélectionner banque0 clrf PORTB ; sorties PORTB à 0 bsf STATUS,RP0 ; passer en banque1 bcf TRISB,0 ; RB0 en sortie

; Registre d'options (banque 1) ; ----------------------------- movlw OPTIONVAL ; charger masque movwf OPTION_REG ; initialiser registre option

; registres interruptions ; ----------------------- bsf INTCON,T0IE ; autoriser interruptions timer0

; initialiser variable ; -------------------- bcf STATUS,RP0 ; passer banque 0 movlw CMPTVAL ; charger valeur d'initialisation movwf cmpt ; initialiser compteur de passages

; autoriser interruptions ; ----------------------- bsf INTCON,GIE ; valider interruptions goto start ; programme principal ;***************************************************************************** ; PROGRAMME PRINCIPAL * ;***************************************************************************** start nop ; pour debugger goto start ; boucler END ; directive fin de programme Placez alors, sur la platine précédemment utilisée, une LED, munie de sa résistance, sur la pin RB0 de votre PIC®. Vous voyez que vous n’avez pas à tenir compte du debugger lors de la conception de la platine. C’est logique, puisque ce debugger, contrairement au bootloader, ne sera utilisé que lors de la phase de debuggage de votre programme. Bien entendu, les pins RB6 et RB7 ne sont pas connectées au montage d’application, du fait de la sonde. C’est une limitation du debugger intégré, il vous faudra donc bien supporter cet inconvénient, quitte à utiliser une autre pin dans votre programme, si la fonction d’une de celles-ci était indispensable durant la phase de debuggage.

81

Assemblez votre fichier, placez le dans votre PIC®, celui-ci sur la platine, lancez l’alimentation, et votre LED clignote à la fréquence de 1Hz….

Ah ben tiens non, rien ne se passe ? Evidemment, je n’allais pas vous fournir à debugger un programme qui fonctionne, c’était

bien trop simple, et dépourvu d’intérêt. Nous allons donc utiliser notre debuggage en temps réel, en dialoguant simplement en ASCII avec DTRA Comment utiliser notre debugger ? Simple : il suffit d’abord d’inclure notre routine de debuggage dans notre programme à debugger. Ajoutons donc simplement la ligne suivante, directement après la directive _CONFIG. #include <dtra.inc> ; insère la routine de debuggage. Ensuite, modifiez la directive _CONFIG, de façon à : - Stopper le watchdog éventuel (_WDT_OFF) - Mettre le debugger en service (_DEBUG_On)

82

__CONFIG _CP_OFF & _DEBUG_ON & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC C’est tout ce que vous avez maintenant à faire pour pouvoir debugger en temps réel, ajouter cette simple ligne dans votre programme. Difficile de faire plus simple. Une règle de bonne pratique, recommandée par Microchip®, est d’insérer une instruction « nop » comme première instruction du programme, à l’adresse 0x00. Nous allons le faire : org 0x000 ; Adresse de départ après reset nop ; première instruction = nop goto init ; Initialiser N’oubliez jamais de couper le watchdog durant le debuggage, et de placer DEBUG_ON. Sans ça, cela ne fonctionnera jamais. Une fois votre fichier debuggé, replacez DEBUG_OFF, remettez le watchdog en service si nécessaire, et supprimez la ligne « include <dtra.inc> ». C’est tout ce que vous aurez à faire, mais il faudra le faire. Lancez l’assemblage, vous obtenez alors un fichier .hex. Ce fichier contient également le « goto » à l’adresse 0x2004 vers notre routine de debuggage. Le fichier asm obtenu à ce stade se trouve dans le cours sous la dénomination « led_trmD2.asm ». Vous obtenez les messages suivants, avant vos messages habituels concernant le programme à debugger : Message[301] chemin\DTRA.INC 87 : MESSAGE: (DEBUGGER EN SERVICE, veuillez couper le watchdog) Message[301] chemin\DTRA.INC 94 : MESSAGE: (Adresse de debugger par défaut : 0x1B90) Message[301] chemin\DTRA.INC 99 : MESSAGE: (Fréquence de 20 Mhz prise par défaut) Message[301] chemin\DTRA.INC 104 : MESSAGE: (Débit de 19200 bauds pris par défaut) Message[301] chemin\DTRA.INC 168 : MESSAGE: (zones RAM 0x110/0x11F + 0x7E/0x7F réservées) Message[302] chemin\LED_TMRD.ASM 135 : Register in operand not in bank 0. Ensure that bank bits are correct. Message[302] chemin\LED_TMRD.ASM 140 : Register in operand not in bank 0. Ensure that bank bits are correct. Si vous désirez imposer des autres valeurs que celles par défaut, il suffira d’ajouter les assignations correspondantes AVANT la ligne #include . Par exemple : BAUDR EQU D’38400’ ; imposer un débit de 38400 bauds Dans ce cas, le message correspondant disparaîtra.

83

Allez chercher la dernière version d’IC_PROG sur le site de Bonny Gijzen : www.ic-prog.com 8.2 Dans le vif du sujet

Chargez le fichier « .hex » obtenu dans IC-PROG. La case « debugger » doit être cochée si vous ne vous êtes pas trompé. N ‘oubliez pas de paramètrer en fonction de votre debugger, et de choisir le PIC16F876 dans le menu déroulant. Allez avec la souris à côté des bits de configuration (à droite de la fenêtre) et cliquez sur le bouton droit. Un menu contextuel apparaît : - Edit config word - Edit debugger word

Choisissez « Edit debugger word ». Ceci vous donne accès à l’adresse 0x2004. Vous

devez y lire la valeur 0x2B90. Si vous vous souvenez de la façon dont est construite l’instruction « goto », vous verrez que ceci correspond à « goto 0x1B90 », qui est l’adresse de notre routine de debuggage. Programmez maintenant votre PIC®, avec l’option « tout programmer (program all) » Vous pouvez maintenant placer votre sonde sur la platine d’application, le PIC® dans la sonde, lancer BIGOPIC light si ce n’était pas fait. Connectez le port série, et ensuite seulement, lancez l’alimentation. Vous avez maintenant un message de bienvenue EN DIRECT DU DEBUGGER TEMPS REEL. [DTRA]:0001 W:DF STA:F1 FSR:C1 INT:01 PIR1:00 PIR2:00 Les valeurs peuvent être différentes, ce n’est pas important. Ce qu’il est intéressant de constater, c’est que l’adresse d’arrêt est maintenant 0x0001, ce qui est logique, puisque l’arrêt a été provoqué après l’exécution de la première instruction, donc le « nop » que nous avons placé en 0x00 par précaution, juste avant le « goto start ». Vérifions donc si nous sommes effectivement bien en mode debugger. Pour ceci, lisons le registre ICKBUG. R18E<RETURN> 80

84

Ce qui correspond au seul bit INBUG positionné. Nous sommes donc bien dans le mode debugger intégré. Commençons par définir l’absence de point d’arrêt à l’aide de la commande « B » avec, en paramètre, une zone située hors de notre programme principal, par exemple 0x1FFF. Attention de toujours taper les « chiffres » en majuscule (FFF et non fff). B1FFF<RETURN> [OK] Lançons maintenant notre programme principal, afin de voir clignoter notre LED. Tapons : G<RETURN> [GO] Nous sommes sorti du mode de debuggage, le programme tourne normalement, et rien ne se passe. Notre LED ne clignote pas. Il va donc falloir debugger ce programme, mais ça, nous le savions déjà. Tapez simplement <RETURN>, ce qui va provoquer plusieurs impulsions sur RB6, et donc générer un « halt ».

Notre debugger répond par son message de bienvenue, et par l’adresse qui suit celle où il a été interrompu. J’obtiens [GO][DTRA]:0022 W:23 STA:F1 FSR:D8 INT:A1 PIR1:00 PIR2:00 Donc, la prochaine instruction qui sera exécutée sera : goto start Comment le sais-je ? Rien de plus simple : Souvenez-vous que dans MPLAB®, en ouvrant la fenêtre « memory program », vous pouvez voir les correspondances entre l’adresse de la mémoire programme, et l’instruction qui s’y trouve. La seconde colonne vous donne les adresses en hexadécimal, il suffit donc de regarder ce qui correspond à l’adresse 0x22. Nous sommes donc arrêtés dans la boucle principale de notre programme. Nous allons maintenant examiner ce qui se passe dans notre routine d’interruption, et, pour ceci, nous allons positionner un point d’arrêt dans cette routine. La routine d’interruption commence à l’adresse 0x0004. Plaçons-y donc un break-point : B0004<RETURN> [OK]

85

Relançons le programme : G<RETURN> [GO] Et attendons….. En fait, nous avons beau attendre, il ne se passe rien, notre programme ne passe donc jamais par notre routine d’interruption. Voilà le problème. Voici un petit aperçu de l’état de vos fenêtres si vous n’avez pas fait d’erreur :

Commençons par déterminer quelles sont les causes possibles du non passage dans la routine d’interruption : - Le bit GIE du registre INTCON n’est pas positionné - Le bit T0IE du registre INTCON n’est pas positionné - Le timer ne compte pas.

Remarquez que le debugger vous donne accès à tout le contenu du PIC®, il ne réfléchit pas à votre place. Heureusement, car, sans ça, je n’aurais plus rien à faire ☺

86

Commençons par notre registre INTCON. Il nous faut stopper le programme : <RETURN> [CBDS]:0022 W:23 STA:F1 FSR:D9 INT:A1 PIR1:00 PIR2:00 Regardons INTCON (adresse 0x00B) : R00B <ENTER> A1 A1 donne en binaire B’10100001’. Autrement dit, sont positionnés les bits : - GIE : logique : les interruptions sont donc bien en service - T0IE : logique : l’interruption timer0 est bien en service - RBIF : logique : les variations sur RB6/RB7 de notre debugger ont provoqué la

modification de ce flag.

Donc, tout est OK au niveau de notre registre d’interruption. L’absence d’interruption ne peut donc être due qu’au fait que notre timer0 ne déborde jamais.

Examinons notre timer en effectuant plusieurs lectures :

R001<RETURN> FF R001<RETURN> FF R001<RETURN> FF Notre timer ne compte pas, voici d’où provient le problème, reste à en déterminer la cause.

Ceci ne peut être du qu’à une erreur dans la configuration du bit T0CS du registre OPTION_REG. Notez, je le rappelle, que dans le simulateur de MPLAB®, au démarrage le timer contient 0x00. Dans le cas de mon PIC®, cette valeur est 0xFF. Peut-être votre propre valeur est-elle différente ? Interrogeons donc le registre de configuration : R081<RETURN> A7 A7 en binaire donne B’10100111’. Autrement dit, les bits suivants sont positionnés :

87

RBPU : les résistances de rappel du PORTB sont coupées T0CS : le timer0 est en mode compteur ? ? ? ? PSx : prédiviseur sur timer = 256 La voilà, notre erreur, T0CS devrait être à 0 pour un fonctionnement en mode timer. Qu’à cela ne tienne, modifions la valeur en direct, puisque l’initialisation ne s’effectue qu’au lancement du programme, la valeur que nous allons mettre ne sera pas écrasée. Notez, si vous ne l’aviez pas compris, que lorsque vous relancez le programme, vous le relancez à l’endroit où il s’était arrêté, et non au début. En sommes, vous effectuez l’équivalent d’un arrêt sur image d’un magnétoscope. M081,87<RETURN> 87 Relançons le programme en mode normal, pour voir ce que cela nous donne : G<RETURN> [GO] Le programme se lance, puis s’arrête directement, et renvoie l’adresse 0x0005. Logique, puisque notre point d’arrêt est toujours positionné sur l’adresse 0x0004. L’instruction suivante à exécuter est donc bien en 0x005. Nous savons donc que maintenant notre programme entre dans la routine d’interruption, et que notre timer tourne. [DTRA]:0005 W:23 STA:E1 FSR:B0 INT:25 PIR1:00 PIR2:00 Eliminons donc ce point d’arrêt : B1FFF<RETURN> [OK] G<RETURN> [GO] Maintenant, la LED semble tout le temps allumé. Damned, il y a un autre bug dans notre programme. Repositionnons le point d’arrêt à l’entrée de notre routine d’interruption, puis relançons le programme. <RETURN> [DTRA]:0021 W:23 STA:E1 FSR:B0 INT:25 PIR1:00 PIR2:00 B0004<RETURN>

88

[OK] G<RETURN> [GO] Le programme s’arrête comme prévu à l’adresse 0x0004. [DTRA]:0005 W:23 STA:E1 FSR:B0 INT:27 PIR1:00 PIR2:00 Passons en mode pas-à-pas. S<RETURN> [ON] G<RETURN> [GO] Avancez, à coup de G<RETURN> jusque l’adresse d’arrêt 0x0012, et examinez maintenant le registre 000B (INTCON).

89

Notez que ce registre vous est donné sans même l’interroger (INT :27). Vous lisez la valeur 0x27. Autrement dit : - GIE est coupé : logique, coupé automatiquement durant l’interruption (remarquez que

vous pouvez vérifier maintenant par vous-même que c’est bien comme cela que ça se passe. D’ailleurs, vous pouvez à partir de maintenant, vérifier tout ce que je vous ai dit dans les précédents ouvrages.

- T0IE est positionné : logique, l’interruption timer0 est autorisée - T0IF est positionné : Donc, voilà l’erreur, nous avons oublié d’effacer ce flag avant le

retfie. En effet, juste après suit le retour d’interruption, notre flag devrait donc être effacé, sous peine de réentrer immédiatement dans la routine d’interruption .

- INTF est positionné : logique, puisque nous allumons notre LED via RB0 - RBIF est positionné : logique car le debugger modifie RB6/RB7.

Si vous examinez votre programme, vous verrez qu’il manque la ligne « bcf INTCON,T0IF » avant de sortir de la routine d’interruption. Ajouter cette ligne dans votre fichier asm. : restorereg bcf INTCON,T0IF ; effacer le flag

et profitez-en pour corriger la première erreur en remplaçant : OPTIONVAL EQU B'10100111' Par OPTIONVAL EQU B'10000111' Tant que nous sommes dans le debugger temps réel, amusez-vous à effectuer des M006,01<RETURN> 01 M006,00<RETURN> 00 Vous verrez alors votre LED s’allumer et s’éteindre. Je sais que tout le monde aime bien de temps à autre voir quelque chose de concret. Ainsi, vous vérifiez physiquement que vous communiquez bien avec votre PIC®. Maintenant, continuez à exécuter votre programme en pas-à-pas dans le debugger, et vous allez retourner dans le programme principal (adresse 0x0021 ).

Ceci semble illogique, puisque notre flag n’étant pas effacé, nous devrions rester coincé dans notre routine d’interruption. Examinons le registre INTCON. Vous lisez la valeur 0xA7

90

[DTRA]:S 0022 W:23 STA:F1 FSR:D9 INT:A7 PIR1:00 PIR2:00 A7 signifie que GIE et T0IE sont positionnés, et que T0IF est positionné. C’est donc d’un illogisme complet, puisque dans ce cas, nous devrions être dans la routine d’interruption, et donc GIE devrait être effacé. Alors, mon programme ne fonctionne pas, pensez-vous ? Et bien si ! Nous ne pouvons que constater un nouveau bug dans notre PIC®.

En mode pas-à-pas, les interruptions ne fonctionnent pas correctement. Ce n’est guère gênant, mais il est bon de le savoir. Inutile de demander des informations

chez Microchip®, ils font la sourde oreille sur ces problèmes. J’en ai déjà parlé. Vous verrez du reste plus loin que j’ai réussi à trouver une trace de la présence de ce bug (mais bon, il faut vraiment vouloir la trouver).

Autrement dit, si vous travaillez en mode pas-à-pas, surveillez INT. Dès qu’une condition

d’interruption se présente, placez un point d’arrêt en 0x0004, coupez le mode pas-à-pas, et relancez le programme. Celui-ci ira alors tout droit dans la routine d’interruption, d’où vous pourrez reprendre le fonctionnement en pas à pas. C’est un peu dérangeant, mais bon, c’est mieux que se casser la tête durant des heures à chercher l’erreur dans son programme.

Honnêtement, combien de temps estimez-vous que vous auriez passé pour trouver ces 2 bugs dans le fichier source, rien qu’en le lisant ?

Bien entendu, vous pouviez ici utiliser le simulateur, mais ce n’est pas toujours possible. Bon, lancez l’assemblage de votre programme corrigé (disponible sous « led_tmrd3.asm »), et reprogrammez votre PIC® à l’aide de IC-PROG. Placez le PIC® sur le circuit et lancez l’alimentation. [DTRA]:0001 W:DF STA:F1 FSR:F1 INT:00 PIR1:00 PIR2:00 Lancez le programme : G<RETURN> [GO]

91

La LED clignote gaiement. Il vous suffit de taper un return pour interrompre le programme, examiner ou modifier à votre guise, et le relancer. Essayez par exemple de changer le prédiviseur du timer0 pour faire clignoter la LED plus vite. <RETURN> M081,16 <RETURN> G<RETURN> Une autre expérience très instructive, et qui vous montrera la différence de comportement entre un simulateur comme MPLAB® et un debugger intégré, c’est d’interroger la valeur des emplacements RAM non utilisés. Je vous ai souvent dit que ces valeurs étaient aléatoires, alors que MPLAB® vous les place systématiquement à « 0 ». Examinons par exemple les emplacements non utilisés 0x30 à 0x33, en tapant : R030<RETURN> FF R031<RETURN> 20 R032<RETURN> 9F R033<RETURN> 00 Voici ce que j’obtiens, et vous ? Par curiosité, coupez puis relancez l’alimentation, et effectuez la même manœuvre. Chez moi, ces valeurs restent strictement identiques. Elles sont donc aléatoires, mais prennent pioritairement un état toujours semblable. Rien ne prouve cependant que ce soit toujours vrai. Si ça l’est, vous pouvez écrire un programme qui ne tourne que sur un PIC® déterminé. Amusant, non ? Vous pourriez toujours essayer de debugger un programme comme ça au simulateur. 8.3 Résumé des procédures Pour debugger sur circuit n’importe quel programme, il vous suffit donc de : - Insérer un « nop » à l’adresse 0x00, juste avant le « goto start » - Validez _DEBUG_ON dans la configuration - Mettre hors-service le watchdog - Ajouter la ligne #include <debug.inc> juste après la directive _CONFIG

Avouez que c’est simple, au vu des possibilités obtenues. Bien entendu, il nous reste à réaliser un programme plus pratique. Rassurez-vous, c’est fait, vous le verrez par la suite. Si vous travaillez avec un quartz différent de 20Mhz, vous devrez de plus ajouter l’assignation de la variable FQUARTZ avant la directive « include », en remplaçant 20000000 par la nouvelle fréquence de votre quartz exprimée en Hz.

92

FQUARTZ EQU D'4000000' ; On travaille à 4Mhz Si vous souhaitez modifier le débit de communication, vous pourrez également ajouter la ligne suivante au même endroit, en remplaçant 19200 par votre nouveau débit : BAUDR EQU D'4800' ; on désire communiquer à 4800 bauds Enfin, si toutes ces modifications vous valent un message d’erreur, essayez alors de modifier la constante suivante en lui attribuant des valeurs comprises entre 0 et D’10’ : BAUDRL EQU D'1' ; On ajoute un « nop » dans les routines de tempo 8.4 Quelques remarques Ainsi que nous l’avons vu, le mode FREEZE semble défectueux dans la PIC® que j’ai utilisée. Autrement dit, durant un halt, les compteurs et autres périphériques continuent de fonctionner, ainsi que les flags associés. Ceci peut être gênant, tenez-en compte. Idem en mode pas-à-pas. Dans ce mode, il vous faudra surveiller les interruptions. Si une condition d’interruption est réalisée, annulez le bit « S », placez un point d’arrêt en 0x0004, puis relancez le programme. Ainsi, l’interruption sera correctement gérée, vous pourrez alors repasser en mode pas-à-pas. Il est fortement déconseillé, en fonctionnement sous debugger, de positionner l’option _LVP_ON. En effet, La procédure de « halt » pourrait faire passer de façon intempestive le PIC® en mode programmation. Je n’ai pas vérifié ce phénomène, mais elle est précisée par Microchip®. Si vous utilisez la programmation basse tension, à vous de vérifier si ce point pose problème avec mon interface, comme il pose problème avec celle de Microchip® (j’en doute, mais bon…) 8.5 Les ressources utilisées Je vais vous rappeler ici ce que monopolise le debugger, et donc, ce qui n’est plus disponible pour votre programme principal, ainsi que les obligations qui vous incombent : - 2 adresses en mémoire RAM commune, 0x7E et 0x7F. - 16 adresses en mémoire RAM banque 2 : de 0x160 à 0x16F ou 0x110/0x11F - Les 1136 dernières adresses en mémoire programme (page 3) - Les pins RB6 et RB7 - Un niveau sur la pile utilisé par le debugger. Donc, vous n’avez plus droit qu’à 7 niveaux

de sous-routines (Si ça vous embête pour une application particulière, il suffit de travailler avec les points d’arrêt uniquement, et de ne pas interrompre le programme dans les endroits ou le niveau de sous-routine est maximum).

- Pas d’utilisation du mode LVP (sauf après vérification, à vous de voir)

93

- Pas de watchdog durant le debuggage

Maintenant, concernant les 2 bugs, à savoir l’impossibilité d’utiliser le mode FREEZE, et le problème de l’entrée dans les interruptions lorsqu’on travaille en pas-à-pas.

Vous pensez bien qu’il faut plus qu’un refus de coopération de Microchip® pour me faire

renoncer à connaître le fin mot de l’histoire. J’ai donc fouiné un peu partout, et notamment dans la documentation officielle du debugger ICD® de Microchip®.

La première chose que j’ai constaté, c’est que le mode freeze est tout simplement passé à

la trappe : aucun moyen d’accéder à cette fonction dans ICD®. J’en déduis donc que ce mode ne fonctionne effectivement pas.

Pour le mode pas-à-pas, j’ai trouvé la remarque suivante, toujours dans le manuel

d’utilisation de ICD® : Note: With the design of the MPLAB ICD, it is IMPOSSIBLE to single step through an interrupt. Due to hardware restrictions, it is IMPOSSIBLE to jump to the interrupt vector memory location while doing a single step function. Traduction Note : Avec l’utilisation de MLAB ICD, il est impossible en mode pas à pas d’entrer en interruption. Dû aux limitations hardware, il est impossible de sauter à l’adresse du vecteur d’interruption durant le fonctionnement en mode pas à pas. Ceci confirme ce que j’ai trouvé par mes essais, il y a donc bien un bug également à ce niveau. On ne peut entrer dans la routine d’interruption en fonctionnement pas-à-pas. A vous d’en tenir compte. Une dernière astuce pour les plus perspicaces. Vous n’avez pas manqué de constater que la sonde utilise les pins RB6/RB7/MCLR/VSS. Ce sont justement les pins utilisées pour la programmation du PIC®. Autrement dit, si vous placez un connecteur compatible avec le brochage de la sonde sur votre programmateur, il vous suffira de déconnecter la sonde de votre debugger et de la connecter sur votre programmateur pour pouvoir programmer sans devoir retirer votre PIC® du circuit. En ajoutant, de plus, un inverseur 2 positions, vous passez du mode programmateur au mode debugger sans rien démonter. Voilà encore une option pratique.

Vous verrez par la suite, que je me suis montré encore plus malin (ben oui, c’est moi le prof, non ? ☺ ). 8.6 Conclusions Vous voici en possession d’un outil de debuggage fonctionnel, et d’un rapport qualité/prix imbattable.

94

Grâce à DTRA, le debugger temps réel le moins cher et le plus simple du marché, et grâce à la collaboration de Bonny Gijzen (Ic-Prog), vous avez maintenant la possibilité de debugger vos programmes en temps réel directement sur votre circuit d’application. Ceci constitue un confort sans précédent dans les techniques de debuggage « low-cost ». Si vous voulez mieux (mais plus cher), il vous reste la possibilité d’utiliser l’ICD2® de Microchip®, qui, lui, s’interface directement avec MPLAB®, ce qui est son principal avantage. Il n’est, par contre, pas isolé galvaniquement, et ne permet pas la sauvegarde automatique des registres d’interruption.

Mais si vous voulez un debugger plus puissant, beaucoup plus économique en ressources que DTRA, d’un emploi beaucoup plus confortable, moins cher que ICD2®, et avec de nouvelles fonctions, alors lisez le chapitre suivant.

95

Notes : …

96

9. Le debugger temps réel « CBDS » 9.1 La démarche Et oui, il y avait encore moyen de faire mieux. Je vous explique la réflexion qui m’a conduit à améliorer DTRA. La première étape est de décider de construire un logiciel spécifique pour le PC. Ceci nous décharge de toute une série d’opération qui peuvent être transférées au logiciel du PC. Par exemple : - Tout ce qui traite de la conversion ASCII / HEXA et réciproquement - La gestion des messages vers l’utilisateur - L’automatisme des fonctions - L’utilisation des adresses symboliques - L’indication du point d’arrêt dans le fichier source.

Tout ceci nous procure un confort supplémentaire, mais ce confort est uniquement dû au programme PC. Donc, aucune raison de prétendre qu’il s’agit d’options supplémentaires, ou de « révolution ».

Par contre, le raisonnement suivant présente un intérêt certain :

- On sait qu’un PIC® contenant une routine de debuggage commence son exécution par

cette routine. - On sait que le PIC® est capable d’écrire dans sa mémoire programme.

Là, il y en a déjà qui ont compris. Ajoutons alors : - Pour écrire dans la mémoire programme, il faut un programme - Un programme existe déjà sous forme de notre routine de debuggage.

Alors, ça devrait être la révélation. L’astuce est d’utiliser le programme de debuggage pour écrire le programme à debugger

dans la mémoire programme du PIC®. En somme, rien d’autre que de combiner debugger et bootloader.

Ceci permet alors le fonctionnement suivant :

- Vous programmez une seule fois la routine de debuggage dans la mémoire haute du PIC®

avec votre programmateur classique. Nul besoin de modifier les sources de votre programme pour y inclure la routine debugger.

97

- Vous placez le PIC® avec sa sonde sur votre carte d’application. - SANS devoir couper le courant, et SANS programmateur, vous allez pouvoir charger

votre programme à debugger dans votre PIC®.

Ainsi, vous debuggez, vous trouvez un bug, vous modifiez le source et relancez l’assemblage. Le debugger renvoie le programme modifié dans le PIC® sans rien toucher au hardware, et le debuggage est relancé.

Ainsi, vous obtenez un fonctionnement comparable à celui de l’ICD® de Microchip®,

avec les options supplémentaires que j’ai ajoutées dans le chapitre précédent, et donc avec un confort maximum.

Bien entendu tout ceci n’est possible que si un software relativement puissant du côté PC

prend en charge la gestion de tout ceci, en symbiose avec le software du PIC®. Mais assez parlé, passons aux choses sérieures…

98

10. Le programme PIC® de CBDS 10.1 Le cahier des charges

Nous allons retrouver ici une partie du cahier des charges de DTRA, augmenté de nouvelles contraintes (faut-il que je sois masochiste). - Récupération de l’interface BIGOPIC2. - Très simple d’utilisation - Flexibilité complète, de façon à permettre la modification par l’utilisateur - Communication en asynchrone, permettant l’utilisation de distances convenables, et du

port COM du PC. - Diminution des ressources utilisées, que ce soit en mémoire programme ou en

emplacements RAM. - Possibilité de debugger avec le watchdog en service - Debuggage pour les PIC® 16F876 et 16F877 ou équivalants (8K programme/4 banques

RAM) 10.2 Réalisation du programme

Bon, une fois de plus, il s’agit de réaliser une routine très particulière. Concernant les limitations et le hardware utilisé, je vous renvoie au chapitre précédent.

On commence par l’en-tête, que je vais détailler, car il contient des informations utiles.

;***************************************************************************** ; SOUS-ROUTINE DE DEBUGGAGE POUR PIC 16F87X. * ; PERMET LE DIALOGUE AVEC LE PROGRAMME BIGOPIC_Pro * ; * ; Merci à Bonny Gijzen pour la modification de IC-Prog * ; * ; Je ne remercie pas les différentes maisons mères qui ont tenté de * ; m'empêcher de mener ce projet à terme. * ; * ; Ce programme est une version améliorée de DTRA, mais une partie des * ; opérations est reportée sur le logicial du PC. * ; * ; Les échanges d'informations sont en format hexadécimal * ; Dès lors, un logiciel spécifique est indispensable sur le PC * ; * ; Cette version permet de programmer le PIC par technique de bootloader * ; le programmateur n'est donc nécessaire que pour charger la routine de * ; debuggage. Le présent debugger permet donc de recharger le logiciel * ; sans intervention physique en cours de debuggage. * ; CBDS permet de debugger des programmes dont le watchdog est activé *

99

; * ;***************************************************************************** ; * ; NOM: CBDS * ; Date: 20/10/2002 * ; Version: 1.0 * ; Circuit: interface BIGOPIC * ; Auteur: Bigonoff : softwares PIC et PC * ; http://wwwabcelectronique.com/bigonoff * ; Tous droits réservés, propriété intellectuelle de l'auteur * ; * ; Le présent logiciel ne peut être distribué sans le livre et * ; les fichiers auxquels il fait référence, à savoir : * ; "La programmation des PICS par Bigonoff - quatrième partie - * ; In circuit debugger". Vous ne pouvez utiliser ce programme * ; qu'après avoir pris connaissance de cet ouvrage, et d'en avoir* ; accepté toutes les clauses et avertissements. * ; * ; Toute utilisation sur des circuits présentant des tensions * ; à risque létal ne pourra se faire qu'en respectant les * ; législations en vigueur. L'utilisateur à l'obligation de se * ; renseigner et se conformer à ces législations. * ; * ; L'intégralité des fichiers est disponible uniquement sur le * ; site de Bigonoff. http://www.abcelectronique.com/bigonoff * ; Les webmasters sont autorisés à placer un lien sur leur site. * ; * ; Les droits relatifs à l'utilisation à des fins privées de * ; ce programme sont soumis aux mêmes conditions que celles * ; décrites dans l'ouvrage susmentionné. * ; * ; Toute utilisation commerciale est interdite sans l'accord * ; écrit de l'auteur. La modification de ce source n'est * ; autorisée qu'à des fins privées, toute distribution du code * ; modifié est interdite. * ; * ; L'auteur décline toute responsabilité quant aux conséquences * ; éventuelles résultant de l'utilisation de ce programme * ; et interfaces associées. * ; * ;*****************************************************************************

Ceci concerne principalement les messages de copyright (je mets tout ça à votre disposition, ce n’est pas pour que quelqu’un d’autre se fasse des bénéfices sur mon dos).

De plus, mon travail étant bénévole, pas question que je me retrouve impliqué dans

une responsabilité quelconque. Si telle était votre vision des choses, merci de tout effacer de vos supports concernant tous les ouvrages et utilitaires que j’ai écrits.

Je n’accepte pas non plus la diffusion de sources modifiés, pour la simple et bonne

raison que ceci ne manquerait pas de m’attirer nombre de courriers relatifs à des modifications dont j’ignorerais l’existence. Si vous trouvez une modification pertinente, écrivez-moi, j’en tiendrai compte pour la version suivante.

Attention au refus de support officiel de ce mode de fonctionnement de la part de Microchip®. N’oubliez pas que vous ne pouvez utiliser ce mode que pour debugger. Dès lors, ne pas laisser le PIC® en mode debuggage pour une application sur site, surtout

100

pour une application susceptible de mettre en danger la vie d’autrui. Cet exemple n’est pas limitatif.

Ne connectez l’interface que sur une platine dont la masse peut être connectée sans

danger à celle de votre PC. La liaison directe avec un montage dont la masse est connectée à une borne du secteur est interdite. Utilisez dans ce cas un transformateur d’isolement ou toute autre méthode appropriée.

En utilisant ce debugger, vous déclarez disposer de toutes les compétences requises

au niveau de l’électronique, de l’électricité, et de leurs problèmes de sécurité. Notez qu’il est important de signaler que Microchip® interdit explicitement

l’utilisation des PIC® pour des applications à risque létal. Par exemple, vous ne pouvez utiliser un PIC® pour fabriquer un défibrillateur. Si c’était votre intention, vous devez présenter votre projet à Microchip®, et solliciter leur accord. Remarquez que CBDS, contrairement à DTRA, prend en charge le debuggage des programmes pour lesquels le watchdog est activé. Je vous rappelle simplement que je vous conseille de ne pas activer ce watchdog durant les phases de debuggage. Ceci est cependant maintenant autorisé (à vous de voir). Notez que même l’ICD2® de Microchip® ne le permet pas. Bon, après vous avoir fait peur (mais ce ne sont en fait que des pratiques d’usage courant que je vous remémore), je vous informe des commandes supportées par le CBDS. Ces commandes sont les suivantes : ;***************************************************************************** ; * ; Fichier requis: P16F876.inc * ; * ;***************************************************************************** ; * ; Fichier à inclure dans le programme à debugger * ; * ; En cas d'erreur, on répond uniquement "ERR" * ; * ; Données envoyées automatiquement au démarrage : * ; contenu de la RAM (8 bits) pour chaque emplacement de 0x00 à 0x1FF * ; * ; Commandes acceptées : * ; * ; "R" : RAM : demande de renvoi de toutes les valeurs RAM * ; Réponse : 512 valeurs de la RAM * ; * ; "M" + adresse (2 octets) + donnée (1 octet) : modifier registre * ; Réponse : 1 octet : valeur effective de modification * ; * ; "P" + adresse (2 octets) : positionner le pointeur d'adresse * ; Réponse : 2 octets : valeur du pointeur * ; * ; "W" + donnée (2 octets) : écrit l'instruction et incrémente le ptr * ; Réponse : 4 octets : adresse + valeur effectivement lues * ; * ; "E" + donnée (1 octet) : écriture de la valeur en eeprom + ptr+ * ; Réponse : 2 octets : adresse (1 octet) + donnée effective * ; *

101

; "O" : lecture de toute la zone eeprom * ; Réponse : 256 octets de la zone eeprom * ; * ; "G" : retour au programme principal (GO) * ; Pas de réponse * ; * Autrement dit, vous pouvez : - Ecrire en mémoire programme (avec vérification incluse) - Ecrire en mémoire EEPROM (avec vérification incluse). - Modifier un emplacement RAM (avec renvoi de la valeur effectivement écrite). - Obtenir le contenu complet de la RAM - Obtenir le contenu complet de la zone EEPROM. - Revenir au programme principal - Revenir en mode debuggage

Toutes les autres fonctions peuvent être créées dans le programme PC à partir de ces fonctions de base, puisqu’elles donnent accès à l’intégralité des ressources du PIC®. Notez que plusieurs commandes sont similaires à celles du bootloader, ce qui me permettra de récupérer plusieurs routines de mon programme PC BIGOPIC_light. Inutile de se chercher des complications. Ensuite, il faut bien entendu savoir que lors de la connexion sur la routine de debuggage, les registres utilisés par CBDS devront être sauvegardés à l’entrée de la routine, puis restaurés avant le retour dans le programme principal, exactement comme pour une routine d’interruption. Nous en avons déjà parlé lors de l’étude de DTRA. Moyennant quoi, si vous lisez le contenu de « STATUS », par exemple, en lisant le contenu de l’adresse 0x03, vous aurez le contenu de STATUS tel qu’il se trouve au moment de sa lecture (et donc après qu’il ait déjà été modifié par le debugger) et non son contenu au moment de l’arrêt du programme principal (valeur qui vous intéresse en réalité). Pour ces registres, vous devez donc lire la variable de sauvegarde de ce registre, et non le registre lui-même. Dans le debugger DTRA, ceci était pris en charge par le programme en PIC®, ici, optimisation oblige, ce travail est reporté sur le programme PC. Il vous faut donc connaître l’emplacement de ces variables si vous désirez écrire vous-même un programme pour PC. Je vous les donne : ; REMARQUES CONCERNANT LA ZONE RAM * ; -------------------------------- * ; * ; Les registres renvoyés sont ceux concernant l'état de la RAM au * ; moment de l'exécution de la routine. * ; * ; Donc, pour les registres modifiés par le debugger, il faut utiliser * ; les valeurs sauvegardées par ce debugger. * ; Les registres sauvegardés sont aux adresses suivantes : * ; * ; Registre W : adresse RAM 0x7F * ; Registre STATUS : adresse RAM 0x106 + offset * ; Registre PCLATH : adresse RAM 0x107 + offset *

102

; Registre FSR : adresse RAM 0x108 + offset * ; Registre INTCON : adresse RAM 0x109 + offset (si existe) * ; Registre PIR1 : adresse RAM 0x10A + offset (si existe) * ; Registre PIR2 : adresse RAM 0x10B + offset (si existe) * ; * ; De même, toute modification d'un de ces registres avant le retour * ; au programme principal doit concerner ces emplacements de sauvegarde * ; L'exception concerne : PIR1, PIR2, et INTCON, qui ne seront restaurés * ; que si le bit FREEZ de ICKBUG est positionné. Donc, si FREEZ est * ; positionné, modifier les variables de sauvegarde, sinon modifier * ; directement les registres. * ; Si l'option CBDS_NOFREEZ est définie, la restauration ne sera pas non * ; plus effective. Dans ce cas, modifier directement les registres * Vous voyez que notre registre STATUS devra être lu à l’adresse 0x106 + offset. Que vaut donc cet offset ? Tout d’abord, je vous ai laissé le choix entre 2 emplacements pour les variables réservées par CBDS. Soit à partir de l’adresse 0x110, soit dans les derniers emplacement jusque 0x16F. Il vous incombera, si vous ne conservez pas l’emplacement par défaut, de paramétrer le logiciel PC en conséquence. Vous voyez en face de INTCON, PIR1, et PIR2 le commentaire « si existe ». En effet, si vous choisissez de ne pas autoriser le mode « FREEZE », alors les registres PIR1, PIR2, et INTCON ne seront ni sauvegardés, ni restaurés. Ainsi, vous économisez ces variables, et vous accéderez donc à ces registres par leur adresse réelle. Attention dans ce cas qu’un événement extérieur peut positionner un flag d’interruption, alors qu’il ne l’était pas lors de l’entrée dans votre debugger. Par défaut, ces sauvegardes sont opérationnelles. Ne les supprimez que si vraiment vous manquez de place pour loger CBDS dans le PIC®. Plus bas, je vous indique que la restauration de ces registres sera effective uniquement si le bit FREEZ de ICKBUG a été positionné par vos soins. Dans ce cas, la modification éventuelle des registres avant le retour dans le programme principal devra s’effectuer sur les adresses de sauvegarde. Dans le cas contraire, la modification doit être réalisée directement sur les adresses réelles. Je vous rappelle qu’un bug dans les PIC® actuels empêche l’utilisation réelle du mode FREEZE. Lorsque je vous parle de ce mode ici, il s’agit évidemment du pseudo-mode FREEZE en partie simulé par le debugger software. Pour être certain que vous avez bien compris, en imaginant que le mode FREEZE soit autorisé (ne pas confondre le positionnement du bit avec l’autorisation, qui permet d’inclure la routine) : Soit le cas où le bit FREEZ n’est pas positionné : - On entre dans la routine de debuggage, INTCON est sauvé dans, disons, intcon_temp - Si on lit INTCON, on obtient sa valeur au moment de la lecture - Si on lit intcon_temp, on a la valeur de INTCON au moment de l’arrêt du programme - On modifie éventuellement INTCON - Lors de la sortie, INTCON conserve la modification éventuellement faite Soit le cas où le bit FREEZ est positionné

103

- On entre dans la routine de debuggage, INTCON est sauvé dans, disons, intcon_temp - On lit INTCON, on a sa valeur au moment de la lecture - On lit intcon_temp, on a la valeur de INTCON au moment de l’arrêt du programme - On modifie éventuellement intcon_temp - Lors de la sortie, intcon_temp est copié dans INTCON, donc les modifications sont prises

en compte.

Rassurez-vous, tout ceci sera pris automatiquement en charge par les différents logiciels. Je vous l’indique seulement pour information, si vous désirez écrire vos propres programmes. Maintenant, voici les lignes que vous pouvez éventuellement ajouter à votre programme principal pour modifier les caractéristiques de CBDS : ; PARAMETRES POSSIBLES AU NIVEAU DU PROGRAMME PRINCIPAL * ; ----------------------------------------------------- * ; * ; CBDS_HIGH : Zone RAM utilisée passe en fin de banque 2 * ; par défaut, début de la zone 0x110 * ; * ; * ; CBDS_NOFREEZ : pas de sauvegarde des registres d'interruption * ; Economise 3 emplacements RAM et 24 FLASH * ; Par défaut, sauvegarde réalisée * ; * ; CBDS_NOBOOT : Bootloader hors service * ; Economise 62 emplacements FLASH * ; Par défaut, bootloader en service * ; * ; FQUARTZ = V : avec V = fréquence du quartz utilisé en Hz * ; Par défaut : FQUARTZ = 20000000 (20Mhz) * ; * ; BAUDR = V : avec V = débit en bauds * ; par défaut : BAUDR = 19200 * ; * ; BAUDRL = V : à ne préciser qu'en cas d'erreur de débit * ; annoncé par un message. * ; par défaut : BAUDRL = 0 * ; * ; CBDSADD = A : avec A = adresse forcée de départ de la routine * ; Permet d'imposer une adresse de chargement de la * ; routine de debuggage (attention, toujours en page 3) * ; Par défaut, la routine se charge à la fin de la * ; page 3 (derniers emplacements disponibles) * Notez que la plupart du temps, aucune « commande » ne sera nécessaire pour le bon fonctionnement du debugger. Ce sont simplement des possibilités que je vous permets pour adapter éventuellement le debugger à un cas précis. CBDS_HIGH indique que la zone réservée pour les variables sera en fin de banque 2. Les emplacements exacts sont toujours donnés par un message lors de l’assemblage. De plus, l’adresse de début est envoyée au debugger sur PC, souvenez-vous. Cette ligne s’utilise telle quelle, en première colonne du programme. Il suffit d’ajouter la ligne AVANT la directive « include » d’inclusion de cbds.inc.

104

CBDS_HIGH ; RAM réservée en fin de banque 2 LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include

#include <cbds.inc> ; inclure fichier debugger Si vous ne précisez pas cette commande, les variables seront placées à partir de l’adresse 0x110. Si donc, la zone 0x110 est utilisée par votre programme, il vous reste la possibilité d’utiliser la fin de la zone 0x16F.

CBDS_NOFREEZ s’utilise exactement de la même façon. C’est également une commande sans paramètre. Si vous l’utilisez, la sauvegarde et la restauration des registres d’interruption PIR1, PIR2, et INTCON ne pourra être réalisée (même si vous positionnez le bit FREEZ dans ICKBUG).

Ceci vous économise 3 emplacements mémoire en RAM, et une partie de mémoire

programme. Par défaut, la sauvegarde est en service. Si vous n’avez pas un absolu besoin de ces emplacements, inutile d’utiliser cette commande. CBDS_NOBOOT est encore une commande sans paramètre. Si vous la précisez, vous n’encodez pas le mécanisme de bootloader, qui vous permet de charger vos programmes via le debugger.

Ceci vous économise de la place mémoire programme, mais impose l’utilisation d’un programmateur pour charger votre programme. Si vous manquez de place, et si vous utilisez l’astuce donnée dans le chapitre précédent pour connecter votre programmateur sur la sonde du debugger, alors vous pouvez entrer cette commande. Par défaut, le bootloader sera chargé.

CBDSADD accompagnée de l’adresse permet d’imposer une adresse fixe pour le chargement de la routine de debuggage. Ceci peut être utile si vous avez vous-même utilisé les derniers emplacements de la mémoire programme en page 3.

Attention cependant, l’adresse indiquée doit impérativement être dans la page 3, donc

entre 0x1800 et (0x2000 – taille de la routine). Attention, si vous précisez une adresse pour laquelle il n’est pas possible de caser la

routine (mémoire déjà utilisée par le programme, emplacement trop haut ne permettant pas de caser la routine), vous serez gratifiés d’une série d ‘erreur avec impossibilité d’assembler. Par défaut, l’adresse est calculée automatiquement par l’assembleur, afin de placer la routine dans les derniers emplacements de la page 3. Le reste des commandes permet de modifier fréquence du quartz et débit, nous les avons déjà étudiées dans le chapitre précédent. Par défaut, vous êtes sensés travailler avec un PIC® cadencé à 20Mhz, et utiliser un débit de 19200 bauds. Si ce n’est pas le cas, précisez les valeurs correctes à l’aide de ces pseudo-commandes. Notez qu’avec un PIC® de 20MHz, le debugger fonctionne parfaitement à une vitesse de 38400 bauds. Rien ne vous empêche donc, si vous êtes très pressés, de paramètrer la communication à 38400 bauds.

Maintenant, je précise les différentes ressources utilisées, selon les options choisie.

; RESSOURCES UTILISEES *

105

; -------------------- * ; * ; RAM : de 8 à 11 emplacements selon CBDS_NOFREEZ * ; 7 à 10 Emplacements à partir de 0x110 ou jusque 0x16F * ; 1 emplacement en 0x7F * ; * ; FLASH : De 260 à 339 mots suivant CBDS_NOFREEZ, CBDS_NOBOOT * ; * ; PINS : RB6 (in) et RB7 (out) * ; * ;***************************************************************************** Vous voyez que ces ressources sont fortement revues à la baisse par rapport à DTRA. Ceci assure une bonne économie des ressources.

Pour information, Microchip®, avec son ICD® doté d’un PIC® intermédiaire, utilise 6 emplacements RAM et 256 emplacements en mémoire programme (non paramétrables).

En supprimant les options ajoutées, qui n’existent pas dans l’ICD® de Microchip®, nous

en sommes à 260 mots de mémoire programme et 8 emplacements en RAM (paramétrables).

Compte tenu des contraintes supplémentaires que nous impose l’absence d’un PIC® intermédiaire, je pense m’en être pas mal sorti. Si vous décidez définitivement de ne pas utiliser le watchdog durant le debuggage, vous pouvez supprimer les instructions « clrwdt » de la routine de debuggage. Ceci vous fera gagner 7 emplacements supplémentaires, ramenant la taille minimale à 253, moins que Microchip® (et je pense qu’eux, ils sont bien placés pour optimiser, et qu’ils ont joué la facilité avec un transfert synchrone). Il vous suffira alors de reporter cette diminution de 7 dans la ligne CBDS_TAILLE = D'339' ; taille nominale du programme Que nous verrons plus loin. La nouvelle valeur sera donc D’332’. Bon, je crains que, de nouveau, il ne faille vous accrocher si votre niveau n’est pas encore suffisant. On va une fois de plus jouer allègrement avec les directives. Allez, on commence : IFNDEF INTCON ; Si pas inclus dans programme principal CBDS_TEST ; définir mode test ENDIF ; fin d'assemblage conditionnel

Qu’est-ce que INTCON vient faire ici, allez-vous me dire ?

En fait, il n’y aura aucune différence entre le programme CBDS.INC tournant de façon autonome, en tant que programme principal et la routine intégrée dans votre programme principal. Ceci vous permet très facilement de faire des modifications dans CBDS, de les tester de façon autonome, puis de pouvoir utiliser ces modifications en tant que routine de debuggage. En sommes, l’étape consistant à transformer le programme en routine, comme pour le DTRA, vous sera épargné, car prise en charge par toute une série de directives utilisant le résultat du test précédent.

106

Du reste, si vous conservez le bootloader intégré, vous n’aurez même plus besoin d’inclure le debugger dans votre programme, nous en reparlerons. Examinons alors cette ligne. Si vous intégrez votre routine de debuggage dans un programme principal, vous aurez les lignes successives suivantes dans votre programme principal : LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include

#include <cbds.inc> ; inclure fichier debugger Autrement dit, lors de l’analyse du test précédent, tous les registres (et donc INTCON) auront été définis par l’inclusion du fichier P16F876.inc. Par contre, si le programme CBDS est testé seul, alors ce fichier n’est pas encore présent au moment du test. INTCON n’est donc pas défini. Autrement dit, si INTCON est défini, c’est-à-dire si on a inclus la routine dans un programme principal, CBDS_TEST ne sera pas défini. Par contre, si on travaille uniquement sur CBDS, alors INTCON n’est pas défini, et on défini alors une étiquette (ou constante) CBDS_TEST. A partir de cet instant, si CBDS_TEST est défini, c’est qu’on est en train d’assembler CBDS en tant que programme autonome, ce qui est son mode de fonctionnement par défaut. Sinon, c’est qu’on l’utilise comme routine de debuggage. Astucieux, non ? Vivent les directives et l’assemblage conditionnel.

Maintenant, première chose à faire, Si on travaille en tant que programme autonome, c’est de préciser la configuration et les inclusions. Voici : IFNDEF INTCON ; Si pas inclus dans programme principal CBDS_AUTON ; définir mode autonome ENDIF ; fin d'assemblage conditionnel IFDEF CBDS_AUTON ; si on est en mode autonome LIST p=16F876 ; Définition de processeur #include <p16F876.inc> ; fichier include __CONFIG _CP_OFF & _DEBUG_ON & _WRT_ENABLE_ON & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC ENDIF ; fin d'assemblage conditionnel Ces lignes ne seront donc pas prises en compte si votre programme est intégré en tant que routine de debuggage dans votre programme principal (entendez programme à debugger). Ceci afin d’éviter un double emploi que, du reste, MPASM® n’apprécierait pas. Notez la présence impérative de _DEBUG_ON dans la configuration.

107

Maintenant, on rappelle les différents paramètres, mis hors-service par l’insertion d’un point-virgule, avec un exemple de leur utilisation. ;***************************************************************************** ; PARAMETRES * ;***************************************************************************** IFDEF CBDS_AUTON ; si on est en mode autonome ;FQUARTZ EQU D'20000000' ; fréquence quartz ;BAUDR EQU D'38400' ; débit en bauds ;BAUDRL EQU D'0' ; Permet de diminuer le taux d'erreur ; Augmente la taille du programme ; conserver la plus faible valeur ; possible. Ne pas dépasser D'5' ;CBDS_HIGH ; utilisation de la zone haute ;CBDS_NOFREEZ ; pas de restauration des interrupts ;CBDS_NOBOOT ; pas de bootloader ;CBDSADD EQU 0x1800 ; adresse forcée de départ de la routine ENDIF ; fin d'assemblage conditionnel Pour mettre une « commande » en service, il vous suffit donc d’ôter le point-virgule. Avouez que je vous mâche le travail ! Maintenant, on va prendre en compte les « commandes » que vous avez éventuellement placées dans votre programme principal. ;***************************************************************************** ; ACTIONS SELON PARAMETRES * ;***************************************************************************** ; valeurs par défaut ; ------------------ IFNDEF FQUARTZ ; si fréquence non précisée FQUARTZ = D'20000000' ; alors fréquence = 20MHz MESSG "Fréquence de 20 Mhz prise par défaut" ; et message endif IFNDEF BAUDR ; si débit non précisé BAUDR = D'19200' ; alors débit = 38400 bauds MESSG "Débit de 19200 bauds pris par défaut" ; et message endif IFNDEF BAUDRL ; si BAUDRL non précisé BAUDRL = 0 ; alors BAUDRL = 0. Message possible

endif ; en cas d'erreur importante

On établit ici les valeurs par défaut pour la fréquence du quartz et le débit (notez donc que l’utilisation la plus simple du debugger consistera à ne rien préciser du tout, tout étant alors géré par défaut). Le message éventuel indiqué par le dernier commentaire sera généré plus loin, au moment des calculs. A partir d’ici, les fréquences et débits ont une valeur, soit imposée par vous-même, soit prise par défaut. S’il s’agit d’une valeur par défaut, un message vous rappelle leur valeur.

108

Maintenant, il faut calculer l’emplacement des variables dans la page 2. On a 3 emplacements possibles. En effet, nous avons la possibilité de placer ces variables à partir de l’adresse 0x110 ou JUSQUE l’adresse 0x16F. De plus, nous avons 2 nombres de variables différents, selon que l’on permet ou pas la sauvegarde des registres d’interruption. Tout ceci nous donne : - Soit on ne définit pas CBDS_HIGH, dans ce cas les variables commencent en 0x110 - Soit on définit CBDS_HIGH et pas CBDS_NOFREEZ, dans ce cas on a 10 variables se

terminant en 0x16F. - Soit on définit CBDS_HIGH et CBDS_NOFREEZ, dans ce cas on a 7 variables se

terminant en 0x16F.

Bien entendu, si on démarre en 0x110, qu’on ait 7 ou 10 variables, l’adresse reste la même. Par contre si on termine en 0x16F, l’adresse du début dépend du nombre de ces variables. Ceci explique les 3 emplacements possibles. ; sélectionner emplacement des variables ; -------------------------------------- IFNDEF CBDS_HIGH ; si mémoire basse CBDS_O EQU 0x10 ; offset des emplacements variables MESSG "zones RAM 0x110/0x11C + 0x7F réservées" ELSE ; sinon, si mémoire haute IFNDEF CBDS_NOFREEZ ; si mode FREEZ autorisé CBDS_O EQU 0x66 ; offset = 66 MESSG "zones RAM 0x166/0x16F + 0x7F réservées" ELSE ; sinon, si mode FREEZ interdit CBDS_O EQU 0x69 ; offset = 69 MESSG "zones RAM 0x169/0x16F + 0x7F réservées" ENDIF ; fin de condition sur FREEZ ENDIF ; fin de condition sur CBDS_HIGH

Remarquez que j’ai utilisé 2 « IF » imbriqués afin de permettre plusieurs conditions. Un message indique à l’utilisateur où se situent les zones réservées. Un offset « CBDS_O », est calculé, qui donne l’adresse relative de l’emplacement des variables en banque 2.

Ces emplacements sont en effet nécessaires aussi bien à notre routine de debuggage, qu’à

notre programme sur PC qui doit évidemment savoir où se trouvent les variables de sauvegarde des registres.

Maintenant, nous allons établir la longueur de notre programme en fonction des

différentes options choisies. Nous avons 3 tailles possibles. Attention que si vous allongez CBDS pour votre propre usage, n’oubliez pas de modifier également les tailles correspondantes.

Je vous rappellerai, SVP, de ne pas distribuer une version de CBDS modifiée sans mon

autorisation, car cela risquerait de me valoir des courriers incompréhensibles pour cause de non correspondance avec le projet original. Je ne vous empêche pas de modifier pour votre propre usage, ou de me soumettre une modification à inclure dans les prochaines versions.

109

Ce n’est nullement du protectionnisme (sinon je ne vous fournirais ni sources, ni

explications détaillées), mais uniquement la seule façon pour moi d’être certain que lorsqu’on me pose une question, mon interlocuteur dispose bien de la même version que moi.

Et puis, si vous trouvez quelque chose d’intéressant, autant en faire profiter tout le monde,

non ?

; Tailles du programme ; -------------------- CBDS_TAILLE = D'339' ; taille nominale du programme IFDEF CBDS_NOFREEZ ; si pas de mode FREEZ CBDS_TAILLE -= D'24' ; alors 24 octets de moins ENDIF IFDEF CBDS_NOBOOT ; si pas de bootloader CBDS_TAILLE -= D'55' ; alors 55 octets de moins ENDIF CBDS_TAILLE += (BAUDRL*6) ; ajouter les nop créées par BAUDRL Observez les directives « -= » et « += ». Ecrire « val += 6 » équivaut à écrire « val = val+6 ». En sommes, on évite de répéter la variable. Les amateurs de « C » connaissent cette méthode depuis longtemps. Les 2 premiers calculs prennent en charge l’économie réalisée par la suppression des fonctions inutilisées. Le dernier ajoute les « nop » éventuels provoqués par la modification de la valeur de « BAUDRL ». Comme le debugger gère maintenant le watchdog, j’ai du inclure des instructions « clrwdt » à des endroits stratégiques du programme, tout en limitant leur nombre au maximum. Si vous observez le programme, vous verrez que le temps le plus long séparant 2 « clrwdt » est de l’ordre de 10,5 fois la durée d’un bit transmis. Or le watchdog doit, dans le pire des cas, être resetté toutes les 7ms (sans prédiviseur). Autrement dit, ceci nous donne une durée de bit de 7ms / 10,5 = 0,67 ms. Ceci correspond à un débit de : 1/ 0,67 * 10-3 = 1492 bauds. Fixe et indépendant du quartz utilisé. Evidemment, il s’agit d’un débit minimum, car une diminution allonge la durée d’un bit.

Par précaution, comme le débit de 1492 bauds n’est pas standard, j’ai décidé de prévenir l’utilisateur si le débit choisi est inférieur à 2400 bauds :

110

; watchdog ; -------- IF BAUDR < 2400 MESSG "Ce débit est trop faible pour gérer correctement le watchdog (min 2400 bauds), mettez _WDT_OFF dans votre configuration, ou utilisez un prédiviseur" ENDIF Autrement dit, si vous utilisez un débit inférieur à 2400 bauds, il vous faudra, soit utiliser un prédiviseur assigné au watchdog durant la phase de debuggage, soit, plus simplement couper ce watchdog tant que le debuggage n’est pas terminé. Et oui, il faut penser à tout quand on développe. Mais bon, tout ce que j’ai pensé par avance vous évite de tomber dans le piège plus tard. Attention cependant, il est pratiquement impossible que j’ai pensé à tout. Si vous tombez dans un piège non prévu, prévenez-moi, j’ajouterais la vérification supplémentaire. Etablissons maintenant l’adresse de début de notre routine. On distingue 2 cas : - Soit l’utilisateur n’a rien précisé : on charge en mémoire haute - Soit l’utilisateur impose une adresse précise ; adresse de début ; ---------------- IFNDEF CBDSADD ; si pas déja définie CBDSADD EQU 0x2000-CBDS_TAILLE ; adresse de la routine ENDIF Ici, on calcule simplement l’adresse de début de notre routine de debuggage. Si l’utilisateur a précisé lui-même son adresse, alors le programme ne calcule rien et utilise cette adresse. Sinon, le programme sera logé en fin de page 3. Nous allons maintenant calculer nos valeurs de temporisation en nombre de boucles. Reportez-vous au chapitre précédent pour les explications, je ne reprends pas tout ici. ; Calcul de la constante de temporisation ; --------------------------------------- CBDS_1B EQU (((FQUARTZ/4)/BAUDR)-D'9')/(3+BAUDRL) CBDS_1B5 EQU (((FQUARTZ*3/8)/BAUDR)-D'9')/(3+BAUDRL) IF CBDS_1B5 < 0 ; Si durée trop courte MESSG "Impossible d'établir le débit, diminuez BAUDRL. Si déjà à 0, diminuez le débit" ENDIF If CBDS_1B5 > 0x100 ; Si durée trop longue MESSG "Débit trop faible pour votre quartz. Augmentez le baudrate ou augmentez la valeur de BAUDRL" endif On vérifie l’erreur théorique obtenue, comme je l’ai déjà expliqué. Si l’erreur est trop importante pour une communication sans risque, on avertit l’utilisateur, qui peut intervenir sur différents paramètres.

111

; calcul du débit réel et de l'erreur obtenus ; ------------------------------------------- CBDS_BR EQU FQUARTZ/((((3+BAUDRL)*CBDS_1B)+9)*4) CBDS_ERR EQU (BAUDR-CBDS_BR)*100/BAUDR IF (CBDS_ERR>4 | CBDS_ERR <-4) ; Si erreur > 4% MESSG "Erreur de baudrate trop importante. Essayez de modifier la valeur de BAUDRL" ENDIF Les pins utilisées se passent de commentaire :

; Pins utilisées ; -------------- #DEFINE TXPIN PORTB,7 ; pin pour l'émission (ne pas modifier) #DEFINE RXPIN PORTB,6 ; pin pour la réception (ne pas modifier) Voici notre fameuse instruction inscrite à l’adresse 0x2004, adresse qui nous aura causé tant de démêlés avec Microchip® (et oui, tout ça pour cette simple ligne, simple, mais indispensable). On en profite pour éliminer les warnings indésirables. errorlevel -220 ; supprime le warning d'adresse errorlevel -306 ; supprime le warning cross-page errorlevel -302 ; supprime le warning cross-page ORG 0x2004 ; vecteur du debuggage goto CBDSADD ; sauter sur la sous-routine O

Notez que nous avons utilisé les assignations et définitions pour un usage bien plus puissant que de la simple facilité d’écriture. Vous constatez ici qu’il s’agit de directives puissantes pour qui les utilise correctement. Ca devrait maintenant être votre cas. Passons aux macros, qui ont déjà été vues au chapitre précédent, je n’explique donc plus. Notez que toutes n’étaient plus utiles, j’ai donc épuré. ;***************************************************************************** ; MACROS * ;***************************************************************************** SUBRS macro adresse ; pseudo sous-routine simple LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour goto adresse ; sauter ICI ; adresse de retour endm SUBRV macro adresse,vari ; pseudo sous-routine avec variable LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour movf vari,w ; charger variable dans w goto adresse ; sauter

112

ICI ; adresse de retour endm SUBRC macro adresse,cst ; pseudo sous-routine avec constante LOCAL ICI movlw HIGH ICI ; poids fort de l'adresse de retour movwf PCLATH ; dans PCLATH movlw LOW ICI ; poids faible de l'adresse de retour movwf cbds_pcl ; sauver adresse de retour movlw cst ; charger constante dans w goto adresse ; sauter ICI ; adresse de retour endm RET macro ; retour de pseudo sous-routine movf cbds_pcl,w ; adresse de retour movwf PCL ; dans PCL endm cbdsT macro cbds_dur ; délai d'après la durée LOCAL ICI VARIABLE i movlw cbds_dur ; charger durée movwf cbds_tempo ; dans compteur de boucles i = 0 ; compteur de boucles ICI WHILE i < BAUDRL ; tant que i < BAUDRL nop ; ajouter nop i+=1 ; incrémenter i ENDW decfsz cbds_tempo,f ; décrémenter compteur goto ICI ; pas 0, recommencer endm Passons aux variables. Une seule adresse en variable commune, la sauvegarde du registre « W ». Les autres seront en mémoire page 2 (et oui, optimisation ici en taille mémoire RAM commune, souvenez-vous qu’on peut optimiser sur tout ce qu’on veut, et la mémoire commune est une ressource précieuse, donc sujette à optimisation) ;***************************************************************************** ; VARIABLE ZONE COMMUNE * ;***************************************************************************** w_CBDS EQU 0x7F ; Sauvegarde registre W Ensuite, les autres variables. ;***************************************************************************** ; VARIABLES BANQUE 2 * ;***************************************************************************** CBLOCK 0x100 + CBDS_O ; Début = 0x110, 0x166, ou 0x169 ; 7 à 10 emplacements

; variables ; --------- cbds_byte : 1 ; byte reçu ou envoyé

113

cbds_pcl : 1 ; adresse de retour pseudo sous-routine cbds_cmptb : 1 ; compteur de bits cbds_tempo : 1 ; compteur pour temporisation

; sauvegardes ; ----------- status_CBDS : 1 ; sauvegarde registre STATUS PCLATH_CBDS : 1 ; sauvegarde PCLATH FSR_CBDS : 1 ; sauvegarde FSR

; non utilisées si NOFREEZ ; ------------------------ INTCON_CBDS : 1 ; sauvegarde INTCON PIR1_CBDS : 1 ; sauvegarde PIR1 PIR2_CBDS : 1 ; sauvegarde PIR2 ENDC ; Fin de la zone Les variables non utilisées éventuellement (mode NOFREEZ) sont placées en fin de zone, ceci évite les calculs supplémentaires. Nul besoin de condition ici, la déclaration des variables n’implique aucune conséquence dans le programme. Si on ne les utilise pas, la déclaration ne sert tout simplement à rien. En effet, on déclare, mais on ne « réserve » rien. On arrive enfin dans le vif du sujet. On commence par sauvegarder les registres. ;***************************************************************************** ; SAUVEGARDER REGISTRES * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Sauvegarde les registres utilisés par la routine de debuggage ;----------------------------------------------------------------------------- org CBDSADD ; Adresse de la routine de debuggage

;sauvegarder registres ;---------------------

clrwdt ; effacer watchdog movwf w_CBDS ; sauver registre W swapf STATUS,w ; swap status avec résultat dans w BANKSEL FSR_CBDS ; passer banque2 movwf status_CBDS ; sauver status swappé IFNDEF CBDS_NOFREEZ ; si mode FREEZ autorisé movf INTCON,w ; charger INTCON movwf INTCON_CBDS ; sauver INTCON bcf STATUS,RP1 ; passer banque0 movf PIR1,w ; charger PIR1 bsf STATUS,RP1 ; passer banque 2 movwf PIR1_CBDS ; sauver PIR1 bcf STATUS,RP1 ; passer banque0 movf PIR2,w ; charger PIR2 bsf STATUS,RP1 ; passer banque 2 movwf PIR2_CBDS ; sauver PIR1 ENDIF ; fin d'assemblage conditionnel movf FSR , w ; charger FSR movwf FSR_CBDS ; sauvegarder FSR movf PCLATH , w ; charger PCLATH movwf PCLATH_CBDS ; le sauver PAGESEL CBDSADD ; pointer sur page actuelle

114

Remarquez que la sauvegarde des registres d’interruption ne s’effectue QUE si vous n’avez pas précisé CBDS_NOFREEZ. Dans le cas contraire, ces instructions ne seront tout simplement pas écrite dans votre routine finale.

Pour rappel, on appelle ceci de l’assemblage conditionnel. Il ne s’agit pas d’un test au moment de l’exécution du programme, mais d’un test au moment de l’assemblage qui précise si ces lignes feront ou non partie du code final assemblé. Ensuite, on entre dans la routine proprement dite. On commence par configurer les pins, puis on attend qu’il n’y ait plus de transit sur la pin RB6. ;***************************************************************************** ; Entrer dans le mode debugger * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Envoi registres de debuggage ;----------------------------------------------------------------------------- cbds_start

; initialiser ; ----------- bsf TXPIN ; préparer sortie à 1 bsf STATUS,RP0 ; passer banque 3 bcf TXPIN ; passer pin émission en sortie bsf RXPIN ; passer pin réception en entrée bcf STATUS,RP0 ; repasser banque 2 SUBRS cbds_endrec ; attendre fin de réception éventuelle Ensuite, on lit « bêtement » les 512 emplacements RAM et on envoie les valeurs vers le PC. Il va de soi que certaines valeurs sont redondantes (INTCON se trouve dans les 4 banques), ou inutiles (l’adresse 0x00 donne le contenu de l’adresse pointée par FSR dont on ignore le contenu). Mais le but est d’optimiser la routine en taille, autant laisser le programme PC effectuer le tri. ; envoyer les emplacements RAM ; ---------------------------- cbds_start1 bcf STATUS,IRP ; on commence par banques 0 et 1 clrf FSR ; effacer pointeur cbds_start2 SUBRV cbds_sendw,INDF ; envoyer registre pointé incf FSR,f ; pointer sur suivant btfss STATUS,Z ; 256 octets envoyés? goto cbds_start2 ; non, suivant btfsc STATUS,IRP ; 512 octets envoyés? goto cbds_boucle ; oui, terminé bsf STATUS,IRP ; non, 256 suivants goto cbds_start2 ; et envoyer On arrive maintenant dans notre boucle principale, dans laquelle on va tourner jusqu’au retour au programme principal.

115

;***************************************************************************** ; BOUCLE PRINCIPALE * ;***************************************************************************** ;----------------------------------------------------------------------------- ; On attend la commande ; ensuite, on teste pour voir de laquelle il s'agit ;----------------------------------------------------------------------------- cbds_boucle SUBRS cbds_rec ; attendre et recevoir commande On se borne à lire la commande reçue. Ensuite, on arrive au test de notre première commande.

La valeur reçue se trouve dans cbds_byte. Un simple xorlw fera l’affaire. ;***************************************************************************** ; TRAITER COMMANDE "R" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Demande de rafraîchissement des variables RAM ; Réponse : 512 octets : tout le contenu de la RAM ;----------------------------------------------------------------------------- ; tester commande ; --------------- movf cbds_byte,w ; charger octet reçu xorlw "R" ; comparer avec commande "R" btfsc STATUS,Z ; tester si commande "R" goto cbds_start1 ; oui, envoyer RAM Comme on aura un programme automatisé à l’autre bout, et pour limiter la taille mémoire, j’ai choisi de renvoyer l’intégralité de la RAM à chaque commande « R » qui sera donc utilisée sans paramètre. C’est donc un « Refresh » de la RAM qui sera effectué, et non une demande d’un emplacement précis. Ceci nous permet de réutiliser la routine exécutée au démarrage du debugger (toujours l’optimisation en taille). Notez que la vitesse de 38400 bauds possible permet d’effectuer cette opération en 0,13 seconde. La syntaxe est donc « R », tout simplement et sans paramètre. La réponse consistera en 512 octets consistant en autant de lecture de la zone RAM, de 0x00 à 0x1FF. On arrive au test suivant. S’il ne s’agit pas d’une commande « R », on va tester s’il s’agit d’une commande « M ». Vous allez peut-être penser que, puisque le contenu de « w » a été détruit par le test précédent, nous allons procéder comme ceci : movf cbds_byte,w ; charger octet reçu xorlw "M" ; comparer avec commande "M" En fait, c’est la façon « intuitive » de procéder, mais ce n’est pas une façon optimisée de le faire. Nous en avons déjà parlé au sujet du bootloader, je n’y reviens donc pas. Nous utiliserons donc plutôt :

116

xorlw "R"^"M" ; comparer avec commande "M" On gagne une instruction (pour chaque test), donc un emplacement en mémoire programme. C’est compliqué pour si peu ? Ben oui, c’est ça l’optimisation. Notez qu’ici l’optimisation est totale, taille et vitesse, sans aucune contrepartie. Il est donc logique de toujours utiliser cette technique lors de tests consécutifs. ;***************************************************************************** ; TRAITER COMMANDE "M" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; On reçoit 2 octets pour l'adresse (haute puis basse), puis la nouvelle ; valeur à insérer. ; Réponse : 1 octet : valeur effectivement relue ;-----------------------------------------------------------------------------

; tester si reçu "M" ; ------------------

xorlw "R"^"M" ; comparer avec commande "M" btfss STATUS,Z ; tester si égalité goto cbds_comP ; non, tester commande suivante

; réception de l'adresse ; ----------------------

bcf STATUS,IRP ; par défaut, banques 0 et 1 SUBRS cbds_rec ; lire octet fort btfsc cbds_byte,0 ; tester si adresse 0x1xx bsf STATUS,IRP ; oui, positionner IRP SUBRS cbds_rec ; lire octet faible movf cbds_byte,w ; prendre octet reçu movwf FSR ; dans pointeur indirect

; réception et écriture de la donnée ; ---------------------------------- SUBRS cbds_rec ; lire donnée movf cbds_byte,w ; charger donnée reçue movwf INDF ; la mettre dans registre concerné

; envoi de la donnée réellement écrite ; ------------------------------------ SUBRV cbds_sendw,INDF ; envoyer registre pointé goto cbds_boucle ; attendre commande suivante Notez que cette routine est simple par ailleurs. Elle prend l’adresse passée en paramètre, la place dans IRP et dans FSR, reçoit la valeur passée en paramètre, et la place dans l’adresse pointée. Ensuite, on relit l’adresse pointée et on renvoie la valeur effectivement écrite. Remarquez qu’on utilise directement les valeurs reçues, donc sans les sauver dans des variables (économie de RAM). Vous allez me dire qu’on risque de perdre des octets reçus puisque la réception continue durant ce temps.

En fait, non, puisque nous sortons de la routine de réception d’un octet au milieu du stop-bit. Il nous reste donc un demi stop-bit pour réentrer dans cette routine pour la réception de l’octet suivant.

117

Autrement dit, à 38400 bauds, la durée d’un demi-bit nous permet d’exécuter 65 cycles d’instruction. C’est largement suffisant. Remarquez tout de même que lorsqu’on réalise un programme un peu pointu, il y a des tas de questions de ce type à se poser (et donc pour lesquelles il faut trouver une réponse). Veillez cependant à ce que si vous diminuez la fréquence de quartz, ou que vous augmentez le débit, vous ayez suffisamment de temps pour exécuter la manœuvre. La syntaxe est donc : « M »abc, avec « ab » l’adresse du registre à modifier (ou de la variable), et « c » la nouvelle valeur à écrire. La réponse consiste en un seul octet, qui est la nouvelle valeur actuelle du registre modifié (après relecture). Autrement dit, si vous tentez de modifier un bit en lecture seule, par exemple, vous verrez en réponse que ce bit n’aura pas été modifié. Voyons la commande suivante, « P ». Cette commande positionne le pointeur flash/eeprom constitué de EEADR et EEADRH., qui servira pour l’écriture en mémoire programme ou en eeprom. Pour ce dernier cas, seul l’octet de poids faible (le second envoyé) sera utilisé (EEADR). ;***************************************************************************** ; TRAITER COMMANDE "P" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Positionne le pointeur qui sera utilisé pour l'écriture et la lecture en ; mémoire eeprom et flash ; On reçoit le poids fort puis le poids faible ; Réponse : 2 octets : les 2 octets reçus ; L'utilisation de cette commande détruit les registres EEADR et EEADRH ; Ces registres devront être restaurés par le programme PC. ;----------------------------------------------------------------------------- cbds_comP

; tester si reçu "P" ; ------------------ xorlw "M"^"P" ; comparer avec commande "P" btfss STATUS,Z ; tester si égalité goto cbds_comW ; non, tester commande suivante

; réception des 2 octets ; ----------------------

SUBRS cbds_rec ; lire donnée movf cbds_byte,w ; charger donnée lue movwf EEADRH ; dans pointeur poids fort SUBRS cbds_rec ; lire donnée movf cbds_byte,w ; charger donnée lue movwf EEADR ; dans pointeur poids faible

; renvoi de la valeur écrite ; --------------------------

cbds_comP2 SUBRV cbds_sendw,EEADRH ; envoyer pointeur haut SUBRV cbds_sendw,EEADR ; envoyer pointeur bas goto cbds_boucle ; attendre commande suivante

118

Notez la première ligne de test, qui fonctionne comme la précédente. Le contenu de « W » a été inversé une première fois suivant « R », puis a été remis en ordre et inversé de nouveau suivant « M ». Il faut donc inverser ici suivant « M » puis « P ». En fait, on prend toujours la précédente commande xor l’actuelle. C’est très simple une fois qu’on a compris. Cette commande positionne simplement la variable interne cbds_ptr, sur 2 octets, et renvoie la valeur de ce pointeur. La syntaxe est : « P »ab, avec « ab » la nouvelle valeur du pointeur. La réponse sera : ab Cette commande doit donc précéder une demande d’écriture en mémoire programme ou en mémoire eeprom. On trouve maintenant notre routine de bootloader, qui sert donc à « programmer » notre programme dans le PIC®, en nous servant du PIC® lui-même. Cette commande est la commande « W ». Vous constaterez que l’utilisation des commandes relatives aux écritures ou lectures EEPROM ou FLASH modifient les registres EEDATH, EEDATA, EEADR, EEADRH, et EECON1. Pour des raisons évidentes d’économie de RAM, ces registres ne sont pas sauvegardés. Mais comme le programme PC reçoit les valeurs de ces registres lors du passage en mode debug, il est très simple pour ce dernier de renvoyer les valeurs adéquates au PIC® avant le retour au programme principal. J’ai donc effectué cette restauration pour vous dans le programme BIGOPIC_Pro. Donc, si vous créez vous-même un programme PC, pensez à renvoyer ces valeurs si vous avez effectué une des commandes relatives à ces accès. ;***************************************************************************** ; TRAITER COMMANDE "W" BOOTLOADER * ;***************************************************************************** ;----------------------------------------------------------------------------- ; reçoit l'instruction à placer en mémoire programme (2 octets) ; Modifie EEDATH, EEDATA, EEADRH, EEADR et EECON1. Ne les restaure pas. ; Ceci est peu important, on écrit le programme, il ne tourne donc pas encore ; Réponse : 4 octets : adresse (2 octets) + instruction (2 octets) ; Après écriture, on pointe sur l'emplacement suivant ;----------------------------------------------------------------------------- cbds_comW IFNDEF CBDS_NOBOOT ; si boot pas hors-service

; tester si reçu "W" ; ------------------

xorlw "P"^"W" ; comparer avec commande "W" btfss STATUS,Z ; tester si égalité goto cbds_comE ; non, tester commande suivante

; réception des 2 octets de donnée ; -------------------------------- SUBRS cbds_rec ; lire donnée octet fort movf cbds_byte,w ; charger octet lu movwf EEDATH ; placer dans registre SUBRS cbds_rec ; lire donnée octet faible movf cbds_byte,w ; charger octet lu movwf EEDATA ; placer dans registre

119

; écrire instruction en flash ; --------------------------- bsf STATUS,RP0 ; pointer banque 3 bsf EECON1,EEPGD ; pour écriture en mémoire programme bsf EECON1,WREN ; autorisation d'écriture movlw 0x55 ; début de la séquence d'écriture movwf EECON2 ; commande 0x55 movlw 0xAA ; pour commande 0xAA movwf EECON2 ; envoyer commande bsf EECON1,WR ; écrire nop ; instructions non exécutées nop bcf EECON1,WREN ; verrouiller écritures bcf STATUS,RP0 ; repasser banque 2

; envoyer adresse courante ; ------------------------

SUBRV cbds_sendw,EEADRH ; envoyer pointeur haut SUBRV cbds_sendw,EEADR ; envoyer pointeur bas

; envoyer donnée flash ; --------------------- bsf STATUS,RP0 ; pointer banque 3 bsf EECON1,RD ; ordre de lecture nop ; attendre fin de lecture nop ; attendre bcf STATUS,RP0 ; repasser banque 2 SUBRV cbds_sendw,EEDATH ; envoyer data haute cbds_incptr SUBRV cbds_sendw,EEDATA ; envoyer data basse

; incrémenter pointeur ; -------------------- incf EEADR,f ; incrémenter pointeur poids faible btfsc STATUS,Z ; tester si débordement incf EEADRH,f ; oui, incrémenter poids fort goto cbds_boucle ; commande suivante ENDIF ; fin d'assemblage conditionnel Ici, on commence par recevoir les 2 octets de données, qui seront placés directement dans les registres nécessaires pour l’écriture en mémoire flash. L’opération d’écriture en mémoire programme consiste alors simplement à utiliser la procédure imposée par Microchip®. Nous renverrons alors l’emplacement d’écriture suivie par la valeur effectivement relue. Ceci constitue une vérification. Il ne reste ensuite qu’à incrémenter le pointeur constitué de EEADRH/EEADR. Il va de soi que la première utilisation de cette commande nécessite le positionnement correct de ces registres, ce qui s’effectue par la commande « P ». Puisque le pointeur est automatiquement incrémenté, l’écriture suivante s’effectuera à l’adresse qui suit directement celle en cours. Passons maintenant à l’écriture en eeprom, qui est strictement identique, excepté la procédure imposée, qui, elle, est évidemment différente .

120

;***************************************************************************** ; TRAITER COMMANDE "E" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Ecriture dans la zone eeprom. Attend la fin de l'opération avant de ; continuer. ; Modifie EEDATA, EEADR, et EECON1, mais ne les restaure pas ; Ceci est du ressort du programme PC. ; Réponse : 2 octets : adresse + valeur relue ;----------------------------------------------------------------------------- cbds_comE

; tester si reçu "E" ; ------------------ IFDEF CBDS_NOBOOT ; si pas de bootloader xorlw "P"^"E" ; comparer avec commande "E" ELSE ; sinon xorlw "W"^"E" ; comparer avec commande "E" ENDIF ; fin d'assemblage conditionnel btfss STATUS,Z ; tester si égalité goto cbds_comO ; non, tester commande suivante

; réception octet de donnée ; ------------------------- SUBRS cbds_rec ; lire donnée octet faible movf cbds_byte,w ; charger octet lu movwf EEDATA ; placer dans registre

; écrire en eeprom ; ---------------- bsf STATUS,RP0 ; passer banque 3 bcf EECON1,EEPGD ; pour écriture en mémoire data bsf EECON1,WREN ; autorisation d'écriture movlw 0x55 ; début de la séquence d'écriture movwf EECON2 ; commande 0x55 movlw 0xAA ; pour commande 0xAA movwf EECON2 ; envoyer commande bsf EECON1,WR ; écrire

; renvoyer pointeur ; ----------------- bcf STATUS,RP0 ; pointer banque 2 SUBRV cbds_sendw,EEADR ; envoyer pointeur

; attendre fin d'écriture ; ----------------------- bsf STATUS,RP0 ; passer banque 3 clrwdt ; effacer watchdog btfsc EECON1 , WR ; tester si écriture terminée goto $-2 ; non, attendre bcf EECON1,WREN ; verrouiller écritures

; lire data lue ; -------------- bsf EECON1,RD ; ordre de lecture bcf STATUS,RP0 ; passer en banque2

; incrémenter pointeur ; -------------------- IFDEF CBDS_NOBOOT ; si pas de commande "W" SUBRV cbds_sendw,EEDATA ; envoyer data lue

121

incf EEADR,f ; incrémenter pointeur goto cbds_boucle ; et commande suivante ELSE ; sinon goto cbds_incptr ; profiter de la routine de la commande "W" ENDIF ; fin d'assemblage conditionnel Remarquez tout d’abord l’assemblage conditionnel concernant le test de la commande, tout au dessus. Il faut en effet se souvenir que la commande précédente n’est pas assemblée si l’utilisateur a précisé CBDS_NOBOOT. Autrement dit, dans ce cas, la ligne « xorlw "P"^"W" » n’aura pas été exécutée. En d’autres termes, si l’utilisateur choisi cette option, on passe directement de la commande « P » à la commande « E », ce qui explique cet assemblage conditionnel. En fin d’exécution, on doit procéder à l’envoi de EEDATA et à l’incrémentation du pointeur. Seul le pointeur EEADR est concerné par cette incrémentation, lorsqu’il s’agit d’une écriture en eeprom. Si la commande « W » précédente n’existe pas, suite à la présence de CBDS_NOBOOT dans le programme principal, on procède de façon classique : SUBRV cbds_sendw,EEDATA ; envoyer data lue

incf EEADR,f ; incrémenter pointeur goto cbds_boucle ; commande suivante.

Ceci demande 7 octets en mémoire programme, et une durée de 9 cycles d’instruction pour revenir à notre boucle principale. Par contre, si la commande « W » existe, j’utilise l’envoi, l’incrémentation et le saut déjà existants dans cette commande. Le registre EEADRH sera également incrémenté, mais comme on ne l’utilise pas, cela n’a pas d’importance. goto cbds_incptr ; profiter de la routine de la commande "W" Tout ceci prendra alors 13 cycles d’instruction et 1 emplacement en mémoire programme. Soit 6 cycles de plus, contre 6 instructions de moins.

Voici donc encore un exemple typique de choix entre optimisation en vitesse et optimisation en taille. C’est évidemment la taille qui importe dans cette application. Toutes ces lignes permettent donc d’économiser 6 instructions. Eh oui, pas toujours simple d’optimiser, n’est-ce pas ? Nous arrivons maintenant à la commande « O » qui va permettre de lire l’intégralité de la zone EEPROM. Une fois de plus, cette façon de procéder économise au maximum la taille du programme tout en permettant l’accès à toutes les adresses. ;***************************************************************************** ; TRAITER COMMANDE "O" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Lecture de toute la zone eeprom ; Réponse : 256 octets : contenu de la zone eeprom ; Modifie EEADR, EEDATA et EECON1 qui devront être restaurés par le programme

122

; PC ;----------------------------------------------------------------------------- cbds_comO

; tester si reçu "O" ; ------------------ xorlw "E"^"O" ; comparer avec commande "O" btfss STATUS,Z ; tester si égalité goto cbds_comG ; non, alors commande suivante

; envoyer les 256 octets ; ----------------------

clrf EEADR ; effacer pointeur cbds_comO1 bsf STATUS,RP0 ; passer banque3 bcf EECON1,EEPGD ; pointer sur zone data bsf EECON1,RD ; ordre de lecture bcf STATUS,RP0 ; passer en banque2 SUBRV cbds_sendw,EEDATA ; envoyer data lue incf EEADR,f ; incrémenter pointeur EEPROM btfss STATUS,Z ; tester si terminé goto cbds_comO1 ; non, suivant goto cbds_boucle ; oui, commande suivante Il n’y a rien de bien particulier à dire ici. Utiliser l’instruction decfsz dans la boucle au lieu d’un incf suivit d’un btfss aurait permis de gagner une instruction. Seulement, on aurait reçu en premier l’emplacement 0x00, puis 0xFF, 0xFE etc. Ceci n’était pas pratique pour une simple instruction gagnée. Je n’ai pas retenu cette possibilité. La commande « G » permet le retour au programme principal. ;***************************************************************************** ; TRAITER COMMANDE "G" * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Retour au programme principal ;----------------------------------------------------------------------------- cbds_comG ; tester si reçu "G" ; ------------------ xorlw "O"^"G" ; comparer avec commande "G" btfss STATUS,Z ; tester si égalité goto cbds_err ; non, alors commande inconnue De suite après sont restaurés les registres qui ont été sauvegardés ;***************************************************************************** ; RESTAURER REGISTRES * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Restaure les registres modifiés par la routine de debuggage ; Restaure les registres INTCON,PIR1, et PIR2 si FREEZ est positionné ;-----------------------------------------------------------------------------

; Restauration registres interruption ; ----------------------------------- clrwdt ; effacer watchdog IFNDEF CBDS_NOFREEZ ; si mode FREEZ autorisé

123

bsf STATUS,RP0 ; passer banque 3 btfss 0x0E,6 ; bit FREEZ mis? goto cbds_restore2 ; non, sauter bcf STATUS,RP0 ; passer banque 2 movf PIR2_CBDS,w ; charger PIR2 sauvegardé bcf STATUS,RP1 ; passer banque 1 movwf PIR2 ; restaurer PIR2 bsf STATUS,RP1 ; passer banque 2 movf PIR1_CBDS,w ; charger PIR1 sauvegardé bcf STATUS,RP1 ; passer banque 1 movwf PIR1 ; restaurer PIR1 bsf STATUS,RP1 ; passer banque 2 movf INTCON_CBDS,w ; charger INTCON sauvegardé movwf INTCON ; restaurer INTCON ENDIF ; fin d'assemblage conditionnel ; restauration autres registres ; ----------------------------- cbds_restore2 bcf STATUS,RP0 ; passer banque2 movf PCLATH_CBDS,w ; recharger ancien PCLATH movwf PCLATH ; le restaurer movf FSR_CBDS,w ; charger ancien FSR movwf FSR ; restaurer FSR swapf status_CBDS,w ; swap ancien status, résultat dans w movwf STATUS ; restaurer status swapf w_CBDS,f ; Inversion L et H de l'ancien W swapf w_CBDS,w ; Réinversion de L et H dans W return ; retour au programme principal Si l’utilisateur choisi d’indiquer CBDS_NOFREEZ dans son programme principal, la routine de restauration des registres d’interruption ne sera pas assemblée lors de l’assemblage du programme. Par contre, s’il ne choisit pas cette possibilité, la routine sera présente, et donc occupera les emplacements mémoire programme concernés, même si l’utilisateur choisi alors de ne pas procéder à la restauration en ne positionnant pas le bit FREEZ. Il est donc important de bien comprendre la différence entre : IFNDEF CBDS_NOFREEZ ; si mode FREEZ autorisé Qui est une directive précisant que les lignes suivantes ne feront pas partie du programme final (n’existeront pas), et : btfss 0x0E,6 ; bit FREEZ mis? goto cbds_restore2 ; non, sauter Qui précisent que les instructions suivantes seront passées, mais existeront bel et bien dans le programme final. Ici, pas d’économie de place, on n’exécute simplement pas le code présent. L’utilisateur dispose alors du choix permanant de passer de l’utilisation ou pas par clic d’un simple bouton dans le programme PC. Maintenant, on va traiter les commandes erronées :

124

;***************************************************************************** ; TRAITER COMMANDE ERRONEE * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Si commande inconnue, ou si paramètres incorrects, alors erreur ; réponse : 3 octets : Exx ;----------------------------------------------------------------------------- cbds_err SUBRS cbds_endrec ; attendre fin de réception éventuelle SUBRC cbds_sendw,"E" ; envoyer "E" goto cbds_comP2 ; et 2 octets quelconques Il fallait ici pouvoir distinguer un message d’erreur d’une réponse classique. Imaginons que notre erreur renvoie simplement « E » L’utilisateur pense envoyer une commande dont la réponse est donnée sur un octet, et il se trompe ou un parasite détériore la commande. Il reçoit alors « E » en réponse, car le programme PIC® détecte l’erreur. Il est alors impossible de savoir, au niveau du PC, si «E », donc 0x45 est la valeur de réponse de la commande, ou un message d’erreur. J’ai donc choisi un message d’erreur qui renvoie 3 octets. Comme il n’y a aucune commande qui renvoie 3 octets, le seul fait de compter ces octets permet à coup sûr de détecter un message d’erreur. Pour économiser de la place, et comme le simple fait d’envoyer un message de 3 octets précise qu’il s’agit d’une erreur, j’envoie « E » suivi par 2 octets quelconques que j’ai « empruntés » à une autre commande. Nous avons maintenant nos sous-routines, déjà expliquées au chapitre précédent, mais avec gestion du watchdog intégrée : ;***************************************************************************** ; Attendre fin du trafic RS232 * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Attend que le PC n'émette plus avant de sortir ; ON effectue 30 mesures à intervalles d'un demi-bit. Si toutes valident le ; repos, alors on sort ; on entre sur n'importe quelle banque et on sort sur la banque 2 ;----------------------------------------------------------------------------- cbds_endrec movlw D'30' ; pour 20 lectures movwf cbds_cmptb ; dans compteur cbds_endrecl clrwdt ; alors effacer watchdog btfss RXPIN ; lire si pin entrée est au repos goto cbds_endrec ; non, on recommence cbdsT CBDS_1B/2 ; tempo d'une durée d'1/2 bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto cbds_endrecl ; pas dernière lecture, suivante RET ; pas de réception en cours ;***************************************************************************** ; Envoi d'un octet * ;***************************************************************************** ;----------------------------------------------------------------------------- ; envoie l'octet contenu dans w

125

; si entrée par cbds_sendbyte, on envoie l'octet contenu dans cbds_byte ; l'octet cbds_byte est détruit par l'opération ; on entre en banque2, on sort en banque2 ;----------------------------------------------------------------------------- cbds_sendw

; envoyer start-bit ; ----------------- movwf cbds_byte ; sauver octet à envoyer cbds_sendbyte bcf TXPIN ; générer start-bit cbdsT CBDS_1B ; attendre 1 bit movlw 0x08 ; 8 bits à envoyer movwf cbds_cmptb ; dans compteur de bits nop ; 1 cycle en plus

; envoyer 8 bits de data ; ---------------------- cbds_sl rrf cbds_byte,f ; lire bit poids faible btfss STATUS,C ; tester si bit = 0 bcf TXPIN ; oui, envoyer 0 btfsc STATUS,C ; tester si bit = 1 bsf TXPIN ; oui, envoyer 1 cbdsT CBDS_1B ; attendre durée d'un bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto cbds_sl ; pas dernier, suivant

; envoyer stop-bit ; ---------------- goto $+1 ; attendre fin délai bit 7 goto $+1 goto $+1 bsf TXPIN ; générer stop-bit cbdsT CBDS_1B5 ; attendre 1,5 bit par précaution clrwdt ; effacer watchdog RET ; et sortir ;***************************************************************************** ; Réception d'un octet * ;***************************************************************************** ;----------------------------------------------------------------------------- ; Reçoit un octet, le retourne dans cbds_byte ; On entre en banque 2, on sort en banque 2 ;----------------------------------------------------------------------------- cbds_rec clrwdt ; effacer watchdog btfsc RXPIN ; pin réception = 0? goto $-2 ; non, attendre cbdsT CBDS_1B5 ; attendre 1,5 bit clrf cbds_byte ; effacer octet reçu movlw 0x08 ; pour 8 bits movwf cbds_cmptb ; dans compteur de bits cbds_rec1 bcf STATUS,C ; par défaut, bit = 0 btfsc RXPIN ; bit reçu = 1? bsf STATUS,C ; oui, positionner carry nop ; pour correction du temps rrf cbds_byte,f ; faire entrer bit reçu cbdsT CBDS_1B ; attendre 1 bit decfsz cbds_cmptb,f ; décrémenter compteur de bits goto cbds_rec1 ; pas dernier, suivant

126

clrwdt ; effacer watchdog RET ; retour errorlevel +302 ; remet les warnings de banque errorlevel +220 ; remet les warnings d'adresse errorlevel +306 ; remet les warnings de page IFDEF CBDS_AUTON ; si on est en mode autonome errorlevel -212 ; car le ENDIF ne sera pas pris en compte END ; directive fin de programme ENDIF ; fin d'assemblage conditionnel Remarquez les instructions « goto $+1 ». Qu’est-ce que ça peut bien signifier ?

En réalité, ça signifie « sauter à la ligne suivante », ce qui est parfaitement inutile. J’avais besoin ici de perdre 6 cycles d’instruction, je pouvais donc écrire 6 instructions « nop ». Mais ces 6 instructions occupaient 6 positions en mémoire programme, alors qu’un saut, lui, consomme 2 cycles, mais pour une seule instruction écrite.

En remplaçant mes 6 « nop » par 3 « goto $+1 », je gagne donc facilement 3 instructions.

Le fait qu’il s’agisse d’un « faux » saut ne change rien, le PIC® exécute en interne toute la procédure mise en place pour un saut habituel. Remarquez le dernier bloc. Si on est en mode programme autonome, alors on doit placer un « END » en fin de programme. Sinon, on ne doit pas le mettre. Mais, si on est en mode programme autonome, alors le « END » sera pris en compte, ce qui stoppe l’assembleur, qui ne pourra alors pas prendre en compte la directive ENDIF, située après le END. Celle-ci est cependant indispensable en mode routine de debuggage. Or, si l’assembleur ne détecte pas le « ENDIF », alors nous aurons un warning numéro 212. C’est pourquoi j’ai ajouté la suppression du warning dans le test. Notez qu’il n’y a nul besoin de remettre le warning 212 en service. En effet, il n’est opérationnel qu’en mode programme autonome, aucun programme principal étranger ne suivra donc cette directive. Remarque importante : Cette routine a été écrite pour le 16F876 ou le 16F877, c’est-à-dire des PIC® disposant de RAM dans les banques 2 et 3. Ce n’est pas le cas des 16F873 ou 16F874.

Si vous voulez debugger sur un de ces derniers cités, vous avez 2 options : - Soit vous modifiez CBDS pour y insérer tous les changements de banques nécessaires,

ainsi que de gérer l’augmentation de taille qui en résulte. - Soit vous utilisez un PIC® 16F876 ou 16F877 pour effectuer votre debuggage.

Je préconise fortement cette seconde solution, car en procédant de la sorte, vous évitez le risque de tomber à court de mémoire RAM.

Vous allez penser que ceci représente dans ce cas particulier un achat supplémentaire.

127

Effectivement, mais, de toute façon, vous pourrez réutiliser ce PIC® de debuggage pour

une autre application. Et, de plus, si vous aviez construit l’ICD® officiel, vous auriez été contraint de « sacrifier » à demeure un 16F876 sur l’interface en question.

Si, en plus, vous remarquez que la différence de prix entre 16F876 et 16F873 est minime,

alors autant travailler avec les PIC® les plus performants (surtout pour des applications en série limitée).

Une fois le programme écrit, lancez l’assemblage via MPLAB®. Vous placez le fichier

« cbds.hex » obtenu dans le PIC®, à l’aide de IC-Prog, et vous réalisez le montage décrit au chapitre 8. Placez le PIC® dans la sonde, et la sonde sur le circuit, comme expliqué précédemment.

Vous pouvez maintenant passer à l’étude de BIGOPIC_Pro.

128

11. Le programme PC BIGOPIC_Pro 11.1 Introduction J’avais décidé d’arrêter ici ce projet, puisque vous disposiez d’une version simple opérationnelle, et d’une version optimisée du debugger PIC® comprenant tous les renseignements voulus pour faire votre propre application. Cependant, vu que certaines personnes ont fait l’effort de contribuer directement, et que d’autres placent à disposition des autres personnes des tonnes d’informations sur leur propre site, j’ai choisi d’ offrir un « bonus » à toutes ces personnes. ☺ Ce bonus est en l’occurrence un programme de debuggage complet, d’utilisation très simple, et entièrement symbolique. Son confort d’utilisation me semble équivalant à l’officiel ICD® de Microchip®. Il est donc réservé à ceux qui m’ont envoyé une contribution, et à tous ceux qui disposent d’un site Internet (pas une simple page perso) qui propose gratuitement des informations, assistances, forums, logiciels freeware etc., et ce, dans tous les domaines techniques (électronique, informatique..). Si vous n’avez pas accès à la partie concernée du site, et que vous estimez remplir les conditions, vous pouvez m’envoyer un mail à : [email protected] Je ne garantis aucunement une suite positive à la requête, qui sera fonction de mon appréciation. Ce n’est donc pas du tout un programme soumis à payement, mais un logiciel destiné à remercier ceux qui permettent que vive l’Internet libre. Je conserve tous les droits sur le logiciel, et je ne suis responsable d’aucun préjudice, direct ou indirect pouvant résulter de son utilisation. Le logiciel est fourni « tel quel », je tenterai de corriger les bugs qui se présenteront, mais je n’y suis tenu en aucune façon, de même que le fait de contribuer n’impose nullement la mise à disposition de ce logiciel. N’oubliez pas que cela reste un cadeau, non un achat. Toute utilisation commerciale est soumise à mon autorisation écrite, la distribution est interdite, le logiciel « BIGOPIC_Pro » ne pouvant être téléchargé que sur mon site. Pour l’instant, je conserve cette formule de mise à disposition, il n’est pas exclus qu’un jour je libère complètement ce logiciel, mais ce n’est pas à l’ordre du jour. J’estime qu’il faut bien que les efforts de certains soient récompensés.

129

11.2 Le cahier des charges Commençons maintenant par les choses intéressantes. De quoi devra donc être capable BIGOPIC_pro ? En fait, je suis parti des souhaits suivants : - Reprise de toutes les fonctions de BIGOPIC_light - Exploitation du bootloader via le mode debugger - Debugger complètement paramétrable - Accès aux valeurs des registres SFR sous forme symbolique - Reconnaissance automatique des noms de variables symboliques - Edition directe des valeurs symboliques - Visualisation et modification de la zone eeprom - Affichage du code source automatique - Suivi et placement du point d’arrêt directement dans le code source - Environnement simple et convivial - Sauvegardes automatiques des registres modifiés - Gestion du pseudo mode Freez - Gestion transparente des valeurs sauvegardées par rapport aux adresses réelles - Blocage automatique de la position du point d’arrêt - Edition et affichage des valeurs en décimal et hexadécimal, + affichage en ascii - Blocage des zones affichées sur la zone choisie par l’utilisateur - Rafraîchissement automatique des valeurs - Signalement automatique des conditions d’interruption en mode pas-à-pas. - Enregistrement de tous les paramètres et sélections utilisateur.

Je pense être parvenu à respecter ce cahier des charges. Forcément, d’ailleurs, puisque si je n’y étais pas arrivé, il m’aurait suffit d’effacer la ligne correspondante et vous le l’auriez jamais su. ☺ ☺ ☺

130

11.3 Lancement de BIGOPIC_Pro Une fois le logiciel récupéré sur mon site : www.abcelectronique.com/bigonoff , il vous suffira de lancer l’exécutable pour procéder à son installation. Un raccourci est alors créé par défaut dans le menu « démarrer ». Une petite remarque : dans le répertoire d’installation, par défaut : « C:\program files\BIGOPICPro », un fichier « BIGOPICp.cfg » sera créé à chaque fois que vous quittez le programme. Si vous souhaitez revenir un jour aux paramètres par défaut, tels qu’expliqués dans la suite de ce cours, il vous suffira d’effacer ce fichier avant de lancer le logiciel. Une fois tout ceci terminé, lancez « BIGOPIC_Pro ». Vous obtenez une fenêtre comme celle-ci (les captures d’écran ne sont pas remises à jour lors des révisions du logiciel, vous pouvez donc constater des différences à certains endroits).

Si vous avez utilisé le fichier « cbds.hex » que je vous ai fourni dans votre PIC®, alors toutes les valeurs par défaut de BIGOPIC_Pro sont bonnes. Vous n’avez rien à changer à ce niveau pour l’instant.

131

Par défaut, BIGOPIC_Pro est paramètré en mode debugger, mais vous pouvez travailler avec le mode bootloader et le mode DTRA, tout comme BIGOPIC_Light. Pour passer d’un mode à l’autre, il vous suffit d’utiliser le menu « mode ». 11.4 Chargement du fichier exécutable La première chose à faire, est d’envoyer notre programme d’application dans le PIC®. Pour ceci, nous allons repartir de notre fichier Led_tmrd1.asm. Effectuez une copie de ce fichier, renommez-la en « led_tmrd.asm ». Créez un nouveau projet dans MPLAB®. Si vous avez déjà modifié les paramètres par défaut de MPLAB®, éditez le projet, regardez les propriétés du nœud (voir cours première partie), et vérifiez que la case « List File » est bien cochée. En effet, pour bénéficier de toutes les facilités, BIGOPIC_Pro a besoin du fichier « LST » créé par MPASM®. Ici est utilisé MPLAB®5, pour les explications sur la version 6, chargez une version récente du cours-part1.

Ensuite, pour bien respecter la norme, et bien que cela ne soit pas indispensable, nous allons ajouter un "nop » à l’adresse 0x00 ;***************************************************************************** ; DEMARRAGE SUR RESET * ;***************************************************************************** org 0x000 ; Adresse de départ après reset nop goto init ; Initialiser Lancez l’assemblage avec <F10>.

132

Revenez dans BIGOPIC_Pro, et cliquez sur l’icône d’ouverture du fichier. Localisez votre répertoire d’assemblage, et sélectionnez le fichier « Led_tmrd.hex » que vous venez de créer.

Cliquez ok, ou double-cliquez sur le nom du fichier. La fenêtre se ferme, et vous voyez votre source apparaître dans la fenêtre ASM de votre programme.

133

Vous pouvez, si vous le désirez, redimensionner toutes les fenêtres, y compris la fenêtre principale, afin de mieux visualiser les contenus. Les nouvelles dimensions que vous avez choisies seront mémorisées pour la prochaine utilisation. Nous allons maintenant établir la communication avec CBDS qui se trouve dans le PIC®. Si vous avez déjà mis en pratique les chapitres précédents, tout devrait bien se dérouler. Par défaut, le logiciel communique sur le port COMM1. Si votre interface n’est pas connectée sur ce port, modifiez la configuration en cliquant sur la seconde icône de la barre d’outils, représentant une fiche suivie d’un point d’interrogation. Confirmez la modification. Cliquez maintenant sur la première icône, permettant d’établir la communication. Les fiches doivent se rejoindre. Ensuite, cliquez sur le bouton « reset », représenté par un « R » en rouge à côté de la fiche. A ce moment, le PIC® doit répondre, et les fenêtres doivent se remplir.

Si vous obtenez quelque chose d’équivalent, vous êtes sauvés, c’est que tout se passe bien.

134

Dans la fenêtre de droite, intitulée « SFR », vous voyez tous les registres spéciaux utiles du PIC®. Ces registres contiennent les valeurs telles qu’elles étaient au moment de l’arrêt. Autrement dit, tout ce qui concerne les adresses de sauvegarde est pris en charge par le logiciel. Ces valeurs sont incluses dans le fichier « Breg.cfg ». Si vous voulez d’autres registres dans la fenêtre FSR (utilisation d’un autre PIC®), il vous suffit d’insérer la ligne, composée du nom de registre suivi de son adresse. De préférence, insérez cette valeur à l’emplacement correspondant à son adresse. De même, vous pouvez éliminer les registres qui ne vous intéressent pas (déconseillé). Dans la fenêtre « RAM », vous voyez le contenu de la RAM, tel qu’il est réellement dans le PIC®. Alors que le simulateur de MPLAB® vous gratifie de « 0 » au démarrage, ici vous vous rendez compte que les contenus sont aléatoires. Vous verrez les noms de variables utilisés par votre programme dans cette fenêtre. C’est ainsi que vous voyez la variable « cmpt », à l’adresse 0x20, ce qui correspond bien à ce que vous avez déclaré dans le fichier « Led_tmr0.asm ». L’étiquette « start », qui correspond à l’adresse 0x21 de la mémoire programme, est interprété comme une variable à l’emplacement 0x21. Ce n’est pas réellement une variable, mais ce n’est pas gênant. Il n’y a aucune façon d’éviter ça en partant du fichier list, et, du reste, MPLAB® vous proposera également cette « variable » si vous faites défiler le menu de la fenêtre de modification des variables. Si vous aviez utilisé une vraie variable à cet emplacement, c’est son nom que vous auriez vu à l’emplacement concerné. Donc, rien de gênant Vous pouvez faire défiler les zones, soit à l’aide des flèches du clavier, soit via le curseur à la droite de chaque fenêtre. Notez que pour votre confort, les titres restent visibles en permanence. De même, dans la fenêtre FSR, le contenu du registre W reste visible en permanence (j’ai pensé à votre confort). La dernière fenêtre vous montre le contenu de la mémoire eeprom. Nous allons maintenant vérifier que notre programme est bien chargé dans BIGOPIC_Pro, et qu’il se trouve bien à l’emplacement prévu. Allez dans le menu « mode », et sélectionnez « bootloader ». Vous voyez maintenant le contenu de votre programme, et vous disposez des mêmes possibilités que celles étudiées dans le cours sur le bootloader. Je n’y reviendrai pas. Notez simplement que votre programme commence ici en adresse 0x00. Il n’y a pas de conflits ici, étant donné que le debugger n’a pas besoin d’une adresse de saut en page 0.

135

Vous voyez parfaitement votre « nop » à l’adresse 0x00, et votre « goto » à l’adresse 0x01 (souvenez-vous qu’une instruction qui commence par « 0x28 » est un « goto » (voir cours sur le bootloader). Il nous faut maintenant charger ce programme dans le PIC®, à l’aide du bouton « envoyer vers PIC® », le 5ème de la barre d’outils. ATTENTION : Vous ne pouvez pas cliquer ce bouton lorsque vous êtes dans ce mode si vous travaillez avec le debugger. En effet, le programme croirait alors que vous avez chargé le bootloader dans le PIC®, alors qu’il s’agit du debugger. Le programme ne manquerait pas de vous informer de problèmes de communication. Vous devez donc commencer par revenir au mode « debugger », que vous n’étiez, du reste, pas obligé de quitter. Choisissez « mode->debugger », puis cliquez sur le bouton d’envoi.

136

Cliquez ensuite sur <envoyer flash >, et attendez un bref instant la confirmation de chargement. Cliquez ensuite sur <Quitter> pour revenir à l’écran précédent. Remarquez que le bouton <Démarrer programme PIC> n’est pas accessible lorsque cette fenêtre a été accédée depuis le mode debugger. Vous devrez le lancer depuis la fenêtre de debuggage, c’est voulu.

A ce stade, votre programme est chargé dans le PIC®. Cliquez sur le bouton de sélection du point d’arrêt, c’est celui avec le signal « stop » suivi d’un point d’interrogation. Dans la fenêtre qui s’ouvre, entrez 0, si ce n’est déjà fait, et validez votre choix.

137

Maintenant, cliquez sur le bouton <reset> de la barre d’outils. Ceci va resetter le PIC®, qui va démarrer et s’arrêter à l’adresse du point d’arrêt. Souvenez-vous que ce point d’arrêt résiste au reset.

Vous voyez maintenant que le programme a démarré, et l’adresse retournée par le debugger, c’est-à-dire l’adresse de l’instruction suivante, est indiquée dans le fichier source. La fenêtre Asm indique « goto init », qui est l’instruction suivante à exécuter. Souvenez-vous qu’au moment de l’arrêt, cette ligne n’a pas encore été exécutée, exactement comme dans le simulateur de MPLAB®. Si vous avez la curiosité de faire défiler la fenêtre SFR, jusqu’à visualisation des registres ICKBUG et BIGBUG, vous verrez que le bit INBUG de ICKBUG (bit 7) vous confirme que vous êtes bien en mode debugger, et que les autres bits sont à 0. L’adresse contenue dans BIGBUG vous confirme que vous êtes bien arrêtés à l’adresse 0x01. 11.5 En route pour le debuggage Maintenant, nous allons lancer le programme, bien que nous sachions déjà que ce programme ne fonctionne pas.

138

Cliquez sur l’icône « go/stop », le troisième en partant de la droite, qui représente un feu rouge qui devient vert. Le programme démarre, et votre LED ne clignote pas.

La plupart des boutons sont maintenant en grisé, étant donné que le PIC® ne peut plus communiquer avec votre debugger, puisqu’il exécute le programme principal. Puisque rien ne se passe, nous allons stopper notre programme et revenir dans le debugger. Pour cela, pressez de nouveau le bouton <go/stop> (notez qu’il représente maintenant un feu vert qui se transforme en rouge, pour signifier la mise à l’arrêt).

139

Remarquez que le programme vous indique de nouveau directement dans le source le point d’arrêt, à savoir quelque part dans la boucle principale. Comme la led ne s’allume pas, et que celle-ci est commandée dans la routine d’interruption, nous allons mettre un point d’arrêt à l’adresse 0x04. On pourrait le faire de nouveau en cliquant sur le bouton de la barre d’outils, mais on va procéder autrement. Faites défiler le programme dans la fenêtre asm, et repérez la première instruction suivant la directive 0x04. Double-cliquez ensuite n’importe où sur cette ligne. Vous êtes gratifiés de l’adresse effective d’arrêt.

Si vous cliquez sur la directive « ORG », ou sur une autre ligne ne correspondant pas à une instruction, vous serez averti par un message de recommencer votre frappe.

140

La ligne de break sélectionnée, elle, s’affiche en gras dans votre fichier source.

Notez que, si vous avez tout compris, à chaque arrêt du PIC®, l’adresse d’arrêt contenue dans ICKBUG et BIGBUG pointe sur l’instruction qui suit l’arrêt. L’adresse de break est donc continuellement modifiée. Cependant, BIGOPIC_Pro prend ceci en charge, et rafraîchit automatiquement cette adresse de break à chaque action sur le bouton « go/start ». Ainsi, votre adresse d’arrêt ne change que si vous précisez qu’elle doit changer. Lancez le programme par le bouton « Go/start ». Comme rien ne se passe de nouveau, arrêtez une nouvelle fois le programme. Vous pouvez en déduire que notre programme n’est pas entré dans la routine d’interruption. L’interruption est provoquée par le débordement du timer0. Nous allons commencer par voir si ce timer compte. Pour ça, cliquez une fois dans la fenêtre SFR, puis cliquez avec le bouton droit de la souris, et sélectionnez « rafraîchir » à plusieurs reprises. Vous constatez que le contenu de tmr0 ne change pas, preuve qu’il ne compte pas.

141

Un coup d’œil sur le livre part2 ou dans le datasheet, vous indique que le fonctionnement du timer0 dépend du registre Option_reg, à l’adresse 0x81. Faites défiler les registres de la fenêtre SFR jusqu’à faire apparaître le contenu de ce registre. J’ai dénommé ce registre « opt_reg » pour économiser la place. J’ai fait défiler jusqu’à ce qu’il se trouve juste sous le registre « W », afin de faciliter la lecture de la figure ci-dessous.

Vous constatez que la valeur binaire du registre option est « 10100111 », ce qui nous permet de voir que le bit T0CS est positionné, ce qui fait travailler le tmr0 en compteur et nom en timer. Nous allons donc modifier cette valeur, et, pour ça, double-cliquez simplement sur la ligne contenant le nom de ce registre. Modifiez le bit 5 de 1 à 0, pour annuler T0CS.

142

La nouvelle valeur hexadécimale est donc 0x87. Pressez <Accepter> pour valider. Ceci ferme la fenêtre. Vérifiez que le contenu de opt_reg a bien été modifié. Allez dans la fenêtre FSR, puis clic droit, et sélectionnez plusieurs fois « rafraîchir » pour vérifier que le timer varie maintenant. Démarrez de nouveau votre programme, toujours à l’aide du même bouton <Go/stop>. Le programme s’arrête immédiatement dans la routine d’interruption. Voici donc un problème trouvé. Nous allons essayer de relancer notre programme, pour voir si notre problème est résolu. Pour ça, il faut commencer par supprimer le point d’arrêt. Ceci s’effectue tout simplement en cliquant sur le 4ème bouton à partir de la droite, et qui représente une fin d’interdiction. Cliquez simplement une fois, vous n’aurez aucun message de confirmation. Relancez une nouvelle fois le programme et observez la LED. Celle-ci semble tout le temps allumée, il y a donc un autre problème. Arrêtez le programme par une nouvelle action sur le bouton d’arrêt. Replacez ensuite votre point d’arrêt sur l’instruction 0x04, puis relancez le programme, qui s’arrête à l’adresse 0x04. Nous allons maintenant passer en mode pas-à-pas pour observer ce qui se passe. Cliquez donc sur le bouton « Step » (l’avant-dernier). Tant que vous y êtes, cliquez également sur le bouton « freeze » (le dernier). Les 2 indicateurs de ces boutons sont maintenant au vert. Notez que je vous conseille en général d’utiliser le bit Freez lorsque vous utilisez le mode « step ». Ceci permet dans une certaine mesure, de compenser les bugs internes du PIC® à ce niveau. Néanmoins, une fois un de ces boutons enclenché, il convient de bien interpréter les informations fournies, ceci passe par la bonne compréhension de tout ce qui précède. Cliquez maintenant plusieurs fois sur le bouton <Go/start>, et vous verrez votre programme avancer ligne par ligne dans le source. Avancez jusqu’à l’instruction de sortie de la routine d’interruption.

143

Vous allez remarquer qu’il vous faudra presser 2 fois pour passer la directive « BANKSEL ». C’est parfaitement logique, puisque cette directive contient en fait 2 instructions de changement de banque. Il est donc logique qu’elle nécessite 2 arrêts.

Sur les directives intégrées, il n’est pas possible de visualiser les instructions contenues, par contre, j’ai prévu le cas pour vos macros, nous allons en reparler.

Vous voyez que vous êtes prêt à sortir de la routine d’interruption. Cliquez encore une fois.

Vous voici gratifiés d’un message d’avertissement. En fait, vous venez de sortir de la routine d’interruption. Souvenez-vous que le PIC® est incapable d’entrer dans une routine d’interruption lorsqu’il se trouve en mode pas-à-pas. Or, comme j’ai prévu ce cas,

144

BIGOPIC_Pro se charge de vous avertir qu’une condition d’interruption est rencontrée lorsque vous êtes en mode pas-à-pas. Ceci vous évite de surveiller sans arrêt vos registres d’interruption. C’est de nouveau un plus par rapport à l’ICD® et l’ICD2®. Mais, à la sortie de notre interruption, nous ne devrions pas avoir une nouvelle condition d’interruption, car cela signifierait qu’on entre sans arrêt dans la routine d’interruption. Cliquez <OK>, ce qui a pour effet d’annuler le mode pas-à-pas, et de placer le point d’arrêt à l’adresse 0x04. Ainsi, en mode pas-à-pas, un simple clic vous permet de suivre le vrai déroulement du programme, avec prise en compte des interruptions même en mode pas-à-pas. J’ai donc contourné ce bug du PIC®. Avant de relancer le programme, vérifions ce qui se passe, en examinant le registre « INTCON ». Celui-ci contient 0xA7, ce qui nous donne comme bits positionnés : GIE, INTF, T0IF, et RBIF. Les bits INTF et RBIF ont été positionnés du fait de l’allumage de la LED, présente sur RB0, et du fait de l’action sur RB6 pour stopper le programme. LE bit GIE est positionné par notre programme, qui autorise les interruptions. Reste le bit T0IF, qui a déclenché l’interruption. Or, ce bit est sensé avoir été effacé par notre routine d’interruption avant de sortir, comme à notre habitude. Une petite vérification permet de constater que j’ai « oublié » de resetter ce flag. Retournons dans MPLAB® pour corriger nos 2 erreurs. Tout d’abord l’initialisation de Option_reg. Il nous suffit de modifier la constante déclarée : ; REGISTRE OPTION_REG (configuration) ; ----------------------------------- OPTIONVAL EQU B'10000111' Puis, ajoutons le reset du flag T0IF :

;restaurer registres ;------------------- restorereg bcf INTCON,T0IF ; reset flag T0IF swapf status_temp,w ; swap ancien status, résultat dans w Maintenant, pour vous montrer comme BIGOPIC_Pro se comporte avec une macro, nous allons en créer une directement après le define : ;***************************************************************************** ; MACRO * ;***************************************************************************** BANK0 macro bcf STATUS,RP0 ; passer en banque 0 bcf STATUS,RP1 endm Nous allons maintenant remplacer nos deux directives « BANKSEL » par notre macro :

; Interruption TMR0 ; ----------------- BANK0 ; passer en banque 0

145

decfsz cmpt , f ; décrémenter compteur de passages et init ; initialisation PORTS (banque 0 et 1) ; ------------------------------------ BANK0 ; passer en banque0 Lancez l’assemblage, puis revenez dans BIGOPICPro. Il vous suffit de cliquer sur l’icône de chargement de fichier, et rechargez votre nouveau fichier « Led_tmr0.hex ». Notez que le programme a mémorisé le chemin d’accès à votre fichier, ceci afin de vous faciliter une nouvelle fois l’existence. Cliquez sur l’icône d’envoi vers le PIC®, et envoyez le programme avec <envoyer flash >. Notez que si vous oubliez d’arrêter le PIC®, vous recevrez un message de non réponse. Il vous suffit alors, pour vous sortir de ce mauvais pas, de cliquer sur « reset », puis, si le PIC® ne s’arrête pas, sur < Go/start>. En effet, après un reset, le PIC®, soit tourne sur son programme d’application, soit entre en mode debugger, selon la valeur attribuée au point d’arrêt (qui résiste au reset, je le rappelle). Votre programme est maintenant dans le PIC®. Cliquez sur le bouton de suppression du point d’arrêt, puis effectuez un <reset> pour redémarrer le PIC® au début. Si tout s’est bien passé, votre led clignote, et votre programme est debuggé. Stoppez le programme, et placez un point d’arrêt à l’adresse 0x00 (le nop du début). Si vous cliquez sur le bouton de démarrage, votre programme ne s’arrêtera jamais à l’adresse 0, pour la bonne raison qu’une fois passé cette adresse, votre programme led_tmr0 ne repasse jamais plus par 0x00. Pour le forcer à repasser par là, il suffit de le redémarrer en cliquant sur <reset> faites-le. Passez ensuite en mode pas-à-pas et en mode « freez ». Cliquez maintenant plusieurs fois sur le bouton de démarrage, jusqu’à arriver sur la ligne « clrf PORTB ». Vous remarquez que non seulement vous pouvez observer le déroulement des instructions contenues dans votre macro, mais qu’en plus les instructions en question sont écrites à l’endroit approprié du programme. N’est-ce pas plus pratique que la méthode MPLAB® qui, à chaque macro, saute dans la zone des déclarations et vous fait perdre le fil de votre programme ? De plus, ainsi, vous pouvez placer des points d’arrêt dans les macros, et vous voyez ce qu’à réellement écrit l’assembleur. ICD® et ICD2® sont incapables de placer des points d’arrêt dans les macros. Afin de différencier ce qui a été placé par la macro, le texte est affiché dans une couleur différente, directement sous le nom de la macro.

146

Nous allons effectuer une autre manœuvre : replacez le point d’arrêt sur l’instruction 0x04. Coupez le mode pas-à-pas, et lancez le programme. Celui-ci va s’arrêter à l’adresse 0x04, et pointer sur l’adresse 0x05. Répétez l’opération à plusieurs reprises, en observant le contenu de la variable « cmpt » dans la fenêtre « RAM ». Vous voyez qu’à chaque clic, la variable cmpt est décrémentée. En effet, dans notre programme, l’inversion de la LED s’effectue lors du passage à 0 de cette variable. Double-cliquez sur la variable. Entrez alors la valeur « 1 » pour cette variable.

147

Notez qu’à partir de cette fenêtre, il vous est loisible de modifier n’importe quelle variable ou n’importe quel registre, à l’aide du menu déroulant, ou même en entrant directement l’adresse concernée dans les cases d’adresse. :

Regardez l’état de votre LED, et cliquez sur le bouton de démarrage du programme : votre LED s’inverse. Vous pouvez également tenter de modifier directement le bit 0 du registre PORTB, pour piloter votre LED en direct. Attention cependant de ne pas modifier RB6 et RB7, ce qui pourrait bloquer le debugger. Ceci ne serait cependant pas bien grave, il vous suffirait de cliquer sur <reset>, et éventuellement sur <Start/stop>. Il nous reste une manœuvre à effectuer, à savoir la modification d’une valeur en zone eeprom. Il suffit pour cela de double-cliquer sur l’adresse à modifier dans la fenêtre eeprom, ou alors d’effectuer un clic droit, puis « modifier », et ensuite choisir l’adresse concernée. L’écriture en eeprom modifie les registres EECON1, EEDATA, EEDATH, EEADR, et EEADRH. Cependant, une fois de plus, le logiciel prend tout en charge, et s’occupe de restaurer immédiatement les registres en question. Vous n’avez donc pas à vous en préoccuper.

148

11.6 Conclusions Voilà, je pense avoir réalisé un outil pratique pour celui qui en ressent l’utilité. Je pense que la majorité des utilisateurs devraient trouver ici leur bonheur. Bien entendu, ce programme n’est pas parfait, il s’agit d’un premier jet, mais je pense néanmoins que, tel quel, il pourra déjà rendre pas mal de services lors des debuggages récalcitrants. L’option de bootloader intégrée permettra de corriger très vite les programmes, et de les tester en temps réel, sans devoir sans cesse retirer le PIC® de son support. Vous n’aurez donc à programmer qu’une fois le PIC® avec votre programmateur durant toute la période de mise au point. N’oubliez pas, une fois l’application au point, de reprogrammer votre PIC® sans y insérer le debugger, je vous rappelle que l’application finale ne peut tourner avec le debugger inclus. Je vous souhaite de bons debuggages.

149

Notes : …

150

Contribution sur base volontaire La réalisation de ces cours m’a demandé beaucoup de temps et d’investissements (documentations, matériel, abonnements, etc.). Aussi, pour me permettre de poursuivre, je vous demande, si cela est dans vos possibilités, et si vous appréciez ce que je fais, de contribuer un peu, chacun selon ses possibilités et ses désirs. J'ai donc besoin de votre aide pour continuer l'aventure. En effet, je ne dispose plus vraiment de la capacité de consacrer l'intégralité de mon temps libre à écrire des cours et des programmes sans recevoir un petit "coup de pouce". Cependant, je ne voulais pas tomber dans le travers en verrouillant l'accès aux fichiers, et en imposant un payement pour les obtenir. En effet, je tiens à ce qu'ils restent disponibles pour tous. J'ai donc décidé d'instaurer un système de contribution sur base volontaire en permettant à celui qui le désire, et en fonction de ses propres critères, de m'aider financièrement. Le but n'étant pas de me faire riche, mais plutôt de m'aider à "joindre les 2 bouts". Il ne s'agit donc pas d'un payement, ni d'une obligation. Il s'agit simplement d'une assistance sans promesse d'aucun sorte, et sans contrainte. Je continuerai à répondre au courrier de tout le monde, sans distinction, et sans interrogation à ce sujet. Une bonne méthode consiste donc, pour celui qui le désire, à télécharger le document choisi, le lire ou l'utiliser, puis décider si cela vaut ou non la peine de m'aider sur base de l'usage que vous en faites. Si oui, vous vous rendez sur mon site : www.abcelectronique.com/bigonoff ou www.bigonoff.org, et vous suivez le lien « cours-part1 ». Vous y trouverez, dans la page « contributions », la procédure à suivre. Pensez que ces contributions me sont très utiles, et contribuent à me permettre de continuer à travailler pour vous. Pour remercier ceux qui ont contribué, soit par l’envoi d’une lettre, soit par la création d’un site d’utilité publique, j’offrirai le logiciel BIGOPIC_Pro. N’oubliez pas de mettre votre email en caractère d’imprimerie, pour que je puisse vous répondre. Je réponds toujours au courrier reçu. Aussi, si vous n’obtenez pas de réponse, n’hésitez surtout pas à me contacter pour vérifier s’il n’y a pas de nouveau un problème. Merci d’avance à tous ceux qui m’ont aidé ou m’aideront à poursuivre ce travail de longue haleine. Je réponds toujours au courrier reçu. Aussi, si vous n’obtenez pas de réponse, n’hésitez surtout pas à me contacter pour vérifier s’il n’y a pas de nouveau un problème.

151

Merci d’avance à tous ceux qui m’ont aidé ou m’aideront à poursuivre ce travail de longue haleine.

152

B. Utilisation du présent document

Le présent ouvrage est une annexe des trois précédents ouvrages. Il décrit la mise en œuvre de la technologie de debuggage sur circuit, encore dénommée « ICD® » pour « In-Circuit Debugging »

Communiquez à l’auteur (avec politesse) toute erreur constatée afin que la mise à jour

puisse être effectuée dans l’intérêt de tous, si possible en utilisant le livre de report d’information présent sur la page de téléchargement du cours.

Pour ces raisons, et par facilité de maintenance pour moi, j’ai décidé que ce cours serait

disponible uniquement sur mon site : www.abcelectronique.com/bigonoff ou www.bigonoff.org

Aussi, si vous trouvez mon cours ailleurs, merci de m’en avertir. Bien entendu, j’autorise (et j’encourage) les webmasters à placer un lien sur le site,

inutile d’en faire la demande. Bien entendu, je ferai de même en retour si la requête m’en est faite. Ainsi, j’espère toucher le maximum d’utilisateurs.

Le présent ouvrage peut être utilisé par tous, la modification et la distribution sont interdites sans le consentement écrit de l’auteur.

Tous les droits sur le contenu de ce cours, et sur les programmes qui l’accompagnent

demeurent propriété de l’auteur. L’auteur ne pourra être tenu pour responsable d’aucune conséquence directe ou indirecte

résultant de la lecture et de l’application du cours ou des programmes. Toute utilisation commerciale est interdite sans le consentement écrit de l’auteur. Tout

extrait ou citation dans un but d’exemple doit être accompagné de la référence de l’ouvrage. J’espère n’avoir enfreint aucun droit d’auteur en réalisant cet ouvrage, je n’ai utilisé que

les programmes mis gracieusement à la disposition du public par la société Microchip®. http://www.Microchip®.com

Si vous avez aimé cet ouvrage, si vous l’utilisez, ou si vous avez des critiques, merci de

m’envoyer un petit mail ou de poster un message sur mon site. Je pense, après cette série de cours, faire un petit break sur cette famille de PIC®. J’ai pleins de projets, et nous nous retrouverons, soit pour de nouveaux cours sur d’autres familles, soit pour des réalisations pratiques de projets. Vous m’avez en effet prouvé que cette aventure vous intéressait, et que je ne travaillais pas pour rien. Laissez-moi seulement le temps de souffler un peu.

Certains continuent à envoyer des messages sur mon ancienne adresse. Prenez

connaissance de la bonne adresse, pour de pas encombrer des adresses non concernées. Vous risquez de plus d’attendre longtemps votre réponse. Sachez que je réponds toujours au courrier reçu, mais notez que :

153

- Je ne réalise pas les programmes de fin d’étude pour les étudiants (même en payant), c’est une demande qui revient toutes les semaines dans mon courrier. Tout d’abord je n’ai pas le temps, et ensuite je ne pense pas que ce soit un bon service. Enfin, pour faire un peu d’humour, si je donnais mes tarifs, ces étudiants risqueraient un infarctus.

- Je n’ai malheureusement pas le temps de debugger des programmes complets.

Inutile donc de m’envoyer vos programmes avec un message du style « Ca ne fonctionne pas, vous pouvez me dire pourquoi ? ». En effet, je passe plus de 2 heures par jour pour répondre au courrier, si, en plus, je devais debugger, j’y passerais la journée. Vous comprenez bien que c’est impossible, pensez que vous n’êtes pas seul à poser des questions. Posez plutôt une question précise sur la partie qui vous semble inexacte. De nombreuses personnes (plusieurs par semaine) m’écrivent en me disant : « je sais bien que vous ne debuggez pas les programmes, mais… ». Comprenez que si je donne suite aux « mais », alors autant ne rien dire.

- Si vous avez des applications personnelles, n’hésitez pas à les faire partager par tous. Pour

ce faire, vous pouvez me les envoyer. Attention cependant, faites précéder votre envoi d’une demande, je vous redirigerai alors sur une autre boîte, celle-ci étant limitée à 512K.

- Le cours est lisible sur toutes les plates-formes, mais, malheureusement, les utilitaires ne

tournent que sous windows. Il ne tient qu’à vous de développer l’application pour d’autres plates-formes, et d’en faire profiter tout le monde.

Je remercie tous ceux qui m’ont soutenu tout au long de cette aventure, et qui se

reconnaîtront. Nul doute que sans les nombreux encouragements reçus, ce livre n’aurait jamais vu le jour. Merci au webmaster de www.abcelectronique.com, pour son hébergement gratuit. Merci à Byte, pour sa proposition d’hébergement gratuit. Merci à Grosvince pour sa proposition d’hébergement gratuit.

Merci à Bonny Gijzen pour la modification de IC-Prog, sans qui cette aventure n’aurait pu exister, faute de programmateur. www.ic-prog.com Merci à Torium pour l’adaptation aux versions 16F87xA. Dernière remarque : il est impossible que vous trouviez trace d’un plagiat ici, tout comme dans les précédents cours, étant donné que je n’ai lu aucun ouvrage sur le sujet, autre que les datasheets de Microchip®. Tout est donc issu de mes propres expériences. - Edition terminée en révision beta le 04/12/2002. - Révision Beta 1 le 22/04/2003 : correction page 44 et ficher dtra.asm : inversion du

registre status. - Révision 1 le 22/10/2003 : Suite à l’absence de report d’erreur, la révision Beta1 devient

la révision 1

154

- Révision 2 le 09/06/04 : Modification de mon adresse courrier - Révision 3 le 26/11/04 : Ajout de la gestion des versions A (16F87xA) par Torium. - Révision 4 le 25/11/07 : Ajout d’une remarque dans l’introduction. Ajout de la mention

légale ® à la demande de Microchip®. Réalisation : Bigonoff

Email : [email protected] (Attention BIGOCOURS, PAS BIGONOFF)

155