Programmateur de PIC – Bulk Erase

Bonjour à toutes et à tous !

Comme promis, voici la suite du projet de programmateur de PIC. Nous avons vu la dernière fois une présentation sommaire du programmateur de PIC et de ses fonctionnalités. Aujourd’hui nous allons nous atteler à la première d’entre elles : l’effacement intégral de la mémoire.

Tout d’abord, je vais vous présenter le principe de fonctionnement de l’effacement et de quelques cas d’utilisation. Ensuite, nous allons voir ensemble la constitution du protocole de communication. Enfin, nous verrons par quelle trame ordonner au microcontrôleur l’effacement complet de sa mémoire.

Principe

L’effacement de la mémoire est généralement un pré-requis à l’écriture dans la mémoire. Cela afin de se débarrasser des résidus de programme qui pourrait subsister en se contentant de simplement écrire par-dessus le programme précédent.

Il a également une autre utilité. Le PIC18F2550, entre autres, dispose en effet d’un mécanisme de protection de l’accès à la mémoire. Pour pouvoir réécrire un programme dans une zone mémoire protégée, il faut procéder à l’effacement de la mémoire qui va également réinitialiser les droits d’accès de toutes les zones de mémoire.

Nous ne verrons ici que l’effacement intégral, plus simple à mettre en œuvre.

Chronogrammes et programme

Nous avons vu brièvement dans le précédent article le déroulement de la programmation du microcontrôleur. Je vous propose ici de voir les premières étapes plus en détail.

N.B. : Dans le doute, je préfère ne pas mettre ici les diagrammes présents dans la documentation de Microchip. Toutefois, comme « il est toujours bien plus facile de comprendre avec un dessin », je vous invite à consulter directement le document concerné. Afin de vous faciliter la recherche, j’indiquerai pour chaque diagramme le numéro de la figure et la page.

Entrée en mode Program/Verify

Lors de la programmation du microcontrôleur, la tension d’alimentation se situe entre 3,0V et 5,5V (si le microcontrôleur fonctionne avec son oscillateur interne) ou entre 2,0V et 5,5V (si un oscillateur externe est utilisé) et ce quel que soit le mode d’alimentation utilisé (Low-Voltage ou High-Voltage). De plus, toutes les broches doivent être à l’état bas, sauf VDD.

  • Low-Voltage (page 17, paragraphe 2.6, figure 2-16)

L’entrée dans le mode Program/Verify consiste à indiquer au microcontrôleur que l’on se place en mode Low-Voltage via la broche PGM avant d’alimenter la broche de programmation VPP avec la tension adéquat (entre 2,0V et 5,5V pour le mode Low-Voltage).

Dès lors, nous commençons par placer la broche PGM à l’état haut. Après un court délai minimum de 2 microsecondes, on peut placer la broche VPP à l’état haut puis attendre encore 2 microsecondes minimum avant de transmettre des données via les broches PGD (données) et PGC (horloge).

  • High-Voltage (page 16, paragraphe 2.5, figure 2-14)

Si on utilise le mode High Voltage, la tension de programmation se situe entre VDD+4,0V (donc entre 6/7V et 9,5V, selon l’oscillateur utilisé) et 12,5V et la broche PGM n’est pas du tout utilisée. On commence par alimenter le microcontrôleur et attendre un délai minimum de 100 nanosecondes. Avant de placer la broche de tension de programmation à l’état haut.

Important : le temps de montée de la broche VPP ne doit pas dépasser une microseconde !

Comme pour le mode Low-Voltage, ce n’est que 2 microsecondes après le moment où VPP atteint l’état haut que l’on peut commencer à transmettre via PGD et PGC.

Une routine pour effectuer cette entrée en « Program/Verify mode », en mode Low-Voltage, ressemblerait à ceci :

/*
 * Enter Program/Verify mode
 */
void enter_program_verify_mode()
{
    digitalWrite(PGM, HIGH);
    delayMicroseconds(2);
    digitalWrite(VPP, HIGH);
    delayMicroseconds(2);
}

Sortie du mode Program/Verify

  • Low-Voltage (page 17, paragraphe 2.6, figure 2-17)

Il faut avant tout que les broches PGD et PGC soient et restent à l’état bas, signe qu’elle ne transmettent plus. On peut alors placer VPP puis PGM à l’état bas. Aucun délai n’est à respecter.

  • High-Voltage (page 16, paragraphe 2.5, figure 2-15)

Comme pour le mode Low-Voltage, il faut avant tout que les broches PGD et PGC soient et restent à l’état bas. On peut alors, sans attendre, placer VPP à l’état bas, tout en respectant un temps de descente d’une microseconde maximum. Puis, dans un délai maximum de 100 nanosecondes, on doit placer VDD à l’état bas.

Une routine pour effectuer la sortie du « Program/Verify mode », en mode Low-Voltage, ressemblerait à ceci :

/*
 * Exit Program/Verify mode
 * Power is on (VCC and Programming voltage)
 */
void exit_program_verify_mode()
{
    digitalWrite(PGD, LOW);
    digitalWrite(PGC, LOW);
    digitalWrite(VPP, LOW);
    digitalWrite(PGM, LOW);
}

Envoi de trame (page 18-19, paragraphe 2.7, figure 2-18)

Comme je l’ai dit dans l’article précédent, les commandes sont formés de 20 bits : 4 bits pour l’instruction et 16 bits pour le payload. Ici, je vous détaille comment ces commandes sont transmises.

La transmission s’effectuant en Little-Endian, le plus faible des 4 bits est transmis en premier jusqu’à celui le plus fort. On en fait de même avec les 16 bits, en commençant par le plus faible des 16 et en terminant par le plus fort.

Pour chaque bit, l’horloge doit se placer à l’état haut, la broche de données doit se placer ou être déjà placé à l’état haut pour transmettre un 1 et à l’état bas pour transmettre un 0. Enfin, on place l’horloge à l’état bas pour amorcer l’émission du bit.

Une période d’horloge doit durer au minimum 100 nanosecondes, avec un minimum de 40 nanosecondes pour chaque état d’horloge. Ceci est valable lorsque le microcontrôleur est alimenté en 5V. Lorsque VDD = 2V au lieu de 5V, ce temps minimum doit être décuplé (400 nanosecondes et 1 microseconde au lieu de 40 et 100 nanosecondes).

Concernant la broche de données, il doit s’écouler au moins 15 nanosecondes entre la mise à l’état souhaité et le passage de l’horloge à l’état bas. De même, le temps de maintien de la broche de données à l’état souhaité doit durer au moins 15 nanosecondes à partir du moment où l’horloge est passée à l’état bas.

Enfin, entre la fin de la transmission du dernier des 4 bits de commande et le début de la transmission du premier des 16 bits de payload, il doit s’écouler au minimum 40 nanosecondes. De même à la fin de la transmission du dernier des 16 bits de payload : avant de transmettre quoi que ce soit, il est nécessaire d’attendre au moins 40 nanosecondes.

N.B.: Je sais qu’il peut sembler ridicule d’exiger de patienter durant un temps aussi infime qu’une microseconde ou que quelques nanosecondes. Cependant, à l’échelle du microcontrôleur, ce n’est pas anodin. Si je prends par exemple la fréquence de l’oscillateur interne du PIC18F2550, qui est de 8 MHz, cela nous donne une instruction tous les 500 nanosecondes (TOSC= 1/f = 1/8000000Hz = 0,000000125 secondes = 125 nanosecondes ; TCY = TOSC * 4 = 125 * 4 = 500 nanosecondes par cycle instruction). C’est juste dans la plupart des cas et insuffisant lorsque VDD est de 2V. Dans notre cas, nous utilisons un Arduino cadencé à 16 MHz et le cycle d’instruction se fait le plus souvent en un ou deux cycles d’horloges au lieu de quatre (une particularité des microcontrôleurs AVR sur lesquels sont basés la plupart des cartes Arduino), ce qui amène le temps de cycle à 62,5 ou 125 nanosecondes.
Dans notre cas, cela devrait suffire, la plupart des délais à respecter n’atteignant pas 62,5 nanosecondes.

Voici à quoi ressemblerait la routine permettant d’envoyer une commande au microcontrôleur.

/*
 * Send a command to the chip
 */
void send_command(char command, char lowbyte, char highbyte)
{
    char i;

    /* Command */
    for (i = 0; i < 4; i++) 
    { 
        digitalWrite(PGC, HIGH); 
        if ((command & 1) == 1) 
        { 
            digitalWrite(PGD, HIGH); 
        } 
        else 
        { 
            digitalWrite(PGD, LOW); 
        } 
        digitalWrite(PGC, LOW); 
        command = command >> 1;
    }

    /* Low Byte */
    for (i = 0; i < 8; i++) 
    { 
        digitalWrite(PGC, HIGH); 
        if ((lowbyte & 1) == 1) 
        { 
            digitalWrite(PGD, HIGH); 
        } 
        else 
        { 
            digitalWrite(PGD, LOW); 
        } 
        digitalWrite(PGC, LOW); 
        lowbyte = lowbyte >> 1;
    }

    /* High Byte */
    for (i = 0; i < 8; i++) 
    { 
        digitalWrite(PGC, HIGH); 
        if ((highbyte & 1) == 1) 
        { 
            digitalWrite(PGD, HIGH); 
        } 
        else 
        { 
            digitalWrite(PGD, LOW); 
        } 
        digitalWrite(PGC, LOW); 
        highbyte = highbyte >> 1;
    }
    digitalWrite(PGC, LOW);
    digitalWrite(PGD, LOW);
}

Les commandes d’effacement

À présent, nous disposons de routines permettant l’envoi de commandes qui respectent les standards imposés par la documentation du composant. Nous pouvons à présent transmettre l’ordre d’effacement.

Mais qu’envoyer ? La documentation nous indique la séquence suivante :

4-Bit Command (binary) Data Payload (hexadecimal) Core Instruction (assembly)
0000 0E 3C MOVLW 3Ch
0000 6E F8 MOVWF TBLPTRU
0000 0E 00 MOVLW 00h
0000 6E F7 MOVWF TBLPTRU
0000 0E 05 MOVLW 05h
0000 6E F6 MOVWF TBLPTRU
1100 3F 3F Write 3F3Fh to 3C0005h
0000 0E 3C MOVLW 3Ch
0000 6E F8 MOVWF TBLPTRU
0000 0E 00 MOVLW 00h
0000 6E F7 MOVWF TBLPTRU
0000 0E 04 MOVLW 04h
0000 6E F6 MOVWF TBLPTRU
1100 8F 8F Write 8F8Fh to 3C0004h
0000 00 00 Hold PGD low until erase completes
0000 00 00

Que nous dit cette séquence ? Tout simplement que l’on cherche à se positionner à l’adresse 0x3C0005 via le pointeur TABLPTR (dont j’ai parlé au précédent article) pour y inscrire la valeur 0x3F puis refaire de même avec la valeur 0x8F à l’adresse 0x3C0004.
On termine l’ordre par un NOP (une instruction assembleur dont le principe est de ne rien faire) pour que démarre l’effacement. Ce dernier se déclenche au front descendant d’horloge du 4ème bit de commande du NOP. Lors de l’opération d’effacement, la liaison série sera indisponible jusqu’à la fin (au moins 5 millisecondes). Pendant ce temps, l’horloge peut continuer à osciller, mais la broche de données doit impérativement rester à l’état bas.
Un délai supplémentaire d’une dizaine de microsecondes au minimum doit être opéré à la fin du temps d’attente avant de reprendre toute communication avec le microcontrôleur.

La documentation n’en dit hélas pas davantage sur ces instructions, hormis qu’aux adresses 3C0005h et 3C0004h se situent deux registres dédiés à l’effacement du microcontrôleur ainsi que les valeurs à utiliser pour ces registres selon les zones de mémoire que l’on souhaite effacer.

Mise en pratique

Après quelques tâtonnements, je suis parvenu à écrire un programme Arduino qui effectue l’effacement du microcontrôleur PIC18F2550 auquel il est relié. Pour m’assurer que l’effacement était bien effectif, le programme se termine par une petite boucle qui fait osciller VPP. Le programme précédent se contentant uniquement de garder une LED allumée, si la LED restait éteinte à la fin du programme, l’effacement était considéré comme réussi.

ArduinoICSP – Bulk Erase

Bien évidemment, j’ai revérifié après avec un autre programmateur si la mémoire était bien vierge, et ce fut le cas.
Notez également que j’ai choisi la broche 13 pour commander VPP. Ce n’est pas anodin : cette broche commandant également une LED intégrée à la carte Arduino, cette dernière me fournissait un témoin visuel que la broche était bel et bien en train de changer d’état.

Les broches VDD et VSS du PIC18F2550 sont connectées respectivement aux broches VCC 5V et GND de la carte Arduino.

La commande pour l’effacement se trouve ici n’être qu’un simple tableau qui est transmis par le programme principal en temps qu’arguments à la fonction d’envoi de trame. C’est largement suffisant et les autres opérations seront exécutées de la même manière, avec quelques subtilités cependant (je pense par exemple à l’écriture de programme).

Conclusion

C’est terminé avec l’effacement du microcontrôleur. Il s’agissait d’un article très consistant, ce qui explique pourquoi je ne le publie que maintenant. J’espère parvenir à poursuivre le projet et l’écriture des articles rapportant mes progrès. J’ai moins de temps depuis que j’ai retrouvé un emploi le mois dernier (je ne m’en plains pas, c’est un boulot qui me plaît et les progrès que j’y fais me servent pour ce projet, et réciproquement).

Je m’efforce également de ne pas digresser sur d’autres sujets, ce qui est assez difficile car j’ai déjà plein d’idées de projets que je meurs d’envie de partager ici. Il faudra patienter le temps que je finisse le projet de programmateur de PIC. Les autres qui viendront par la suite seront, je l’espère, plus concis que le programmateur bien que tout aussi intéressants (voire davantage).

Sur ce, je vous laisse et je vous dis à bientôt.

Nicolas SAN AGUSTIN

Programmateur de PIC : Présentation technique

Bonjour à toutes et à tous !

Après tant de temps, je me suis enfin décidé à partager ma progression concernant ce projet de développement. Cela à deux fins : partager avec vous des informations sur la programmation de microcontrôleurs PICs et la manière d’implémenter la méthode ICSP sur une carte de type Arduino et, par ce biais, vous en apprendre également plus sur le fonctionnement d’un microcontrôleur.

Historique des méthodes de programmation

À l’origine, la méthode utilisée pour programmer un microcontrôleur était d’utiliser un programmateur comportant un emplacement prévu pour y insérer le microcontrôleur. On écrit le programme dans la mémoire du microcontrôleur avant de retirer ce dernier et de l’intégrer au système qu’il doit piloter. Inutile de préciser que c’est une méthode fastidieuse qui impose, pour chaque modification du logiciel embarqué, de devoir retirer puis insérer le microcontrôleur à plusieurs reprises pour pouvoir le programmer puis le tester. Cela au risque d’abîmer plus rapidement et plus facilement les broches du microcontrôleur. Mais, plus encore, un problème se pose dans le cas d’une modification majeure du logiciel d’un produit fini et vendu en masse. On ne peut décemment pas exiger de rappeler tous les exemplaires sous le prétexte d’une mise à jour du logiciel, aussi majeure soit-elle, qu’il faudra effectuer pour chaque microcontrôleur.

C’est là qu’apparaît la méthode ISP, pour In-System ProgrammingProgrammation In-Situ en français. Elle permet la programmation d’un microcontrôleur déjà intégré à un système. Cette fois, nous pouvons consulter ou modifier le programme d’un microcontrôleur via un connecteur relié à des broches dédiées de ce microcontrôleur, le tout directement intégré dans le système à piloter. Les programmateurs les plus aboutis permettent même le débogage du logiciel embarqué en temps réel. Elle permet aussi la mise en place de procédures plus simples pour la mise à jour du logiciel embarqué, comme la reprogrammation directe du microcontrôleur ou la mise en place d’un microcontrôleur secondaire sur la carte faisant office de programmateur in-situ.

Microchip fut le premier à implémenter cette méthode de programmation in-situ, nommé alors ICSP pour In Circuit Serial Programming, pour ses microcontrôleurs PIC et dsPIC. Par la suite, de nombreux fabricants ont implémenté leur propre version de cette méthode de programmation.

Description

Selon le fabricant, l’implémentation de la méthode peut différer. Aussi, pour cet article, nous nous concentrons uniquement sur ICSP tel qu’implémenté par Microchip.

De plus, le microcontrôleur utilisé dans cette étude de cas est le PIC18F2550. Il est donc possible que certaines fonctionnalités diffèrent voire sont inexistantes pour d’autres modèles de microcontrôleurs – même provenant de chez Microchip.

Ces points étant explicitement établis, passons maintenant à la description technique de la méthode ICSP.

Brochage

Le connecteur ICSP comprend 6 broches qui se décrivent comme suit :

  1. MCLR/VPP : Il s’agit de la tension de programmation. L’état de la broche permet d’entrer ou de sortir du mode de programmation. Dans le cas qui nous intéresse, la tension varie en fonction du mode de programmation : « High-Voltage » = 12 V et « Low-Voltage » = 5 V.
  2. VDD : La tension d’alimentation du microcontrôleur, ici 5 V.
  3. VSS : Il s’agit tout simplement de la masse. Le PIC18F2550 dispose de deux broches à relier à la masse.
  4. PGM : utilisée uniquement dans le cas d’une programmation « Low-Voltage », autrement elle n’est qu’une entrée/sortie comme une autre (RB5). Lors de l’entrée en mode de programmation, elle est la première broche placée à l’état haut, avant la tension de programmation. De même, elle est la dernière à être placée à l’état bas lors de la sortie du mode de programmation.
  5. PGC : C’est l’horloge utilisée lors de la transmission de données. Comme dans la plupart des protocoles de transmission, c’est le maître – ici le programmateur – qui donne la cadence de l’horloge.
  6. PGD : C’est par cette broche que les données transitent, en little endian – i.e. le bit de poids faible est transmis en premier et le bit de poids fort en dernier.

Organisation des zones mémoire

La mémoire du PIC18F2550 est organisée en différentes zones. Les adresses en mémoire sont exprimées en hexadécimal et chaque adresse correspond à un octet de mémoire.

  • La mémoire dédiée au code exécutable, de l’adresse 0x00000 à l’adresse 0x007FFF, soit 32 Kio divisés en 5 blocs :
    • Le bloc de démarrage (ou Boot Block) sur les 2048 premiers octets, contenant les instructions du programme exécutées en premier au démarrage du microcontrôleur ;
    • Le bloc 0, de 6 Kio, soit 6144 octets ;
    • et trois blocs, numérotés de 1 à 3, de 8 Kio chacun.
  • Les ID locations – des registres dédiés à l’écriture de divers numéros d’identification – de 0x200000 à 0x200007, soit 8 octets au total ;
  • Les registres de configuration, de 0x300000 à 30000D, soit 16 octets organisés en 8 paires de registres (CONFIGxH pour le regitre de poids fort et CONFIGxL pour le registre de poids faible) ;
  • Et enfin, l’identifiant du périphérique (Device ID) sur deux octets, aux adresses 0x3FFFFE et 0x3FFFFF. Il permet au programmateur d’identifier le modèle et le numéro de version du microcontrôleur présent.

Processus de programmation

Le processus de programmation se déroule comme suit :

  • Entrée en mode de programmation/vérification (Program/Verify mode)
  • Effacement partiel ou complet de la mémoire du microcontrôleur
  • Écriture du programme dans la zone mémoire dédiée au code
  • Écriture des ID Locations
  • Écriture de données dans la mémoire EEPROM
  • Vérification du programme
  • Vérification des ID Locations
  • Vérification des données EEPROM
  • Écriture des bits de configuration
  • Vérification des bits de configuration
  • Sortie du mode de programmation/vérification

Pour chaque opération, hormis pour l’entrée et la sortie du mode de programmation/vérification, le programmateur doit envoyer des trames au microcontrôleur. Ces trames se composent toutes de 4 bits de commande et de 16 bits de payload – le contenu du payload dépend essentiellement de la commande.

Tout le processus consiste à manipuler un pointeur nommé TABLPTR au travers de trois registres dédiés : TABLPTRU, TABLPTRH, TABLPTRL. Ces registres vont chacun contenir une partie de l’adresse mémoire vers laquelle TABLPTR doit pointer et à laquelle on souhaite opérer.

Parmi les commandes utilisées par le programmateur, on peut trouver essentiellement :

  • Core Instruction (0b0000) : Elle sert essentiellement à exécuter des instructions du processeur du microcontrôleur. Le payload correspond ici à une instruction en assembleur sur 16 bits (une instruction et son argument). La plupart du temps, cette commande servira à initialiser la valeur de TABLPTR avant d’opérer sur l’octet pointé.
  • Table Read (0b1000) : Une des deux principales opérations que l’on peut effectuer sur l’adresse mémoire pointée par TABLPTR. Elle consiste à lire les données qui se trouve à l’emplacement mémoire pointé. Le payload est constitué uniquement de 0, les données lues étant transmises à la suite de cette commande.
  • Table Write (0b1100) : La seconde principale opération que l’on peut effectuer à l’adresse mémoire pointée par TABLPTR. Par opposition à la précédente, il s’agit ici d’écrire des données à l’emplacement mémoire pointé. Le payload est ici constitué des données à inscrire. L’adresse mémoire pointant vers un octet, soit 8 bits, le payload de 16 bits contient en fait deux fois l’octet à écrire, probablement pour vérifier de manière simpliste l’intégrité des données transmises – i.e. vérifier que toute la donnée à inscrire a bien été transmise et n’a donc pas été perdue ou corrompue.

Les autres commandes sont des variantes des deux dernières présentées avec, par exemple, la possibilité d’incrémenter le pointeur directement pour qu’il pointe vers l’adresse suivante ou de démarrer la programmation suite à l’écriture. Nous les verrons plus en détail au fil des articles traitant des différentes étapes de la programmation.

Et ensuite ?

Toute cette présentation est censée poser les bases du programmateur et vous donner les informations élémentaires pour comprendre la suite. Le prochain article, à paraître fin février 2017, traitera de la première procédure du processus, à savoir l’effacement de la mémoire du microcontrôleur.

Sur ce je vous laisse et vous dis à bientôt.

Nicolas SAN AGUSTIN

Sources :

Les outils pour la programmation de microcontrôleurs

Bonjour à toutes et à tous.

Certain(e)s d’entre vous ont sûrement connu ce site par l’intermédiaire de mon tutoriel sur la configuration de Code::Blocks pour programmer des PIC. Mais comme il s’agit d’un article très spécifique, avec un matériel et des logiciels adaptés, le but du présent article sera donc d’introduire des bases plus générales de la programmation de systèmes embarqués, à commencer par la présentation des outils nécessaires à la programmation de microcontrôleurs.

Le microcontrôleur

À la base, nous avons un microcontrôleur, qui est un composant électronique jouant le rôle d’un ordinateur à une échelle très réduite. Pour chaque microcontrôleur, son fabricant propose généralement un kit de développement permettant de relier ce microcontrôleur à l’ordinateur servant à le programmer.

En effet, contrairement au développement informatique en général, le développement ne se fait pas directement sur le microcontrôleur, ses ressources étant trop limitées pour y implémenter à la fois le programme et tous les outils logiciels pour le développer, comme le compilateur ou l’éditeur de code. Nous devons donc déporter ce développement sur une plate-forme possédant les ressources nécessaires pour accomplir cette tâche. On parle alors de compilation croisée, puisqu’on écrit et compile du code pour une autre plate-forme que celle sur laquelle on développe.

Pour ce qui est du choix du microcontrôleur, il se fait en fonction des besoins du projet à réaliser. Le budget peut également être un facteur déterminant.

Les fabricants ne manquent pas et il existe des microcontrôleurs pour toutes sortes d’usage. Microchip propose des microcontrôleurs assez généralistes, les fameux microcontrôleurs PIC. Ils sont peu chers mais assez chaotiques dans leur fonctionnement. On les utilise généralement pour l’apprentissage de la programmation de microcontrôleurs ou des questions de budget.

Ensuite, on trouve Atmel et ses microcontrôleurs 8 bits AVR. Ils sont généralement de meilleure qualité que les PIC pour un coût à peu près équivalent. Ils sont d’ailleurs à la base des fameuses cartes Arduino, utilisées essentiellement pour l’apprentissage de l’embarqué et pour le développement de nombreux projets amateurs. À noter qu’il existe une version PIC d’Arduino, moins connue, nommée Pinguino.

Il existe une autre architecture de microcontrôleurs, très courante mais non spécifique à un seul fabricant, qui est le 8051. Initialement créé par Intel en 1980, cette architecture a été beaucoup reprise par de nombreux constructeurs et est encore très utilisée aujourd’hui.

On peut également trouver d’autres architectures de microcontrôleurs comme les MSP430 de Texas instruments, les PSoC de Cypress, les 6800 et 68000 de Freescale (anciennement Motorola et appartenant désormais à NXP), les STM8 de STMicroelectronics ou les Z80 de Zilog (que l’on trouvait notamment, sous forme dérivée, dans la fameuse console portable GameBoy).

Enfin, il existe l’architecture ARM. À l’instar de 8051, cette architecture est intégrée par la plupart des fabricants de circuits intégrés et est présente dans bons nombre de produits technologiques du grand public (dans les smartphones et les tablettes, entre beaucoup d’autres). À ce jour, c’est certainement l’architecture la plus utilisée dans les systèmes embarqués, mais sa prise en main n’est pas adaptée à des débutants dans le domaine de l’embarqué.

Read The F***ing Manual

Le développement embarqué c’est également pas mal de temps à se documenter, au moins pour comprendre le fonctionnement du matériel que l’on utilise. C’est pour cela que je vous encourage à lire la documentation du matériel et des outils que vous utiliserez. Pour cela, l’anglais est indispensable puisque la grande majorité des documents sont en anglais.

Cela dit, n’hésitez pas non plus à demander de l’aide sur des forums comme Developpez.net. ;-)

Le langage de programmation

Hormis avec quelques rares exceptions comme les compilateurs mikroBasic ou mikroPascal de MikroElektronika, si vous voulez vous lancer à corps perdu dans le domaine de l’embarqué tout en espérant y trouver suffisamment d’informations pour progresser facilement, il vous faudra passer par l’apprentissage du C, si vous ne maîtrisez pas déjà ce langage.

Pour acquérir les bases du langage C rapidement, je ne peux que vous conseiller de trouver des cours sur internet comme Le C en 20 heures. Vous pouvez également chercher du côté d’OpenClassrooms ou de Developpez.com.

Même si ce n’est pas obligatoire, il est également préférable d’acquérir au moins quelques bases en assembleur.

L’éditeur de code

Les outils pour l’écriture de code restent généralement les mêmes que pour du développement logiciel général, allant du simple bloc-notes à l’environnement de développement intégré. Mais, lors de l’écriture, on tiendra compte des limites de la cible de programmation. En bref, la programmation embarquée exige beaucoup plus de rigueur concernant la gestion des ressources, de la taille mémoire, de la pile, du tas, des exceptions, etc. Mais cela fera l’objet d’autres tutoriels.

Pour en revenir aux éditeurs, on pourra utiliser des outils conventionnels disposant d’extensions spécialisées pour le développement de la cible choisie, voire proposant des outils supplémentaires pour mieux répondre aux contraintes des microcontrôleurs. Je pense notamment à Code::Blocks ou Eclipse.

Mais, de manière générale, chaque fabricant de microcontrôleurs proposera un outil spécifique à son matériel, voire un outil fait maison. C’est le cas par exemple de Microchip avec MPLAB, Atmel avec Atmel Studio, ARM avec MDK-ARM, etc. Pour chaque matériel, on trouvera au moins un outil de développement qui sera soit directement développé par le constructeur, soit développé par des sociétés externes. Ce dernier cas est valable, par exemple, pour la société IAR Systems qui propose des outils de développement ciblant plusieurs architectures d’autres constructeurs – techniquement c’est le même outil mais avec une version spécifique pour chaque architecture.

Il s’agit généralement d’outils propriétaires et/ou payants. Les amateurs de logiciels gratuits et/ou libres seront facilement rebutés et préféreront s’orienter vers d’autres alternatives, dont le monde du logiciel libre ne manque pas. Par exemple, pour les PIC, il existe l’outil Piklab dédié à cette famille de microcontrôleurs ou encore MCU 8051 IDE dédié aux microcontrôleurs à base de 8051.

Le compilateur

Une fois le programme écrit, il nous faut le compiler. Le fabricant du microcontrôleur utilisé proposera un compilateur spécifique à son matériel, allant généralement de pair avec l’outil de développement. C’est le cas, par exemple, pour le compilateur XC qui accompagne l’outil MPLAB X, le compilateur Keil pour MDK-ARM ou le compilateur IAR pour l’outil du même nom.

Côté logiciel libre, on trouvera un bon nombre de compilateurs, généralement dérivés du compilateur GCC. On peut par exemple citer AVR-GCC pour les microcontrôleurs AVR, GNU ARM pour les architectures ARM ou MSP430 GCC pour les microcontrôleurs MSP430 de Texas Instruments.

Il existe aussi le compilateur SDCC, dont j’ai déjà parlé dans un précédent tutoriel, qui a la particularité de cibler plusieurs plate-formes. Parmi ces cibles supportées, on peut compter plusieurs microcontrôleurs 8051, le Z80 de Zilog, des HC08 de Freescale ou encore les fameux PIC de Microchip (extension non libre). Je vous invite à vous référer au site du compilateur pour connaître les architectures supportées.

Le programmateur et le débogueur

Une fois le programme compilé, il faut pouvoir l’inscrire dans la mémoire du microcontrôleur ciblé. Pour cela, il faut un outil matériel communément appelé un programmateur.

Là encore, on trouvera différents programmateurs pour chaque cible, les premiers étant fournis par les fabricants du microcontrôleur, les autres étant souvent le fait de passionnés d’électronique proposant une alternative moins chère aux programmateurs commerciaux, qui peuvent souvent se révéler assez chers.

Pour les PIC, la référence est le PICKit, actuellement dans sa version 3. Pour les microcontrôleurs AVR, ce sera plutôt le AVRISP mkII.

Ces programmateurs sont proposés par le constructeur, mais il existe des alternatives intéressantes, comme le usbpicprog pour les cibles PIC. Il est libre, compact (54 x 28 x 14 mm) et il est assez simple à utiliser. Normalement vous pouvez le construire vous-même mais il est possible d’en commander sur le site pour pas cher (20€  pièce, plus les frais de port qui sont raisonnables).

Côté AVR on se tournera plutôt du côté de l’USBtinyISP, créé par Adafruit (auquel je vous recommande chaudement de vous intéresser, leur travaux sont tout à fait remarquables). Initialement vendu en kit, il est possible de le commander déjà monté, et son coût est à peu près équivalent au usbpicprog.

Attention ! Il est important de faire la distinction entre un programmateur et un débogueur. On retiendra que le programmateur permet de manipuler les données de la mémoire du microcontrôleur, tandis que le débogueur permet d’exécuter le programme et de superviser son fonctionnement en temps réel depuis un ordinateur. Si les deux peuvent être intégrés dans le même outil, ce n’est pas toujours le cas, donc faites attention à vérifier si l’outil que vous choisissez correspond à vos besoins.

Le simulateur

Il peut arriver que l’on ne dispose pas du matériel requis pour travailler directement sur la cible de programmation, ou que l’on préfère simuler le fonctionnement du programme pour éviter d’endommager le microcontrôleur. Dans ces cas-là, on peut utiliser un programme qui va simuler l’exécution du programme que l’on souhaite tester.

Microchip et Atmel ont intégré un simulateur dans leur outil de développement. Les alternatives libres ne manquent pas non plus et on pourra trouver GPSim pour PIC et Simulavr pour AVR. Le compilateur SDCC comprend également un simulateur, nommé µCsim, qui gère essentiellement les cibles 8051.

Retenez cependant qu’un programme qui fonctionne sans problème avec un simulateur n’implique pas forcément que le programme fonctionnera aussi bien sur un microcontrôleur.

Conclusion

J’espère avoir apporté assez d’éléments pour vous permettre d’appréhender les bases du développement sur microcontrôleurs. Bien entendu tout cela est valable surtout si vous souhaitez partir du plus bas niveau, en sélectionnant vous-même le microcontrôleur et les outils associés.

Mais, si tout cela vous rebute, vous pouvez aussi bien vous orienter vers une solution comme Arduino, parfaitement adaptée aux débutants en embarqué. D’autant qu’une communauté très forte s’est bâtie autour de ce système et vous n’aurez donc aucun mal à trouver de l’aide pour progresser.

Cependant, le côté simpliste de la plate-forme risque de vous imposer de passer à quelque chose de plus ardu à un moment donné. Auquel cas, ou si vous souhaitez essayer d’autres architectures par pure curiosité, je vous invite à choisir parmi les cibles évoqués dans cet article. Si vous voulez rester sur du matériel AVR, sachez qu’il est également possible de programmer directement le microcontrôleur de la carte Arduino via les broches ISP prévues à cet effet. Il vous faudra cependant utiliser un programmateur comme un de ceux évoqués plus haut.

N’hésitez pas à poser des questions en commentaires si certains points ne sont pas clairs ou si vous souhaitez obtenir davantage d’informations.

Sur ce, je vous laisse et vous dis à bientôt.

Nicolas SAN AGUSTIN

Copyright Nicolas SAN AGUSTIN 2018
Tech Nerd theme designed by Siteturner