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 1 nous appuierons sur le cas du PIC 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 2 comportant comme une suite ordonnée de registres de 8 bits ( register file ). 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
02h 03h 04h 05h 06h
PCL STATUS FSR TRISA TRISB
82h 83h 84h 85h 86h
PCL STATUS FSR
PCLATH INTCON
0Ah 0Bh
PCLATH INTCON
8Ah 8Bh
PCLATH INTCON
Special Function Register General Purpose Register
Special Function Register 20h
96 octets libres
General Purpose Register
PORTB
102h 103h 104h 105h 106h
PCL STATUS FSR TRISB
182h 183h 184h 185h 186h
10Ah 10Bh
PCLATH INTCON
18Ah 18Bh
Special Function Register A0h
80 octets libres
General Purpose Register 48 octets libres
Special Function Register 120h
14Fh
EFh 7Fh
Bank 0
1FFh
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 ième FSR. Le 8 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 ième er 8 niveaux (c’est une file circulaire : le 9 élément écrase le 1 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 file), d est un spécificateur de registre en RAM ( file 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 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
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
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
f, d f, d f, d f, d f, d f, d f, d 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).
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
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
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)
DECFSZ f,d
test
DECFSZ
compteur, f
(+1) (+2) Suite
;inst i
GOTO suite
;inst i+1
CALL proc1
;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 Bit Test and Skip if x). La structure de saut l’utilisation de l’une des deux instructions BTFSx ( Bit 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
iter
Table
; @Table mise dans W (reg en RAM)
movwf
FSR
; @Table mise dans le registre FSR
movlw
huit
; initialise un compteur cpt à 8
movwf
cpt
clrf
;
INDF incf
; ‘clear’ indirect, adresse dans FSR FSR
decfsz
cpt,f
goto
iter
; FSR pointe sur l’octet suivant
; fini les 8 octets ? aller à suite ; l’initialisati on continue.
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 05 h 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 85 h 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
;
movlw
b’11110000’
movwf
TRISB
sélection page 1 : accès à 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
b’00000011’
; ‘allumez’ 2 bits
movwf
PORTB
; 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’ ‘ 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_0, SELECT_Page_1 SELECT_Page_1 par : SELECT_Page_0 MACRO bcf
STATUS, RP1
;
bcf
STATUS, RP0
;
bcf
STATUS, RP1
;
bsf
STATUS, RP0
;
sélection page 0
ENDM SELECT_Page_1 MACRO sélection page 1
ENDM
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 ff h à 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 i mplique 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 pri se 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 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
movwf
STATUS
swapf
Svg_W, f
; Svg_ST ‘permuté’ dans W ; Restitution correcte de STATUS ; Svg_W recopié ‘permuté’ dans lui-même ; sans casser STATUS ! (pas de
movf) swapf retfie
Svg_W, w
; Svg_W recopié ‘re-permuté’ dans W ; 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 plus lisible, il est 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é.