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.
Salut Fabien,
Toujours aussi efficaces 😉
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.
@+
Même avec le code assembleur, comprendre son fonctionnement peut prendre des mois, voir des années selon la complexité du code.
heu, ça dépend fortement hein, on est d’accord 🙂
^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 😀
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.
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!
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.
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 🙂
« cryptage » ça veut techniquement rien dire et pourtant c’est dans le dico maintenant : http://www.larousse.fr/dictionnaires/francais/cryptage/20841
eh oui 🙂
Bonjour, merci pour ce magnifique tuto, pour Linux, on fait comment ? J’ai pas mal de messages d’erreur quand je lance avrdude -v
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
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
Soldé ! J’ai réussi la manip
Fichier .Hex fait en 3 exemplaires et comparé (aucune différence)
Merci
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.
Ben il te manque le fichier de conf pour AVRDUDE
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 😉
bon en cherchant bien j’ai trouver le fameux fichier conf, j’ai pas l’Arduino sous la mais j’essaie demain, merci
encore
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….
au top merci beaucoup pour ton aide, je suis arrivé a faire ce que je voulais.
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. »
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
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