Changes between Initial Version and Version 1 of li326-BasePIC


Ignore:
Timestamp:
Jan 24, 2014, 3:57:31 PM (10 years ago)
Author:
Franck Wajsburt
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • li326-BasePIC

    v1 v1  
     1{{{
     2#!html
     3<h1 align=center><u>Prise en mains de l'assembleur pic et des outils de développement</u></h1>
     4}}}
     5[[PageOutline]]
     6
     7= Objectif =
     8
     9Le but de ce premier TME est de vous faire une présentation progressive des outils de développement pic sur la base d'un programme très simple, un chenillard, dont vous allez construire et simuler 3 variantes. Vous pourrez aussi tester les séquences de programme écrits la semaine dernière. Nous n'utiliserons pas la maquette au cours de ce premier TME.
     10
     11= Flot de conception =
     12
     13== Aide mémoire sur l'assembleur pic16f877
     14
     15 * [wiki:file-p16f877.inc Noms des symboles du pic16f877]
     16 * [htdocs:3_pic16f877_instruct.pdf Liste des instructions.]
     17
     18== Les outils ==
     19
     20On peut distinguer 5 étapes pour la conception d'un programme en assembleur, avec des rebouclages à chaque étape.
     21 1. `vi ou emacs                `spécification et saisie du programme
     22 1. [htdocs:gpasm.pdf gpasm] Assemblage pic (c'est en fait un des outils de la suite logicielle gputils)
     23 1. [htdocs:gpsim_0.21.2.pdf gpsim] Simulation / debugage graphique PIC
     24 1. [htdocs:picprog_1.17.pdf picprog] programmation et chargement de code dans le µC
     25 1. test
     26
     27== Spécification ==
     28
     29L'analyse du problème est une étape nécessaire quelque soit le langage de programmation utilisé. Toutefois, dans le cas d'un système embarqué et en particulier dans cas d'un microcontrôleur,
     30l'analyse ne peut être faîte correctement que si on a une connaissance précise du microcontrôleur visé et du matériel qui l'environne. Ce module a pour but de vous donner une méthode de travail vous permettant d'aborder la programmation en assembleur du pic16, mais la méthode est valable pour n'importe quel microcontrôleur. Il faut connaitre :
     31
     32 * le microcontrôleur et son langage d'assemblage,
     33 * les modules périphériques internes et externes utilisés,
     34 * la méthode de prise en compte des évènements,
     35 * et avoir une méthode de programmation.
     36
     37La saisie du programme se fait avec un éditeur classique. Comme tous les programmes ont une structure commune, il est bien de fabriquer des modèles de programmes que l'on adapte au besoin.
     38
     39== Assemblage ==
     40
     41Le but d'un assembleur est de traduire un programme écrit sous forme d'une séquence d'instructions simples et de sauts conditionnels ou pas, en code machine pour un processeur donné.  Un programme source est constitué d'un fichier avec l'extention .asm (par convention pour le pic), fichier qui peut en inclure d'autres avec les extentions .asm ou .inc (encore par convention).
     42
     43L'assembleur est un langage plus complexe qu'il n'y parrait au départ.  À la base, un programme en assembleur est constitué de lignes comportant au plus une instruction.  Une ligne se découpe en quatre colonnes :
     44 1. la première colonne commence en tout début de ligne et contient au plus un mot. Ce mot, que l'on appelle aussi symbole ou étiquette, est associé à une valeur numérique représentant le plus souvent l'adresse de la case mémoire de l'instruction ou de la donnée courante. On peut aussi attribuer une valeur quelconque à une étiquette.
     45 1. la deuxième colonne commence après un espace ou une tabulation, elle contient le plus souvent une instruction, mais elle peut contenir une directive, dont on verra le rôle un peu plus loin. Les instructions, comme les directives peuvent avoir des paramètres en nombre quelconque mais fixe.
     46 1. la troisième colonne est séparée de la seconde par un espace ou une tabulation et contient la désignation des opérandes (s'il y en a) associées à l'instruction.
     47 1. la quatrième colonne et dernière commence par un ; et s'achève au retour chariot. Elle contient un commentaire.  {\bf Les commentaires sont très importants en assembleur}. Mais, il ne s'agit pas de décrire le comportement de chaque ligne, mais de décrire l'algorithme et la façon dont on l'utilise, c'est-à-dire la manière dont on passe les paramètres et ce qu'il en fait.
     48
     49Une fois qu'un programme est écrit, on utilise un logiciel assembleur, ici '''gpasm''', qui produit essentiellement trois fichiers:
     50 * `.hex ` code machine à écrire dans la mémoire programme du processeur.
     51 * `.cod ` code machine plus des informations sur le source destiné au simulateur.
     52 * `.lst ` contenant un journal de l'assemblage.
     53
     54== Simulation ==
     55
     56Un programme pic est destiné à être exécuté sur un pic, mais il est très difficile de faire une mise au point directement sur le pic, car il n'est normalement pas possible d'afficher l'état de la mémoire en cours d'exécution du programme.  Pour faire la mise au point on utilise donc un simulateur, qui se comporte comme le pic mais qui permet une exécution en pas à pas et montre l'état des registres à chaque instant.  Le simulateur que vous allez utiliser s'appelle '''gpsim''' et vous verrez qu'il permet des choses très utiles pour la mise au point des programmes.
     57
     58Notez toutefois que le pic dispose d'un mode de fonctionnement qui permet de le stopper à chaque instruction pour lire les registres internes.  Il existe aussi des émulateurs de pic qui se comportent comme des pic mais qui permettent de lire les registres à tout momment ou après qu'une condition soit réalisée. Nous n'utiliserons pas ses possibilités.
     59
     60== Tests ==
     61
     62Les tests réels se font directement sur le processeur. Pour que ce soit possible, il faut que le processeur dispose d'une mémoire spéciale pour le code machine, et qu'un programme associé à un matériel, que l'on nomme un programmateur, puisse envoyer le code issu de l'assembleur dans le processeur.
     63
     64Le pic que vous utilisez dispose d'une mémoire flash pour le programme et a la capacité de se faire reprogrammer en place (sans devoir le retirer de la plaque).  Le programmateur utilise le port RS232 du PC et est piloté par le logiciel **picprog**. Nous utiliserons par la suite un bootloader.
     65
     66= Travaux pratiques =
     67
     68== Mise en place de l'environnement ==
     69
     70 * Pour bash, ajouter dans le fichier `$HOME/.bashrc`
     71{{{
     72  . ~encadr/micro/env/micro.env.bash
     73}}}
     74 * Pour tcsh, ajouter dans le fichier `$HOME/.tcshrc`
     75{{{
     76  source ~encadr/micro/env/micro.env.tcsh
     77}}}
     78
     79Le but principal de ce script est d'ajouter à la variable PATH, le chemin où se trouve les outils de développement pic. Ne recopiez pas le script dans votre compte car celui-ci va évoluer en cours d'année.
     80
     81 * Vous allez maintenant creer un répertoire micro dans votre HOMEDIR
     82{{{
     83  mkdir ~/micro ; cd ~/micro
     84  mkdir tme1 ; cd tme1
     85}}}
     86 * Vous créerez ensuite un répertoire par projet. Pour ce premier TME, vous avez trois programmes à écrire, plus deux autres si vous êtes rapide.
     87{{{
     88  mkdir hello1 hello2 hello3
     89}}}
     90 * Placez-vous enfin dans hello1 et éditez le fichier `hello1.asm`
     91{{{
     92  cd hello1 ; vim hello1.asm
     93}}}
     94
     95== Le premier programme ==
     96
     97L'objectif de ce premier programme est de réaliser un chenillard sur les 8 bits du port D. Plus précisément, un bit du port D est mis à 1, et les autres sont mis à 0, puis le 1 se déplace à gauche ou à droite, jusqu'à ce qu'il disparaisse pour se retrouver dans le bit carry du registre STATUS, et réapparaisse à l'autre extrémité du port D.
     98
     99Le programme que nous allons écrire ne respecte pas les conventions d'écriture pic (pourtant obligatoire), mais ce n'a ici aucune importance, le simulateur va quand même l'accepter. Votre programme fait les choses suivantes:
     100 1. Placer le PORTD en sortie, en écrivant dans le registre TRISD.
     101 1. Mettre la valeur 1 dans le bit 1 du PORTD.
     102 1. Faire une rotation du registre PORTD.
     103 1. Boucler à l'étape 3 (le programme ne s'arrête jamais).
     104
     105PORTD et TRISD sont deux registres spéciaux ([htdocs:2_pic16f877_memory.pdf Description de l'espace mémoire, rôle des registres spéciaux.]) aux adresses respectives: 0x8 et 0x88.
     106
     107Le code du programme se trouve en annexe. Vous devez le recopier, intelligemment (c.-à-d. en comprenant ce que vous faîtes), l'assembler et le simuler pas à pas en observant bien les changements d'état des registres.
     108 * Pour faire l'assemblage vous utilisez la commande `gpasm`:
     109{{{
     110   gpasm -pp16f877 hello1.asm
     111}}}
     112 * simuler vous utilisez `gpsim`:
     113{{{   
     114   gpsim -pp16f877 -shello1.cod
     115}}}
     116
     117Mieux, vous allez écrire un Makefile très simple dans le répertoire hello1, avec trois cibles .PHONY a, s et c, qui réalise
     118respectivement l'assemblage, le lancement du simulateur, et le nettoyage du répertoire. Notez qu'à partir de la semaine prochaine
     119vous utiliserez un script pour l'assemblage.
     120 * Fichier `Makefile` dans le répertoire hello1
     121{{{
     122    .PHONY: a s c
     123    F=hello1
     124    a:;  gpasm -pp16f877 $(F).asm
     125    s:a; gpsim -pp16f877 -s$(F).cod
     126    c:;  \rm *.cod *.hex *.lst 2> /dev/null || true
     127}}}
     128
     129Vous allez voir que gpasm donne des messages lors de l'assemblage. Ici, gpasm vous demande de vérifier que vous avez bien effectué un changement de banc mémoire (initialisation des bits RP0 et RP1 du registre STATUS) avant d'accéder au registre 0x88. En effet, 0x88 est une adresse exprimée en hexadécimal (notation 0x) (ou b'10001000' en binaire) or seuls les 7 bits de poids faible de cette adresse sont codés dans l'instruction. Ces 7 bits sont complétés avec les 2 bits RP0 et RP1 du registre STATUS.  Dès que votre programme fonctionne, passez au suivant.  Ne faîtes pas trop d'essais avec gpsim sur hello1, si vous le faîtes tourner trop longtemps, gpsim plante car vous n'avez pas configuré le processeur correctement.
     130
     131Profitez ce ce premier programme pour regarder ce qui est produit par l'assembleur, c'est à dire les fichiers .hex et .lst (pas le .cod qui est un binaire non éditable).
     132
     133== Le second, pareil mais en mieux ==
     134
     135Le premier programme ne fait pas trois choses qui sont pourtant indispensables dans un programme.
     136 1. l'utilisation des noms symboliques des registres et champs du pic utilisé.
     137 1. la configuration du processeur.
     138 1. la programmation du gestionnaire d'interruption.
     139Vous vous placez dans le répertoire `hello2`, et vous recopiez en le renommant le fichier `hello1.asm` en `hello2.asm` et le `Makefile`.  Vous allez ensuite faire les modifications de ce programme suivant les indications qui vous sont données dans la suite.
     140
     141=== Les noms symboliques de registres ===
     142
     143Le pic dispose d'un grand nombre de registres spéciaux permettant d'accéder aux ressources internes. Ces registres portent des noms et sont présentés dans la documentation technique du processeur ([wiki:file-p16f877.inc noms des symboles]). On peut bien sûr utiliser directement leur numéro mais au détriment de la lisibilité et de la portabilité du programme. C'est pourquoi, pour chaque pic, il existe un fichier contenant la définition des noms symboliques de chaque registre spécial.  Ce fichier est inclus par la directive `include`. De plus, il peut être utile d'indiquer le nom du processeur cible dans le programme, ceci se fait par la directive `list`. Il est alors inutile de donner le nom du processeur lors de l'assemblage.
     144{{{
     145        list    p=16f877        ; definit le processeur cible
     146        include "p16f877.inc"   ; declaration des noms de registres
     147}}}
     148Vous pouvez aussi donner des noms aux registres destinés aux programmes avec la directive CBLOCK vue en cours.
     149
     150=== La configuration du processeur ===
     151
     152Le processeur dispose d'un registre de configuration à l'adresse 0x2007 dans la mémoire de programme permettant de lui donner certains comportements particuliers. Par exemple, on peut protéger en lecture la mémoire de programme, protéger en écriture la mémoire data eeprom, demander la mise en place du watchdog timer (nous verrons l'utilité de ce chien de garde ultérieurement), etc. Vous trouverez le détail de cette configuration à la page 120([htdocs:5_pic16f877_conf_reset_int_wd.pdf]) de la documentation technique 16f877. Pour demander une configuration particulière vous devez utiliser la directive `__CONFIG` de gpasm. En fait, vous utiliserez presque toujours la même configuration quel que soit vos programmes (sauf cas particulier), en l'occurence vous ajouterez en tête de vos programmes (au début de `hello2.asm`), mais après l'`include` et le `list`.
     153{{{
     154        ; Definition du registre de configuration du pic
     155        ; _CP_OFF   : le code n'est pas protege et peut être relu
     156        ; _WDT_OFF  : pas de timer watch dog
     157        ; _PWRTE_ON : attente d'un délai de 72ms apres le power on
     158        ; _HS_OSC   : le pic utilise un oscillateur à quartz
     159        ; _LVP_OFF  : pas de mode programmation basse tension
     160        __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF
     161}}}
     162Pour voir, l'effet de cette commande, après avoir fait l'assemblage, ouvrez le fichier `hello2.lst`, faites le décodage binaire du contenu de l'adresse 0x2007 et vérifiez page 120([htdocs:5_pic16f877_conf_reset_int_wd.pdf]).
     163
     164=== La programmation du gestionnaire d'interruptions ===
     165
     166Le pic16f877 réserve deux adresses pour les interruptions, l'adresse 0 et l'adresse 4. L'adresse 0 est utilisée pour l'interruption reset, l'adresse 4 est utilisée pour les interruptions normales (hors reset).
     167
     168L'interruption reset n'est pas masquable, elle survient pour différentes raisons définies par le mot de configuration.  Dans tous les cas, le programme en cours d'exécution s'interrompt et le pic va à l'adresse 0. Le registre STATUS permet de savoir la cause pour laquelle le code du reset a démarré.  Les raisons sont entre autres:
     169 * On active le signal MCLR, en mettant à 0 la broche du pic correspondante.
     170 * Une baisse de tension d'alimentation a été detectée.
     171 * Le compteur associé au watchdog a débordé.
     172
     173L'interruption normale du pic16f877 survient pour 14 causes différentes. Ces interruptions sont masquables.  Nous les verrons en détail plus tard. Dans tous les cas, le programme en cours d'exécution s'interrompt et le pic va à l'adresse 4. Différents registres permettent de connaitre la ou les causes de l'interruption. Quoi qu'il en soit, comme tous les programmes réels utilisent les interruptions, il faut réserver l'adresse 4 à cet usage.
     174
     175Modifiez votre programme, en utilisant la directive ORG, de manière à ce qu'à l'adresse 0, on fasse un appel à une routine INITIALISATION qui mette le port D en sortie, puis fasse un goto au programme MAIN qui réalise le chenillard sur le port D.  La routine d'interruption sera reduite à l'instruction `retfie`.
     176
     177Ce programme se trouve également en annexe. Essayez de ne pas regarder la correction tout de suite!
     178
     179== Le troisième, le même avec des macros ==
     180
     181L'assembleur pic est très frustre. Il y a peu d'instructions et celles-ci font peu de chose.  C'est à la fois, un avantage car il y a peu de choses à apprendre et un inconvénient car le texte des programmes est assez long et donc source d'erreur. Pour améliorer un peu les choses, il est possible de définir des macros instructions (ou simplement macros).  Il est très simple de créer une macro. Les macros sont placées au début, avant de les utiliser.
     182
     183 syntaxe d'une macro::
     184   {{{
     185   coop     macro   [args]...
     186               séquence d'instruction utilisant les args s'il y en a
     187            endm
     188   }}}
     189 
     190 exemple::
     191   Deux macros pour initialiser une valeur immédiate dans un registre, et pour faire la somme de deux registres sur 1 octet.
     192   {{{
     193   li1      macro   @reg, @val     ; @reg <- @val
     194               movlw @val          ; la valeur @val est placée dans w
     195               movwf @ref          ; w est recopié dans le registre reg
     196            endm
     197   
     198   add1     macro   @rd, @rs, @rt  ; @rd <- @rs + @rt
     199               movf  @rs,w
     200               addwf @rt,w
     201               movwf @rd
     202            endm
     203   }}}
     204   Dans le code on pourra alors écrire
     205   {{{
     206            CBLOCK 0x20
     207               A : 1
     208               B : 1
     209               C : 1
     210            ENC
     211
     212            li1  A, 46
     213            li1  B, 56
     214            add1 C, A, B
     215   }}}
     216
     217Certaines macros, particulièrement utiles, ont été intégrées à l'assembleur gpasm. C'est le cas de la macro `BANKSEL <r>` qui prend comme paramètre `<r>` un numéro de registre (entre 0 et 511[0x1FF] ou plus simplement sous sa forme symbolique) et qui initialise les bits RP0 et RP1 du registre STATUS en fonction du numéro du banc du registre. Entre 0 et 127[0x7F], les bits RP1 et RP0 sont mis à 0; entre 128[0x80] et 255[0xFF], les bits RP1 et RP0 sont mis respectivement à 0 et 1; entre 256[0x100] et 383[0x17F], les bits RP1 et RP0 sont mis respectivement à 1 et 0; enfin entre 384[0x180] et 511[0x1FF] les bits RP1 et RP0 sont mis tous les deux à 1.
     218
     219Recopiez en le renommant le fichier hello2.asm en hello3.asm dans le répertoire hello3, ainsi que le Makefile, puis utilisez la
     220macro BANKSEL avant d'utiliser TRISD et PORTD et utiliser la macro li1.
     221
     222== La suite... ==
     223
     224 k2000::
     225   une variante de hello3 avec un test en plus.  Vous devez faire un balayage du port D avec le bit à 1, de gauche à droite puis de droite à gauche.  Pour celà, il vous faut faire un test pour savoir si vous êtes au bit 0 (à droite) ou au bit 7 (à gauche) afin de changer de sens de décalage.  Vous devez utiliser un registre pour gérer le balyage, utilisez le registre 0x20.
     226 k2000_onoff::
     227   k2000 mais le balayage dépend de la valeur de la broche B0. Si B0 vaut 0, on stoppe le balayage, si B0 vaut 1 on reprend.
     228 
     229 Vous pouvez aussi essayer les séquences de programme demandées lors du premier TD.
     230
     231= Annexe =
     232
     233== hello1 ==
     234{{{
     235; ------------------------------------------------------------------------
     236; - ce programme est volontairement petit et ne fait appel a aucun fichier
     237; - Il ne doit pas etre considéré comme un modèle pour d'autres programmes
     238; ------------------------------------------------------------------------
     239
     240        ; ces deux lignes permettent de sélectionner le bank n°1
     241        bcf     0x3,6      ; STATUS(RP1) <- 0
     242        bsf     0x3,5      ; STATUS(RP0) <- 1  pour désigner le banc 1
     243
     244        ; programme le PORTD en sortie
     245        clrf    0x88       ; place tous les signaux du port D en sortie
     246
     247        ; on change à nouveau de bank
     248        bcf     0x3,5      ; STATUS(RP0) <- 0 revient sur le banc 0
     249
     250        ; on place 1 dans le registre relié au port D
     251        movlw   1          ;
     252        movwf   0x8        ; met 1 sur le bit 0 sur port D
     253       
     254loop
     255        ; rotation vers la droite sur 9 bits car utilise le bit carry
     256        rrf     0x8,f      ; rotation vers la droite du port D
     257
     258        ; on boucle sans fin
     259        goto    loop       ; on boucle sur la rotation
     260
     261; ------------------------------------------------------------------------
     262        END                   ; directive de fin de programme 
     263}}}
     264
     265== hello2 ==
     266{{{
     267; -------------------------------------------------------------------------
     268; - ce programme a le même comportement que hello1 mais il réserve l'usage
     269;   des adresses 0 et 4 pour le reset et l'interruption
     270; -------------------------------------------------------------------------
     271
     272        list    p=16f877        ; definit le processeur cible
     273        include "p16f877.inc"   ; declaration des noms de registres
     274
     275        ; Definition du registre de configuration du PIC
     276        ; _CP_OFF   : le code n'est pas protege et peut etre relu
     277        ; _WDT_OFF  : pas de timer watch dog
     278        ; _PWRTE_ON : attente d'un délai de 72ms apres le power on
     279        ; _HS_OSC   : le pic utilise un oscillateur à quartz
     280        ; _LVP_OFF  : pas de mode programmation basse tension
     281        __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF
     282       
     283        ORG     0
     284        call    initialisation
     285        goto    main
     286
     287        ORG     4
     288        retfie
     289
     290initialisation
     291        bcf     STATUS,RP1      ; STATUS(RP1) <- 0
     292        bsf     STATUS,RP0      ; STATUS(RP0) <- 1 permet de désigner le banc 1
     293        clrf    TRISD           ; place tous les signaux du port D en sortie
     294        bcf     STATUS,RP0      ; STATUS(RP0) <- 0 revient sur le banc 0
     295        return
     296
     297main
     298        movlw   1               ;
     299        movwf   PORTD           ; met 1 sur le bit 0 sur port D
     300loop
     301        rrf     PORTD,f         ; rotation vers la droite du port D
     302        goto    loop            ; on boucle sur la rotation
     303
     304; ------------------------------------------------------------------------------
     305        END                     ; directive de fin de programme 
     306}}}