Skyduino:~#
Articles
arduino, tutoriel

[Arduino] Sauvegarder le programme d’une carte Arduino (ou compatible)

Bonjour tout le monde !

La question suivante m’a été posée sur Twitter. Comme elle me semblait intéressante, j’ai décidé de faire un rapide article dessus 😉

La question : « Comment faire pour sauvegarder le programme d’une carte Arduino »

Petite mise au point avant de commencer

L’idée ici est de récupérer le programme binaire (« le firmware » en bon english) dans la carte Arduino, mais en aucun cas de récupérer le code source du programme.
Programme binaire et code source sont deux choses radicalement différentes, bien qu’intimement liées.

On peut compiler un code source en programme binaire, mais l’inverse (binaire vers code source) n’est pas aussi simple, pour ne pas dire impossible (sauf pour quelques spécialistes).
Si vous pensiez pouvoir obtenir d’un clic de souris du code source C/C++ à partir d’un binaire, désolé de vous ramener sur terre, mais ce n’est pas comme cela que ça marche dans la vraie vie 😉

Maintenant que les choses ont été mises au clair, on peut continuer.

Le bootloader Arduino : optiboot

Ce qui rend possible la sauvegarde du programme binaire présent dans une carte Arduino, sans faire usage du moindre outil spécialisé, c’est le « bootloader ».
Dans le cas d’une carte Arduino, celui se nomme « Optiboot ». C’est un joli bébé de 512 octets écrit en code C.

Un bootloader n’est rien d’autre qu’un petit bout de code qui s’exécute avant le code utilisateur (votre code).
Ce petit bout de code n’a qu’une seule et unique fonction : transférer un programme binaire d’un point A (le port série USB dans le cas d’une carte Arduino) à un point B (la mémoire interne du microcontrôleur).

Pour ce faire, un bootloader implémente en général deux fonctions : lire une page mémoire et écrire une page mémoire.
La fonction d’écriture permet d’écrire le programme en mémoire (logique) et la fonction de lecture permet de vérifier que tout s’est bien passé en relisant les données.

Dans la vraie vie, sous-entendu dans un vrai produit vendu au grand public, le bootloader (s’il y en a un) est verrouillé pour éviter les bidouilles.
Les utilisateurs de smartphones Android connaissent bien le principe des bootloaders bloqués, sur microcontrôleur c’est pareil.

Dans un vrai produit, lors de la mise en production, on fait en général trois choses :
– on verrouille la mémoire du microcontrôleur pour éviter qu’une personne avec le bon matériel ne puisse physiquement lire ou écrire la mémoire,
– on désactive tout ce qui touche au débug (que ce soit dans le code ou dans le hardware) pour éviter de donner une porte d’accès aux vilains bidouilleurs,
– et pour finir, on verrouille le bootloader (via en général un système de chiffrement, avec signature cryptographique) pour permettre à l’utilisateur final de mettre à jour son produit facilement sans outils, mais sans pour autant le laisser faire n’importe quoi.

La philosophie open source fait que les cartes Arduino (et autres cartes compatibles Arduino) sont livrées non verrouillés et avec un bootloader dont on connait absolument tout, du protocole de communication jusqu’au code source.

On peut donc faire quelque chose qui serait impossible sur un produit lambda du marché : récupérer le programme binaire dans la mémoire du microcontrôleur.

AVRDUDE

Avrdude est un logiciel bien pratique qui permet de parler avec plein de microcontrôleurs AVR différents, au moyen de plein de sondes de débug, programmateurs ou bootloaders différents.
Et parmi les bootloader supportés, on retrouve un nom qu’on connait bien : « arduino ».

Je préviens de suite, c’est un utilitaire en ligne de commande, donc si vous avez la phobie des terminaux et des consoles systèmes, ça risque de vous déplaire.
Pour les autres, montez à bords, on décolle.

L’IDE Arduino utilise Avrdude pour envoyer les programmes après compilation, l’exécutable d’Avrdude doit donc se trouver quelque part ?
Exact ! Dans « Arduino-1.0.x\hardware\tools\avr\bin » pour être précis.

Si vous êtes sous Seven ou Windows 8, rendez-vous dans le dossier en question puis faites click droit en appuyant sur la touche majuscule gauche.
Vous devriez voir apparaître une option « Ouvrir une fenêtre de commande ici » dans la liste déroulante, cliquez dessus.

Saisissez maintenant la commande : « avrdude -v » (sans les quotes) pour voir si Avrdude répond.
Vous devriez obtenir une réponse de cette forme :
E:\PortableApps\Arduino-1.0.6\hardware\tools\avr\bin>avrdude -v

avrdude: Version 5.11, compiled on Sep 2 2011 at 19:38:36
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2009 Joerg Wunsch

Si c’est le cas, cela signifie que Avrdude est prêt pour la bataille.

Let’s go dump

Il ne reste maintenant plus qu’à connecter votre carte Arduino et noter le port série qui lui correspond.

La commande de base pour lire le contenu de la mémoire est la suivante :
avrdude -p LENOMDUMICRONTROLEUR -P LENOMDUPORTSERIE -c LENOMDUBOOTLOADER -U flash:r:LENOMDEMONFICHIER.hex:i

Avant de lancer la commande, détaillons un peu la structure de celle-ci :
avrdude : le nom de l’utilitaire qui nous intéresse
-p : (p minuscule) le prochain argument sera le nom du microcontrôleur de la carte (« m328p » pour une carte Arduino classique, « m2560 » pour une carte Mega2560)
LENOMDUMICRONTROLEUR : le nom du microcontrôleur (« m328p », « m2560 », ou autre en fonction de la carte)
-P : (P majuscule) le prochain argument sera le nom du port série
LENOMDUPORTSERIE : dans mon cas COM3, mais chez vous se sera surement un autre port
-c : le prochain argument sera le nom du protocole de communication à utiliser (« arduino » pour les cartes Arduino classiques, « stk500v2 » pour les cartes Mega, « stk500 » pour les vieilles cartes Arduino)
LENOMDUBOOTLOADER : le nom du protocole de communication (« arduino », « stk500v2 » ou « stk500 » en fonction de la carte)
-U : le prochain argument sera une commande Avrdude
flash:r:LENOMDEMONFICHIER.hex:i : ça ce complique, voici le détail :
flash : on travaille sur le mémoire flash interne (mémoire programme)
:r: : on souhaite lire le contenu de la mémoire
LENOMDEMONFICHIER.hex : le chemin vers le fichier de sortie (avec des quotes autours si nécessaire)
:i : on souhaite obtenir un fichier de sortie au format Intel Hex (le format classique)

Exemple avec une carte arduino UNO Rev3 (microcontrôleur « m328p » et bootloader « arduino » donc), sur le port « COM3 » et un fichier « toto.hex » (que je vais enregistrer sur mon bureau).
avrdude -p m328p -P COM3 -c arduino -U flash:r:C:\Users\Fabien\Desktop\toto.hex:i

Le résultat :
E:\PortableApps\Arduino-1.0.6\hardware\tools\avr\bin>avrdude -p m328p -P COM3 -c arduino -U flash:r:C:\Users\Fabien\Desktop\toto.hex:i

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: reading flash memory:

Reading | ################################################## | 100% 4.25s

avrdude: writing output file "C:\Users\Fabien\Desktop\toto.hex"

avrdude: safemode: Fuses OK (H:00, E:00, L:00)

avrdude done. Thank you.

J’obtiens alors un fichier « toto.hex » avec le contenu de la mémoire.
Si on l’ouvre avec un éditeur de texte, on voit bien qu’il contient des données :
(...)
:20026000551FEA95D1F7203080E0380781E0480780E0580720F481E08093190112C02030A1
:2002800080E0380788E0480780E0580778F482E08093190173E056954795379527957A959D
:2002A000D1F730931801209317013FC0203080E0380780E4480780E0580758F483E08093AD
:2002C000190166E056954795379527956A95D1F7E8CF203080E0380780E0480781E0580793
:2002E00040F484E080931901BB27A52F942F832F18C0203080E0380780E0480784E05807D5
:2003000058F485E0809319018AE056954795379527958A95D1F7C5CF85E0809319018FEFBB
:200320009FEF90931801809317018091170190911801909387008093860080911901806116
:20034000809381001F910F91FF90EF9008950F931F930BEA11E0C80140E052EC61E070E01C
(...)

(je vous fais grâce des +1000 lignes restantes)

Au contraire, si le fichier ne contenait que des FF (mémoire vide) ont aurait eu ce genre de chose :
(...)
:207A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86
:207A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66
:207A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46
:207A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26
:207A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06
:207AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6
:207AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6
:207AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6
(...)

(si vous obtenez que des FF ou 00, c’est que le bootloader est verrouillé, chose qui ne devrait pas arriver avec Optiboot, mais on ne sait jamais)

IMPORTANT TOUJOURS faire DEUX lectures de la mémoire, dans DEUX fichiers séparés, puis comparer si ceux-ci sont identiques (checksum, diff, comme vous voulez) et non vides.
Si les deux fichiers sont identiques : c’est bon vous avez votre sauvegarde.
S’ils sont différents : attention danger, quelque chose cloche. Vous n’avez surement pas le vrai contenu de la mémoire dans le fichier (erreur de communication, mémoire défectueuse, bootloader modifié, il peut y avoir plein de raison à cela).

OK. J’ai ma sauvegarde, je fais comment pour la restaurer ?

C’est simple, la commande est la même, seul le :r: de la commande -U change pour devenir :w: (write = écriture).
Avrdude lancera alors l’effacement de la mémoire, l’écriture des données, puis la relecture complète de la mémoire pour vérification.

Remarque : cela supprimera TOUTES les informations contenues dans la mémoire flash pour restaurer celles du fichier de sauvegarde.
Cela ne modifiera pas cependant les informations contenues dans la mémoire EEPROM (mémoire de données utilisateurs).
Avrdude supporte le mode « eeprom » au lieu de « flash » pour la commande -U, mais par défaut Optiboot (sauf sur les cartes Mega) ne supporte pas ce mode.

Discussion

24 réflexions sur “[Arduino] Sauvegarder le programme d’une carte Arduino (ou compatible)

  1. Salut Fabien,
    Toujours aussi efficaces 😉

    Publié par Icare Petibles | 14 février 2015, 13 h 36 min
  2. Re,
    Pour la partie conversion du fichier .hex, il reste la solution de passer par un « décompilateur »
    A partir d’un source en assembleur, il sera toujours possible de retravailler ou adapter le code.
    Même si la tâche n’est pas évidente.
    @+

    Publié par Icare Petibles | 14 février 2015, 14 h 02 min
    • Même avec le code assembleur, comprendre son fonctionnement peut prendre des mois, voir des années selon la complexité du code.

      Publié par Skywodd | 14 février 2015, 14 h 07 min
      • heu, ça dépend fortement hein, on est d’accord 🙂

        Publié par f4grx | 16 février 2015, 11 h 18 min
      • ^commentaire au dessus a supprimer… Ca dépend, mais si t’arrives a obfusquer un code (genre arduino) pour qu’il résiste des années, on t’embauche sur le champ 😀

        Publié par f4grx | 16 février 2015, 11 h 21 min
    • La décompilation marche généralement très mal, sauf pour le java ou .net, et en plus elle n’est pas toujours nécessaire.

      Ce qui est plus en commun c’est le désassemblage, qui est la traduction du hex en code source asm.

      Publié par f4grx | 16 février 2015, 11 h 19 min
  3. Est-ce que Atmel JTAG ICE mkII est réellement compatible avec AVRDUDE comme cela est indiqué sur le site de référence http://www.nongnu.org/avrdude/ ?
    Il me semble que depuis que j’ai installé des versions d’Atmel Studio récentes et le driver « Jungo », rien ne va plus!

    Publié par jmparatte | 14 février 2015, 19 h 51 min
    • Le mkII est compatible avec Avrdude, après si AVR studio a installé des drivers/firmware custom, je sais pas.
      D’après Google, semblerait que ce soit un problème de firmware https://www.olimex.com/forum/index.php?topic=2057.msg9251#msg9251

      Perso j’utilise une sonde Atmel-ICE en mode EDBG pour avrdude ou en mode standard avec AVR Studio pour le debug.
      Elle coûte une misère (moins de 50€, moins cher que l’AVR Dragon !) et fait le debug de tous les micro 8/32bits d’Atmel.

      Publié par Skywodd | 14 février 2015, 20 h 58 min
  4. Merci d’avoir dit « chiffrement » et non pas « cryptage »…

    Sinon merci pour le tuto, ça me fait un site de référence facile à trouver pour quand j’en aurai besoin 🙂

    Publié par f4grx | 16 février 2015, 10 h 32 min
  5. Bonjour, merci pour ce magnifique tuto, pour Linux, on fait comment ? J’ai pas mal de messages d’erreur quand je lance avrdude -v

    Publié par F4FXO | 18 janvier 2017, 10 h 55 min
  6. Bonjour,
    une fois sur Arduino-1.0.x\hardware\tools\avr\bin, comment faire pourlancer la commande avrdude -v ?
    j’ai un probleme pour l’appui du click droit de la souris et le Maj+GAUCHE DU CLAVIER.

    MERCI

    Publié par El Hadji Cata Ndiaye | 4 Mai 2017, 9 h 03 min
  7. Je n’arrive pas à faire cette sauvegarde de fichier HEX depuis un arduino Micro
    Est ce qu’il faut modifier ou adapter un truc qui me dépasse ?

    Je suis preneur d’une aide
    Merci

    Publié par claude | 3 janvier 2018, 11 h 25 min
    • Soldé ! J’ai réussi la manip
      Fichier .Hex fait en 3 exemplaires et comparé (aucune différence)

      Merci

      Publié par CLAUDE | 5 janvier 2018, 8 h 35 min
  8. Bonjour et merci pour cette excellent tuto, j’essaie de réaliser l’opération décrite su un arduino nano avec un puce mega328p mais je n’arrive pas à comprendre / résoudre le message d’erreur que me retourne la ligne de commande, a savoir :

    C:\Program Files (x86)\Arduino\hardware\tools\avr\bin>avrdude -p m328p -P COM3 –
    c arduino -U flash:r:C:\ »essai.hex »:i

    avrdude: can’t open config file «  »: Invalid argument
    avrdude: error reading system wide configuration file «  »

    j’ai essai quelque variation sans résultat, merci d’avance.

    Publié par supercureuil | 17 avril 2018, 12 h 50 min
  9. Ben il te manque le fichier de conf pour AVRDUDE

    Publié par claude | 17 avril 2018, 18 h 00 min
  10. ok merci pour cette réponse ,comment je le trouve / édite / creer ce fichier conf ? désolé si ma question parait stupide mais je suis loin d’être un expert 😉

    Publié par supercureuil | 17 avril 2018, 19 h 42 min
    • bon en cherchant bien j’ai trouver le fameux fichier conf, j’ai pas l’Arduino sous la mais j’essaie demain, merci
      encore

      Publié par supercureuil | 17 avril 2018, 20 h 29 min
    • Hello
      Ici tu trouveras AVRDUDE en dernière version :
      http://download.savannah.gnu.org/releases/avrdude/

      Dans le paquet ZIP tu as le fichier conf à mettre dans le dossier contenant AVRDUDE sur ton pc et après cela devrait mieux aller…
      Tu as également sous ce lien le fichier manuel en PDF qui est trés bien fait…
      Chaque paramètre est bien spécifié dans la ligne de commande à taper….

      Publié par claude | 18 avril 2018, 19 h 16 min
  11. au top merci beaucoup pour ton aide, je suis arrivé a faire ce que je voulais.

    Publié par supercureuil | 19 avril 2018, 16 h 01 min
  12. j’obtiens ça et je galère (loin de m’y connaître, en fait, j’applique bêtement !)

    Merci pour l’aide

    « PS C:\Program Files (x86)\Arduino\hardware\tools\avr\bin> .\avrdude -p m328p -P com6 -c arduino -U flash:r:C:\essai01.hex:i
    avrdude.exe: stk500_getsync() attempt 1 of 10: not in sync: resp=0x0d
    avrdude.exe: stk500_getsync() attempt 2 of 10: not in sync: resp=0x0a
    avrdude.exe: stk500_getsync() attempt 3 of 10: not in sync: resp=0x47
    avrdude.exe: stk500_getsync() attempt 4 of 10: not in sync: resp=0x72
    avrdude.exe: stk500_getsync() attempt 5 of 10: not in sync: resp=0x62
    avrdude.exe: stk500_getsync() attempt 6 of 10: not in sync: resp=0x6c
    avrdude.exe: stk500_getsync() attempt 7 of 10: not in sync: resp=0x20
    avrdude.exe: stk500_getsync() attempt 8 of 10: not in sync: resp=0x30
    avrdude.exe: stk500_getsync() attempt 9 of 10: not in sync: resp=0x2e
    avrdude.exe: stk500_getsync() attempt 10 of 10: not in sync: resp=0x39

    avrdude.exe done. Thank you. »

    Publié par Alain Fontaine | 19 août 2018, 19 h 21 min
  13. petite précision : c’est une carte nano récupérée sur un graveur laser.
    Est-ce possible que le bootloader (ou un truc du genre) soit verrouillé ?
    Merciiiiii

    Publié par Alain Fontaine | 19 août 2018, 19 h 28 min
  14. bonjour
    j’ai testé le chargement et telechargement avec une carte uno v3 tout fonctionne donc dans les 2 sens
    mais impossibele de faire quoi que ce soit sur un nano ou un minipro
    ils ont tous les 2 un atmega 328p
    ai je loupé quelque chose
    merci

    Publié par rene | 5 Mai 2019, 14 h 31 min

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.