ANNEXE : Microcontrôleur PIC Microchip Un microcontrôleur est un processeur destiné à se suffire lui-même pour la réalisation d’une application

autonome dite « embarquée » : il comporte un processeur, de la mémoire ROM, de la RAM ainsi qu’un certain nombre de coupleurs de périphériques (liaisons TOR parallèles, liaison série, timers, convertisseurs A/N et/ou N/A. Il peut également comporter de la mémoire EEPROM pour maintenir les variables d’états d’une application après une coupure de l’alimentation électrique. Les dispositifs de mise en veille pour les économies d’énergie sont de plus en plus présents. La société Microchip a développé une famille de microcontrôleurs dont l’utilisation est très répandue et nous allons plus particulièrement nous intéresser au groupe « PIC 16X » qui correspond au milieu de gamme. « X » est un système de référencement tenant compte des capacités mémoires RAM/ROM et du nombre de coupleurs de périphérique intégrés. Nous nous appuierons sur le cas du PIC 1 16f628 dont nous allons donner les caractéristiques essentielles. Physiquement, le PIC16f628 se présente sous la forme d’un petit (8×23 mm) circuit intégré à 18 broches à consommation électrique faible de l’ordre du milliwatt et dont le coût est de quelques euros. On est aux antipodes des processeurs d’usages généraux que l’on trouve dans les stations de travail et/ou les serveurs ! Architecture du PIC16f628. Le PIC16f628 est un processeur 8 bits à jeu réduit d’instructions, (RISC) avec une organisation de type Harvard au niveau de la mémoire. La mémoire de code est distincte de celle des données et il y a ainsi deux chemins d’accès (bus) séparés. La partie processeur est constituée d’une unité de P C CODE 8 13 RAM données contrôle servant au Mémoire séquencement des Flash Pile DATA 4 pages opérations, au décodage 2048 mots 14b EEPROM 224 registres (8 niveaux) 128 o d’adresse et à d’autres 14 services annexes, d’une unité Adressage Indirect MUX Reg Inst arithmétique et logique 8 bits Adressage Direct FSR associée à un unique registre de 7 8 8 travail W (Work). Les MUX « codes de conditions » sont mis Décodage Instruction à jour dans le registre STATUS. Tous les autres UAL Séquenceur Status Pipeline (2 étages) registres du processeur sont de Divers : Energie, Timing, … fait des emplacements W particuliers de la RAM. L’architecture RISC Xtal Horl implique que toutes les instructions ont la même Autres : timers, … USART Port A Port B taille (ici 14 bits) et leur exécution se fait en un seul cycle de 4 périodes d’horloge. Le parallélisme interne est assuré par un pipeline à deux étages : un étage de recherche d’instruction (phase fetch) et un étage d’exécution. La
                                                            
1

PIC est un nom déposé par Microchip, susceptible de signifier « Peripheral Interface Controller ».

séparation des mémoires de code et de données (Harvard) permet donc d’exécuter l’instruction n et de procéder à la phase fetch de l’instruction n+1. Modèle mémoire et registres. Autour du processeur central, on trouve une mémoire Flash pour le code (2048 motsinstructions de 14 bits), une EEPROM pour 128 octets de données et une RAM statique se comportant comme une suite ordonnée de registres de 8 bits (register file2). La RAM est répartie sur 4 pages (banks) accessibles par un adressage direct sur 7 bits (4 × 128 emplacements possibles) ou un adressage indirect sur 8 bits. Dans ce dernier cas, le registre FSR (File Select Register) sert de registre d’adresse pointant sur la case mémoire voulue. Les registres sont de deux types. Les registres GPR (General Purpose Register), au nombre de 224, sont utilisables comme support de variable au sens de la programmation, ce sont des registres en RAM et il y en a un certain nombre de disponibles dans chaque page. Dans le cas du PIC16f628 la page 3 ne comporte pas de mémoire disponible. Les registres SFR (Special Function Register), que l’on peut aussi appeler ‘Registres Système’, servent à la fois au processeur (par exemple FSR et STATUS déjà cités, mais aussi le compteur de programme PCL) et à la programmation des coupleurs d’Entrées-Sorties (adresses et paramétrage I/O des ports TOR et timers). L’espace mémoire d’entrées-sorties est donc intégré dans l’espace mémoire de données. Certains registres système sont globaux à toutes les pages (PC composé de PCL et PCLATH, STATUS, FSR, INTCON), d’autres sont spécifiques à des pages particulières.
PCL STATUS FSR PORTA PORTB PCLATH INTCON 02h 03h 04h 05h 06h 0Ah 0Bh PCL STATUS FSR TRISA TRISB PCLATH INTCON 82h 83h 84h 85h 86h 8Ah 8Bh PCL STATUS FSR PORTB PCLATH INTCON 102h 103h 104h 105h 106h 10Ah 10Bh PCL STATUS FSR TRISB PCLATH INTCON 182h 183h 184h 185h 186h 18Ah 18Bh

Special Function Register General Purpose Register 96 octets libres
20h

Special Function Register General Purpose Register 80 octets libres
EFh 7Fh A0h

Special Function Register General Purpose Register 48 octets libres
120h

Special Function Register

14Fh

1FFh

Bank 0

Bank 1

Bank 2

Bank 3

L’adressage direct est réalisé avec les 7 bits de numéro de registre contenu dans l’instruction ; la page courante est donnée par les 2 bits de numéros de pages RP0 et RP1 du registres STATUS. Dans l’adressage indirect, les 7 bits de registre sont en poids faible des 8 bits du registre FSR. Le 8ième bit de FSR concaténé avec le bit IRP de STATUS fournit l’accès à la page. L’adressage à la mémoire de code se fait avec une largeur de 14 bits dont 11 sont utilisés dans PIC16f628. Le registre PC, compteur de programme, est de fait constitué par deux
                                                            
2

Le terme file est important pour la suite, car dans l’assembleur PIC, l’accès à la RAM est référencée par la lettre f dans la syntaxe des instructions. RAM et registres du processeurs sont confondus.

registres. PCL fournit les 8 bits de poids faible (accessibles depuis l’UAL), les bits de poids forts restant sont dans le registre PCLATH. Dans le cas des instructions de branchement (Goto et Call), 11 bits de l’adresse de débranchement sont fournis directement par le registre d’instructions, les 2 bits manquants sont donnés par le registre PCLATH préalablement configuré. La pile est une zone de mémoire indépendante permettant une profondeur d’empilement de 8 niveaux (c’est une file circulaire : le 9ième élément écrase le 1er et … sans prévenir). Elle n’est pas manipulable directement et aucune indication n’est donnée sur son état à un instant donné. Le jeu d’instructions. Le µC PIC16f628 comporte 35 instructions ayant toutes une longueur de 14 bits. La syntaxe assembleur est du type Op, Src, Dest où OP, code opératoire, donne la nature (mnémonique) de l’instruction (move, add, …) et Src et Dest sont les paramètres Source et Destination de l’instruction. Dans les notations suivantes, f représente un registre en RAM (file), d est un spécificateur de destination : si d=0 le résultat est mis dans W, si d=1, il est mis dans le registre f spécifié dans l’instruction, b une position de bit et k une valeur immédiate appelée ‘literal’. Il y a quatre types d’instructions.
ADDWF ANDWF CLRF CLRW COMF DECF DECFSZ INCF INCFSZ IORWF MOVF MOVWF NOP RLF RRF SUBWF SWAPF XORWF f, d f, d f, d f, d f, d f, d f, d f, d f, d f, d f f, d f, d f, d f, d f, d Add W and f And W with f Clear f Clear W Complement f Decrement f Decrement f Skip if 0 Increment f Increment f Skip if 0 Inclusive OR W with f Move f Move W to f No Operation Rotate Left f through Carry Rotate Right f throuch Carry Substract W from f Swap nibbles with f Exclusive OR W with f

Les instructions orientées ‘octet’ portent sur un octet. Un bit indique la destination (W, registre de travail ou f registre) et 7 bits l’éventuel numéro de registre dans la RAM. Dans les exemples de programmes présentés, d sera directement remplacé par f ou w suivant que la destination est le registre-RAM ou le registre de travail W. Les instructions orientées ‘bits’ portent sur la manipulation d’un bit particulier (codé sur 3 bits) d’un registre en RAM (codé sur 7 bits).
BCF BSF BTFSC BTFSS f, b f, b f, b f, b Bit Clear b in f Bit Set b in f Bit Test b in f, Skip if Clear Bit Test b in f, Skip if Set

Les instructions à adressage immédiat comportent la valeur immédiate k sur 8 bits dans le code de l’instruction. Le résultat d’une opération arithmétique est toujours mis dans W. Les instructions de saut ont une destination décrite sur 11 bits. Il y a les instructions de saut (goto), d’appel de procédure (call) et 3 retours de procédure (Retxxx). Il n’y a pas vraiment d’instruction de saut conditionnel utilisant les drapeaux du registre d’état STATUS. Une manière de réaliser un ‘débranchement’ conditionnel est d’utiliser l’une des instructions d’incrémentation et de décrémentation d’un registre. Ainsi l’instruction
ADDLW ANDLW CALL CLRWDT GOTO IORLW MOVLW RETFIE RETLW RETURN SLEEP SUBLW XORLW k k k k k k k Add Literal to W And Literal with W Call subroutine Clear Watchdog Timer GoTo address f Inclusive OR literal with W Move Literal to W Return from Interrupt Return with Literal in W Return from subroutine Go into stanby mode Sunstract W from Literal Exclusive OR Literal with W

k k

DECFSZ f,d décrémente le registre f et met le résultat dans W ou f (suivant la valeur de d),

incrémente le compteur de programme PC de 1 (passe à l’instruction suivante) si le résultat est différent de 0 et incrémente PC de 2 dans le cas contraire (saute l’instruction suivante)
test DECFSZ compteur, f ;inst i (+1) GOTO suite (+2) CALL proc1 Suite … ;inst i+1 ;inst i+2 : le résultat valait 0

La variable compteur est décrémentée (résultat dans compteur car d=f) et un appel de procédure est réalisé quand le compteur passe à 0. L’autre manière de procéder passe par l’utilisation de l’une des deux instructions BTFSx (Bit Test and Skip if x). La structure de saut est semblable à celle de l’instruction DECFZ : saut de l’instruction suivante si la condition est vraie. Exemple de code Ce code initialise à 0 une table de 8 éléments et utilise pour ce faire l’adressage indirect. La boucle d’itération est faite sur la base d’une instruction de test de bit.
movlw movwf movlw movwf iter clrf Table FSR huit cpt INDF ; @Table mise dans W (reg en RAM) ; @Table mise dans le registre FSR ; initialise un compteur cpt à 8 ; ; ‘clear’ indirect, adresse dans FSR FSR ; FSR pointe sur l’octet suivant ; fini les 8 octets ? aller à suite ; l’initialisation continue.

incf decfsz cpt,f goto iter suite …

Les deux premières instructions mettent l’adresse de Table dans le registre d’adresse FSR. L’instruction CLRF INDF est particulière au sens du registre destination INDF. L’opération ‘clear’ porte sur un registre RAM INDF qui n’existe pas (adresse 0) mais qui indique que l’adressage à utiliser est indirect (INDirect File) avec l’adresse réelle dans FSR. C’est bien le registre d’adresse FSR qui est ensuite incrémenté pour pointer l’élément suivant. Le compteur cpt est décrémenté et la sortie de boucle réalisée quand il passe à 0.

Gestion des ports d’entrées sorties. Le µC PIC16f628 possède deux ports A et B d’entrées sorties, accessibles via les registres système PORTA et PORTB (adresses 05h et 06h). Chacun de ces ports est constitué d’un ensemble paramétrable de lignes multifonctions (TOR bidirectionnel, comparateurs analogiques, horloges, programmation mémoire Flash …). En configuration TOR, le paramétrage des lignes (RA0-7, RB0-7) en entrée ou en sortie se fait à l’aide des registres systèmes TRISA et TRISB (Transfert Input Set, adresses 85h et 86h) : un bit à 1 (Input) met la ligne correspondante du port en entrée, un 0 (Output) la met en sortie. Certaines entrées TOR peuvent activer une demande d’interruption.
; Exemple d’utilisation du PortB ; on suppose que les lignes sont configurées en TOR bcf STATUS, RP1 ; bsf STATUS, RP0 ; sélection page 1 : accès à TRISB movlw b’11110000’ ; movwf TRISB ; 4 bits en entrée et 4 bits en sortie bcf STATUS, RP1 ; bcf STATUS, RP0 ; sélection page 0 : accès à PORTB

movlw movwf

b’00000011’ PORTB

; ‘allumez’ 2 bits ; de poids faible en sortie de B

Dans l’exemple ci-dessus, on programme le positionnement des broches RB0 et RB1 à 1 (mise au niveau haut, allumer des ampoules LED par exemple). Au départ, on suppose que les broches du port B sont configurées en mode TOR. Avant d’agir sur les sorties ou de prendre en compte les entrées, nous allons d’abord configurer le sens d’utilisation de ces broches. Nous mettons les 4 bits de poids fort en entrée et les 4 de poids faible en sortie en écrivant la valeur ‘11110000’ dans le registre TRISB (page 1, adresse 86). Puis nous mettons les deux bits à 11 en écrivant la valeur ‘00000011’ dans le registre PORTB (page 0, adresse 06). Il est donc nécessaire de changer de page entre les deux commandes. Pour la lisibilité du code assembleur, on a tout intérêt à définir des macros de changement de page du type : SELECT_Page_0, SELECT_Page_1 par :
SELECT_Page_0 MACRO bcf bcf ENDM SELECT_Page_1 MACRO bcf bsf ENDM STATUS, RP1 STATUS, RP0 ; ; STATUS, RP1 STATUS, RP0 ; ;

sélection page 0

sélection page 1

Les interruptions. Le µc PIC16f628 autorise 10 sources d’interruptions parmi lesquelles l’interruption externe, d’usage général, via la broche RB0/INT, les changements de valeur sur les broches RB4-7 du portB, les signaux Tx et Rx de l’USART, et les dépassements (passage de ffh à 00h du compteur) de temporisateurs (timer). Si les principes généraux de la gestion des interruptions sont semblables à ceux d’un processeur classique, il y a quand même pas mal de singularités du point de vue de l’implémentation technique et donc de la mise en oeuvre au niveau de l’assembleur. Lors de la prise en compte d’une interruption, le compteur de programme PC est normalement sauvegardé dans la pile et restitué en sortie de routine d’interruption avec l’instruction RETFIE. Les interruptions peuvent être masquées soit globalement soit localement (plus ou moins individuellement) : des bits de configuration sont prévus à cet effet dans le registre-RAM INTCON (INTerrupt CONfiguration). Par contre, l’architecture interne implique les particularités suivantes. Il n’y pas de vecteur d’interruption, donc une seule routine à une adresse fixe (004) et l’identification de la source d’interruption doit se faire par scrutation. Le temps de latence se voit ainsi augmenté. Il n’y a pas de prise en compte d’une interruption pendant le traitement d’une autre : l’entrée dans la routine d’interruption masque automatiquement les interruptions, le démasquage est fait par RETFIE. Il n’y a pas d’interruptions logicielles. Il n’y a pas de hiérarchisation des interruptions par niveau, le traitement des interruptions est séquentiel (en fifo), éventuellement dans la même routine d’interruption. Au niveau des sauvegardes du contexte, seul PC est rangé dans la pile. Il est du ressort du programmeur de faire la sauvegarde du registre de travail W et du registre STATUS (registre

RAM). Mais, la pile n’étant pas accessible à la programmation, ces sauvegardes doivent nécessairement se faire dans les registres RAM. Or cette sauvegarde est pour le moins singulière en ce qui concerne STATUS. Il n’existe pas d’instruction de transfert d’un registre-RAM vers un autre (à part W) sans passer par W. Cela signifie en premier lieu qu’il faut d’abord obligatoirement sauvegarder le registre W. La sauvegarde de STATUS implique sa recopie dans W (movf STATUS, w), puis le transfert dans un registre (movwf svg_ST) que l’on aura affecté à cette destination. Or l’instruction movf de copie de STATUS dans W, considérée comme une instruction arithmétique (‘mettre’ un résultat dans W) modifie le drapeau Z de … STATUS et ne peut donc être utilisée. L’ « astuce » consiste alors à trouver une instruction permettant le transfert d’un registre dans W sans affecter STATUS. L’instruction swapf fait ce transfert, mais permute (swap) les 2 quartets du registre. Le registre est ainsi recopié avec cette permutation : à la restauration il faudra bien penser à faire la permutation inverse. L’ossature générale d’une routine de traitement d’une interruption avec sa séquence de sauvegarde-restauration pourra avoir la forme suivante :
CBLOC 0x020 ; début de la zone mémoire pour les données Svg_W : 1 ; 1 octet pour sauvegarder W Svg_ST : 1 ; 1 octet pour sauvegarder STATUS

ENDC ORG 0x004 ; adresse de début de la routine d’interruption ; sauvegarde de W et STATUS movwf Svg_W ; W est sauvegardé, STATUS intact swapf STATUS, w ; STATUS ‘permuté’ dans W, STATUS intact movwf Svg_ST ; STATUS ‘permuté’ sauvegardé dans Svg_ST ; sauvegarde d’éventuels autres registres (FSR par exemple) bcf STATUS, RP0 ; travailler en page 0 (par exemple) bcf STATUS, RP1 ; (bits RP0 et RP1 de STATUS mis à 0) ; identification de la source d’interruption ; traitement de l’interruption ; acquittement de l’interruption ; restauration des éventuels autres registes ; restauration de STATUS et W swapf Svg_ST, w ; Svg_ST ‘permuté’ dans W movwf STATUS ; Restitution correcte de STATUS swapf Svg_W, f ; Svg_W recopié ‘permuté’ dans lui-même ; sans casser STATUS ! (pas de movf) swapf Svg_W, w ; Svg_W recopié ‘re-permuté’ dans W retfie ; retour d’interruption

Les bits RP0 et RP1 de STATUS indiquent la page courante de travail : ce numéro de page est donc ‘hérité’ du programme interrompu et n’est pas forcément la page souhaitée, d’où le positionnement de ces 2 bits après la séquence de sauvegarde. La page d’origine sera automatiquement remise en activité par la restauration de STATUS. Pour rendre la programmation plus lisible, il est évidemment possible de définir deux macros pour l’ensemble de ces instructions qui reviennent systématiquement dans la routine d’interruption. On retiendra aussi que les choix architecturaux dans la conception d’un processeur ont une incidence certaine sur la programmation de celui-ci. Le µC PIC16f628 prend en compte d’autres formes d’ « interruptions », maintenant indispensables sur les systèmes embarqués, comme la mise en sommeil et le redémarrage par chien de garde. Le mode Sleep est une mise en sommeil pour économiser l’énergie dans

le système embarqué. Le processeur est arrêté par suppression de son horloge, il est comme figé dans le temps et il n’y a pas de sauvegarde particulière à faire. C’est une forme particulière d’interruption logicielle par l’appel à l’instruction sleep. Le chien de garde (WatchDog) est un dispositif de veille automatique analogue à celui de « l'homme mort » qui permet de s'assurer en permanence que le conducteur d’une locomotive est présent à son poste et conscient. Le conducteur doit effectuer une tâche périodique (appui d’une manette ou pédale) faute de quoi l’arrêt d’urgence du train se met en route automatiquement. Lorsque le Watchdog est activé le programme en cours d’exécution sur le microcontrôleur doit venir régulièrement remettre à 0 le compteur de temps du chien de garde. S’il arrive à expiration, le Watchdog provoque la réinitialisation du programme. Cela permet de s’assurer que le programme ne reste pas bloqué sur une attente infinie ou boucle dans une zone non prévue. La conception de l’application doit, dès les premiers stades, prendre en compte ce type de système de sécurité.