jeudi 30 janvier 2020

ARDUINO : le BOOTLOADER


ARDUINO : le BOOTLOADER


Il y a des questions récurrentes sur le forum ARDUINO concernant le rechargement d'un bootloader sur une carte UNO, NANO, plus rarement MINI.
Il m'a semblé intéressant de mettre à disposition un petit article traitant ce sujet.

Tout d'abord on peut se poser la question : pourquoi charger un bootloader ?

On peut avoir besoin de charger un bootloader dans un ATMEGA328 vierge comme ICI :
https://riton-duino.blogspot.com/2019/07/montage-et-chargement-dun-atmega328p.html

Un deuxième cas de figure peut se présenter : le bootloader a été corrompu, ou bien on a un doute quant à sa présence, et il faut le recharger. Cela arrive ...

Sur une carte ARDUINO UNO ou NANO par exemple, lorsque l'on appuie sur le bouton RESET, le bootloader fait clignoter la LED de la sortie D13 trois fois.
Si ce n'est pas le cas, pas de doute à avoir, le bootloader est absent.

Cet article n'est pas le seul tutoriel que l'on peut trouver sur le WEB traitant du chargement d'un bootloader. Par contre il a l'avantage de présenter de manière très complète le cas particulier de l'ARDUINO NANO, spécialement lorsqu'il s'agit de cartes équipées du processeur ATMEGA328PB (chapitre 2).

1. Le bootloader

Le bootloader est un composant logiciel ayant deux fonctions principales :
  • chargement d'une application dans la mémoire FLASH du microcontrôleur à partir de la ligne série
  • lancement de l'application
Remarque : on appelle souvent l'application "sketch". C'est un petit nom sympathique commun dans le monde ARDUINO, mais je préfère l'appellation application, plus universelle.

Voyons donc le principe de fonctionnement de ce bootloader.

Au démarrage le bootloader attend pendant un certain temps la réception d'un caractère sur la ligne série. Si aucun caractère n'est reçu l'application est démarrée.
Cela a donc une conséquence directe : le démarrage est ralenti par cette attente.

1.1. Le protocole

Le logiciel PC en charge du chargement de l'application se nome AVRDUDE. Le protocole utilisé pour le chargement est le STK500 (STK500V2 pour une carte MEGA).
Qu'est ce qu'un protocole ? C'est un ensemble de règles qui permettent la compréhension mutuelle d'une conversation entre deux logiciels en vis-à-vis, reliés par un canal de communication : ligne série, Ethernet, radio, etc. Le protocole fixe la grammaire à utiliser pour la conversation :
  • démarrage de la conversation
  • envoi d'une adresse de chargement
  • effacement d'une page de FLASH
  • envoi des données binaires
  • etc.
Dans le cas du STK500 le caractère utilisé pour démarrer la conversation est :
GET_SYNCH : 0x0F
Le bootloader répond :
STK_INSYNC : 0x14.

Cet article (j'aime le titre : Everything You Always Wanted to know about Arduino Bootloading but Were Afraid to Ask) explique en détail le déroulement d'un chargement :
https://baldwisdom.com/bootloading/

Celui-ci donne quelques explications concernant le code source :
https://www.electronicwings.com/arduino/basics-to-developing-bootloader-for-arduino

1.2. Les différentes versions

La conversation entre AVRDUDE et le bootloader n'est pas identique pour toutes les cartes, ce qui explique que si l'on choisit le mauvais type de carte dans le menu de l'IDE il peut arriver certaines mésaventures :

         Using Port                    : /dev/ttyUSB1
         Using Programmer              : arduino
         Overriding Baud Rate          : 115200
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x4f


Ce message est une erreur signifiant : le bootloader a envoyé un caractère inattendu. Sa réponse ne correspond pas à la demande.

Cela arrive en particulier lorsque l'on essaie de charger une application dans une carte ARDUINO NANO ayant été chargée avec un bootloader nouvelle génération alors que l'on a sélectionné "ATmega328p (Old Bootloader)" dans le menu Outils / Processeur, ou l'inverse.

L'explication se trouve dans le fichier boards.txt, situé sous dans un répertoire local de l'utilisateur :
LINUX : /home/username/.arduino15/packages/arduino/hardware/avr/1.6.207/
username étant notre identifiant utilisateur
WINDOWS : C:\Program Files (x86)\Arduino\hardware\arduino\avr

Dans ce fichier, pour chaque type de carte, un paramètre permet de fixer le nom du bootloader utilisé :

uno.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
nano.menu.cpu.atmega328.bootloader.file=optiboot/optiboot_atmega328.hex
nano.menu.cpu.atmega328old.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex

On voit bien que les cartes n'utilisent pas toutes le même bootloader.
Cela explique aussi pourquoi, si l'on choisit la carte "Arduino / Genuino UNO" dans le menu Outils, le chargement d'une application est possible sur une NANO, et vice-versa.
En effet le bootloader est le même, et de plus cela ne pose aucun problème.

2. Le chargement

Charger un bootloader ne se fait pas par la ligne série, mais par le bus SPI, à l'aide des broches MISO, MOSI, SCK.

Cette interface se nomme ISP (In Site Programming).
Il n'y a aucun code associé à cette interface. Concrètement c'est une solution de programmation incluse dans le microcontrôleur. Certains processeurs (STM32 en tête) offrent la possibilité de charger une application via une ligne série, ou bien un bus SPI ou I2C. L'ATMEGA est plus ancien, et ne propose que le SPI.

Nous devrons aussi alimenter la carte à charger, et aurons donc besoin de deux broches supplémentaires VCC et GND.

La broche RESET sera utilisée pour redémarrer la carte et pour commuter le microcontrôleur cible en mode esclave.

Cela fait 6 broches en tout.

On peut utiliser le connecteur ICSP dont certaines cartes sont équipées (UNO, NANO) :
Connecteur ICSP sur UNO

Connecteur ICSP sur NANO

Sinon il faut utiliser les broches MISO, MOSI, SCK et RESET disponibles sur les deux rangées de broches classiques (PRO MINI par exemple) :


Il existe différents moyens d'effectuer l'opération :
  • un programmateur spécialisé :
    • ATMEL-ICE
    • USBASP
    • USBTINY
    • BusPirate
    • etc.
  • une carte UNO ou NANO utilisée comme programmateur "As ISP"

2.1. Programmateur USBASP

Programmateur USBASP
Comme on le voit sur cette image le programmateur USBASP est généralement livré avec un câble en nappe et un adaptateur à 6 broches.
Cet adaptateur est directement enfichable sur le connecteur ICSP d'une carte NANO ou UNO.
Si l'on veut raccorder ce programmateur sur une PRO MINI le schéma précédent doit être utilisé.

2.2. Programmateur utilisant une UNO ou NANO

Il existe deux méthodes :
  • ArduinoISP pour les cartes UNO, NANO ou PRO MINI
  • Atmega_Board_Programmer (by Nick Gammon)
ArduinoISP est une méthode classique, mais elle ne fonctionne pas pour charger un bootloader dans une MEGA.

Atmega_Board_Programmer peut certainement convenir à pas mal de cartes. Je l'ai seulement testé avec une MEGA.

Donc, si l'on veut charger le bootloader d'une carte MEGA, voir directement 2.2.2.
S'il s'agit d'une autre carte on a le choix entre les deux méthodes.


2.2.1. ArduinoISP
On peut utiliser une carte additionnelle pour charger le bootloader sur une carte UNO, NANO ou PRO MINI, c'est à dire que la deuxième carte va être utilisée en tant que programmateur.
Cette page explique les raccordements à effectuer entre les deux cartes :
https://www.arduino.cc/en/tutorial/arduinoISP

On peut donc charger un bootloader dans une carte nommée TARGET en utilisant une carte nommée PROGRAMMER. Toutes les combinaisons sont possibles :
  • UNO et UNO
  • UNO et NANO
  • MEGA et UNO
  • NANO et UNO
  • etc.
Voici le cas le plus courant (2 UNOs) :


C'est très simple comme on peut le voir. Les raccordements sont effectués à l'aide de classiques fils DUPONT.
Il peut arriver qu'un fil DUPONT soit défectueux. Il vaut mieux les tester à l'ohmmètre avant de les utiliser. Le bus SPI n'est pas si facile à déboguer, à moins de disposer d'un analyseur de signaux.

La carte appelée PROGRAMMER (celle qui va servir de programmateur) doit être reliée au PC à l'aide d'un cordon USB.

La carte TARGET (celle qui va recevoir le bootloader) est reliée à la première à l'aide de 6 fils.
Ensuite un sketch spécialement prévu doit être chargé dans la carte PROGRAMMER. Cette application permet donc de transformer une carte quelconque en programmateur ISP :

Menu Fichier / Exemples / 11. ArduinoISP / ArduinoISP

Avant de compiler et charger ce sketch il faut d'abord sélectionner le type de carte (Outils / Type de carte).

Important : il s'agit ici de sélectionner le type de la carte PROGRAMMER, pas celui de la carte TARGET.

Il faut aussi sélectionner le bon port Série dans le menu Outils / Port.

Compiler et charger ce sketch (bouton Téléverser).

2.2.2. Atmega_Board_Programmer
Le chargemment du bootloader d'une MEGA ne fonctionne pas avec la méthode précédente.
Apparemment le sketch ArduinoISP n'est pas capable de réaliser cette opération.
Nick Gammon a écrit un autre sketch :
https://www.gammon.com.au/bootloader

Voici le sketch qui va remplacer ArduinoISP :
https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Board_Programmer

Si vous utilisez cette version github, elle fonctionnera sans problème.

Pour éviter d'avoir à télécharger chaque fichier un par un je conseille de récupérer un zip de l'ensemble des sketches de Nick Gammon ici :
https://github.com/nickgammon/arduino_sketches.git
Installer ensuite ce ZIP dans les exemples de l'IDE ARDUINO.

Par contre il se peut que vous trouviez des versions ZIP assez anciennes, par exemple ici :http://gammon.com.au/Arduino/Atmega_Board_Programmer.zip
Le compilateur AVR a évolué. Des erreurs sont générées à la compilation.
Il est nécessaire de faire quelques petites corrections dans tous les fichiers .h du sketch (ajouter const) :

Exemple : bootloader_atmega2560_v2.h :

const byte PROGMEM atmega2560_bootloader_hex [] = {

Si const est déjà présent, c'est OK.

Ensuite on peut suivre tranquillement les instructions de la page de Nick Gammon.

En résumé :
Compiler et charger ce sketch (bouton Téléverser) en ayant pris soin de sélectionner le bon type de carte PROGRAMMER.

Ensuite tout se passe dans le moniteur série :

Atmega chip programmer.
Writt
Atmega chip programmer.
Written by Nick Gammon.
Version 1.21
Compiled on Feb  1 2020 at 14:22:58
Entered programming mode OK.
Signature = 0x1E 0x98 0x01 
Processor = ATmega2560
Flash memory size = 262144 bytes.
LFuse = 0xFF 
HFuse = 0xD8 
EFuse = 0xFD 
Lock byte = 0xCF 
Clock calibration = 0x55 
Bootloader address = 0x3E000
Bootloader length = 7474 bytes.
Type 'V' to verify, or 'G' to program the chip with the bootloader ... 


Entrer 'G' puis RETURN dans le terminal :

Erasing chip ...
Writing bootloader ...
Committing page starting at 0x3E000
Committing page starting at 0x3E100
Committing page starting at 0x3E200
Committing page starting at 0x3E300
Committing page starting at 0x3E400
Committing page starting at 0x3E500
Committing page starting at 0x3E600
Committing page starting at 0x3E700
Committing page starting at 0x3E800
Committing page starting at 0x3E900
Committing page starting at 0x3EA00
Committing page starting at 0x3EB00
Committing page starting at 0x3EC00
Committing page starting at 0x3ED00
Committing page starting at 0x3EE00
Committing page starting at 0x3EF00
Committing page starting at 0x3F000
Committing page starting at 0x3F100
Committing page starting at 0x3F200
Committing page starting at 0x3F300
Committing page starting at 0x3F400
Committing page starting at 0x3F500
Committing page starting at 0x3F600
Committing page starting at 0x3F700
Committing page starting at 0x3F800
Committing page starting at 0x3F900
Committing page starting at 0x3FA00
Committing page starting at 0x3FB00
Committing page starting at 0x3FC00
Committing page starting at 0x3FD00
Committing page starting at 0x3FE00
Committing page starting at 0x3FF00
Written.
Verifying ...
No errors found.
Writing fuses ...
LFuse = 0xFF
HFuse = 0xD8
EFuse = 0xFD
Lock byte = 0xCF
Done.
Type 'C' when ready to continue with another chip ...


Apparemment ce sketch serait capable de charger le bootloader d'un grand nombre de cartes :
  • Atmega8
  • Atmega168 Optiboot
  • Atmega328 Optiboot
  • Atmega328 (8 MHz)
  • Atmega32U4 for Leonardo
  • Atmega1280 Optiboot
  • Atmega1284 Optiboot
  • Atmega2560
  • Atmega16U2
  • Atmega256RFR2
Il procède par détection de la signature du microcontrôleur et charge donc le bootloader correspondant à cette signature.
Je l'ai essayé avec succès avec une UNO comme carte PROGRAMMER et une MEGA2560 comme carte TARGET.

Je ne l'ai pas encore essayé avec d'autres cartes, mais cela viendra.
L'intérêt est que le sketch contient pas mal de bootloaders sous forme de blobs binaires. La conséquence est qu'il ne communique pas avec le PC pour transférer le bootloader à la carte TARGET.
Le chargement est donc extrêmement rapide (3s).
Il est très intéressant dans le cas où l'on a plusieurs de cartes à charger.

Comme le sketch de Nick Gammon réalise toutes les opérations nécessaires il est inutile de lire le paragraphe suivant : 2.3. Charger le bootloader, puisque c'est déjà fait.
On peut passer directement au paragraphe 2.4. Vérification.


2.3. Charger le bootloader

Pour ce faire il faut procéder comme suit :

Sélectionner le bon programmateur :
  • USBasp si vous possédez un programmateur USBASP
  • USBtinyISP si vous possédez un programmateur USBTINY
  • Arduino As ISP si vous utilisez une carte ARDUINO comme programmateur
  • etc.
Sélectionner le type de carte cible.

Important : il s'agit ici de sélectionner le type de la carte TARGET.

Cela permet à avrdude d'envoyer le bootloader adéquat pour la carte en question (TARGET).

Pour envoyer le bootloader il faut utiliser le menu Outils / Graver la séquence d'initialisation.

avrdude va donc envoyer les informations binaires à la carte PROGRAMMER qui les transmettra via le bus SPI à la carte TARGET.

2.4. Vérification

On peut ensuite raccorder la carte TARGET au PC à l'aide d'un cordon USB et charger le sketch Blink :

Menu Fichier / Exemples / 01. Basics / Blink

Compiler et charger ce sketch (bouton Téléverser).

Un oubli courant : il est indispensable de débrancher le fil de RESET de la carte TARGET avant de charger le sketch.

2.5. Ça marche pôôô

Si cela ne fonctionne pas, tout dépend de l'étape à laquelle on détecte un problème :

2.5.1. Chargement du sketch ArduinoISP
Ce cas ne devrait pas arriver. Il faut avant tout vérifier que l'on utiliser comme PROGRAMMATEUR une carte qui fonctionne, en chargeant un sketch Blink par exemple.

Si le problème persiste, la cause peut être :
  • câble USB défectueux
  • carte défectueuse
  • bootloader absent
  • mauvais choix du port série
  • etc.
Voir cet article :
https://riton-duino.blogspot.com/2018/10/arduino-problemes-de-televersement.html

2.5.2. Chargement du bootloader
Si le programmteur refuse de charger le sketch le problème provient certainement d'un défaut de branchement du connecteur ICSP :

Si un programmateur du genre USBASP est utilisé, s'assurer du bon sens de branchement du connecteur ICSP. Attention ce connecteur n'est pas soudé dans le même sens sur une UNO ou sur une NANO.
Si le branchement a été fait à l'envers, que l'on se rassure, ce n'est pas destructeur.

Si une carte ARDUINO est utilisée comme programmateur, vérifier et revérifier les connexions. remplacer éventuellement les fils DUPONT.

2.5.3. Vérification
Après avoir chargé le bootloader, si l'on rencontre un problème de chargement d'une application quelconque, cela peut avoir pour origine le même problème qu'en 2.5.1. Chargement du sketch ArduinoISP.

Il y a une cause possible supplémentaire : avoir sélectionné le mauvais port série, en particulier avoir sélectionné le port de la carte PROGRAMMER en croyant avoir choisi le port de la carte TARGET ce qui revient à charger le sketch Blink dans la carte PROGRAMMER.
Dans ce cas, recommencer depuis le début.

2. Cas particulier : l'ARDUINO NANO

Comme on l'a dit précédemment la NANO a un historique perturbé et elle a été équipée de deux bootloaders différents :
  • atmega (old bootloader)
  • optiboot (new bootloader)
Lorsque l'on commande des cartes NANOs chez de revendeurs différents, on peut très bien à la longue se retrouver avec dans ses tiroirs des cartes "Old Bootloader" et des cartes "New Bootloader".
Dans ce cas il est possible, si l'on trouve cette situation ennuyeuse, d'harmoniser ses cartes.

Un deuxième cas de figure peut se présenter : le bootloader a été corrompu et il faut le recharger. Cela arrive ...

Il suffit donc de refaire l'opération décrite au paragraphe 2. Le chargement.
On sélectionnera dans Outils :
  • Type de carte : Arduino Nano
  • Processeur :
    • ATmega328P si l'on désire charger le nouveau bootloader
    • ATmega328P (Old Bootloader) si l'on désire charger l'ancien
Ensuite : menu Outils / Graver la séquence d'initialisation.

Une fois que la manipulation a été testée avec succès sur la première carte, il est très rapide de la répéter sur 10 ou 20 exemplaires.

2.1. Aïe Aïe Aïe

Cela ne se passe pas comme prévu. Le chargement du bootloader affiche un vilain message pas sympathique du tout :

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: Expected signature for ATmega328P is 1E 95 0F
         Double check chip, or use -F to override this check.
Erreur lors de la gravure de la séquence d'initialisation.


Explication : beaucoup de cartes NANO sont équipées d'un microcontrôleur ATMEGA328PB au lieu d'un ATMEGA328P et avrdude ne reconnaît pas la signature(0x1e9516 au lieu de 0x1E950F).

Il convient donc de forcer le chargement avec l'option -F comme dit dans le message, autrement dit : avec l'option -F avrdude ne vérifiera pas la signature.

Mais comment faire ?
Il existe certainement d'autres méthodes, mais l'utilisation d'avrdude en ligne de commande est une option facile.

Comment récupérer cette ligne de commande ?

La première chose à faire est d'afficher les préférences :
Menu Fichier / Préférences :
  • Afficher les résultats détaillés pendant :
    • cocher "téléversement"
Cocher "compilation" peut être également utile si l'on désire plus de diagnostic pendant la compilation des sketches.

A partir de ce moment il va falloir considérer le type de système d'exploitation installé sur la machine.

2.1.1 Machine LINUX
J'ai réalisé les opérations suivantes sur un IDE version 1.8.5. Cela sera très peu différent avec une autre version.

Dans l'exemple suivant j'ai utilisé un programmateur USBASP.
Si l'on désire réaliser la même opération avec une carte ARDUINO comme PROGRAMMATEUR il suffit de remplacer :
-cusbasp
par :
-carduino -P/dev/ttyUSBX -b19200 (ttyUSBX : le port série)

Essayons une nouvelle fois : Outils / Graver la séquence d'initialisation.

/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/bin/avrdude -C/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m
// ...
// ... ICI un tas de messages inutiles

// ...
avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9516 (probably m328pb)
avrdude: Expected signature for ATmega328P is 1E 95 0F
         Double check chip, or use -F to override this check.

avrdude done.  Thank you.

Erreur lors de la gravure de la séquence d'initialisation.


Nous obtenons donc beaucoup plus de détails et en particulier la ligne de commande utilisée pour lancer avrdude.

La méthode est de recopier la première ligne affichée par l'IDE :

/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/bin/avrdude -C/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m 

On pourrait croire qu'il suffit d'ajouter -F pour arranger les choses :

/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/bin/avrdude -C/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F

Le chargement du bootloader a l'air de bien se passer mais en examinant les messages on se rend vite compte qu'avrdude se contente de charger les fuses. Il est évident que le bootloader n'est pas chargé. Il faut ajouter le chemin du bootloader avec l'option -U flash:w:

/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/bin/avrdude -C/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F -U flash:w:/home/username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex

La version 6.3.0-arduino14 ou 1.6.207 n'est pas forcément correcte et dépend forcément de la version de l'IDE.

Si l'on désire charger l'ancien bootloader il faut remplacer : optiboot/optiboot_atmega328.hex
par :
atmega/ATmegaBOOT_168_atmega328.hex

Personnellement j'ai choisi optiboot.

Voici le résultat :

/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/bin/avrdude -C/home/username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F -U flash:w:/home/username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex

avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/home/
username/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino14/etc/avrdude.conf"
         User configuration file is "/home/
username/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : usb
         Using Programmer              : usbasp
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : usbasp
         Description     : USBasp, http://www.fischl.de/usbasp/

avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9516 (probably m328pb)
avrdude: Expected signature for ATmega328P is 1E 95 0F
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as F5
avrdude: erasing chip
avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x3F:
avrdude: load data lock data from input file 0x3F:
avrdude: input file 0x3F contains 1 bytes
avrdude: reading on-chip lock data:

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

avrdude: verifying ...
avrdude: 1 bytes of lock verified
avrdude: reading input file "0xFD"
avrdude: writing efuse (1 bytes):

Writing |                                                    | 0% 0.00s ***failed;
Writing | ################################################## | 100% 0.03s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xFD:
avrdude: load data efuse data from input file 0xFD:
avrdude: input file 0xFD contains 1 bytes
avrdude: reading on-chip efuse data:

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

avrdude: verifying ...
avrdude: WARNING: invalid value for unused bits in fuse "efuse", should be set to 1 according to datasheet
This behaviour is deprecated and will result in an error in future version
You probably want to use 0xf5 instead of 0xfd (double check with your datasheet first).
avrdude: 1 bytes of efuse verified
avrdude: reading input file "0xDA"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xDA:
avrdude: load data hfuse data from input file 0xDA:
avrdude: input file 0xDA contains 1 bytes
avrdude: reading on-chip hfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xFF"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xFF:
avrdude: load data lfuse data from input file 0xFF:
avrdude: input file 0xFF contains 1 bytes
avrdude: reading on-chip lfuse data:

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

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "/home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex"
avrdude: input file /home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex auto detected as Intel Hex
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against /home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: load data flash data from input file /home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex:
avrdude: input file /home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex auto detected as Intel Hex
avrdude: input file /home/
username/.arduino15/packages/arduino/hardware/avr/1.6.207/bootloaders/optiboot/optiboot_atmega328.hex contains 32768 bytes
avrdude: reading on-chip flash data:

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

avrdude: verifying ...
avrdude: 32768 bytes of flash verified

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as F5
avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)

avrdude done.  Thank you.


Voilà c'est terminé. Le chargement d'une application (Blink par exemple) se fera dorénavant en choisissant l'option par défaut :
Outils / Processeur / ATmega328P
et non pas :
Outils / Processeur / ATmega328P (Old Bootloader).

Si l'on a choisi l'ancien bootloader, ce sera le contraire.

2.1.2 Machine WINDOWS
J'ai réalisé les opérations suivantes sur un IDE version 1.8.8. Cela sera très peu différent avec une autre version.

Dans l'exemple suivant j'ai utilisé un programmateur USBASP.
Si l'on désire réaliser la même opération avec une carte ARDUINO comme PROGRAMMATEUR il suffit de remplacer :
-cusbasp
par :
-carduino -PCOMX -b19200 (COMX : le port série)

Si l'on utilise un programmateur USBASP sous Windows, un driver est nécessaire :
https://protostack.com.au/2015/01/usbasp-windows-driver-version-3-0-7/

L'utilisation des clones de cartes ARDUINO NANO avec convertisseur USB / série CH340 nécessite également l'ajout d'un driver :
https://cdn.sparkfun.com/assets/learn_tutorials/8/4/4/CH341SER.EXE

Essayons une nouvelle fois : Outils / Graver la séquence d'initialisation.

C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude -CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m
// ...
// ... ICI un tas de messages inutiles

// ...
avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

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

avrdude: Device signature = 0x1e9516 (probably m328pb)
avrdude: Expected signature for ATmega328P is 1E 95 0F
         Double check chip, or use -F to override this check.

avrdude done.  Thank you.

Erreur lors de la gravure de la séquence d'initialisation.


Nous obtenons donc beaucoup plus de détails et en particulier la ligne de commande utilisée pour lancer avrdude.

La méthode est de recopier la première ligne affichée par l'IDE :

C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude -CC:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m

Sous Windows il sera nécessaire d'ajouter des quotes (à cause des espaces dans "C:\Program Files (x86)" - ce nom de répertoire est vraiment une mauvaise idée - et de remplacer les '/' par des '\' :

"C:\Program Files (x86)"\Arduino\hardware\tools\avr\bin\avrdude -C"C:\Program Files (x86)"\Arduino\hardware\tools\avr\etc\avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m

On pourrait croire qu'il suffit d'ajouter -F pour arranger les choses :

"C:\Program Files (x86)"\Arduino\hardware\tools\avr\bin\avrdude -C"C:\Program Files (x86)"\Arduino\hardware\tools\avr\etc\avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F

Le chargement du bootloader a l'air de bien se passer mais en examinant les messages on se rend vite compte qu'avrdude se contente de charger les fuses. Il est évident que le bootloader n'est pas chargé. Il faut ajouter le chemin du bootloader à charger avec l'option -U flash:w:

Sous Windows si l'on exécute la ligne suivante le chargement ne se fait pas non plus :

"C:\Program Files (x86)"\Arduino\hardware\tools\avr\bin\avrdude -C"C:\Program Files (x86)"\Arduino\hardware\tools\avr\etc\avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F 0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F -U flash:w:"C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\optiboot\optiboot_atmega328.hex"

La ligne de commande est peut-être trop longue : 272 caractères.
J'ai été obligé de raccourcir celle-ci en changeant de répertoire courant :

cd "\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\optiboot"

Si l'on désire charger l'ancien bootloader il faut remplacer :optiboot
par :
atmega

"C:\Program Files (x86)"\Arduino\hardware\tools\avr\bin\avrdude -C"C:\Program Files (x86)"\Arduino\hardware\tools\avr\etc\avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F -U flash:w:optiboot_atmega328.hex

Si l'on désire charger l'ancien bootloader il faut remplacer :
optiboot_atmega328.hex
par :
ATmegaBOOT_168_atmega328.hex

Avec cette méthode cela fonctionne enfin.

Personnellement j'ai choisi optiboot.

Voici le résultat :

"C:\Program Files (x86)"\Arduino\hardware\tools\avr\bin\avrdude -C"C:\Program Files (x86)"\Arduino\hardware\tools\avr\etc\avrdude.conf -v -patmega328p -cusbasp -Pusb -e -Ulock:w:0x3F:m -Uefuse:w:0xFD:m -Uhfuse:w:0xDA:m -Ulfuse:w:0xFF:m -F -Uflash:w:optiboot_atmega328.hex

avrdude: Version 6.3-20171130
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"

         Using Port                    : usb
         Using Programmer              : usbasp
         AVR Part                      : ATmega328P
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PC2
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : usbasp
         Description     : USBasp, http://www.fischl.de/usbasp/

avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.06s

avrdude: Device signature = 0x1e9516 (probably m328pb)
avrdude: Expected signature for ATmega328P is 1E 95 0F
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as F5
avrdude: erasing chip
avrdude: auto set sck period (because given equals null)
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: reading input file "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lock written
avrdude: verifying lock memory against 0x3F:
avrdude: load data lock data from input file 0x3F:
avrdude: input file 0x3F contains 1 bytes
avrdude: reading on-chip lock data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lock verified
avrdude: reading input file "0xFD"
avrdude: writing efuse (1 bytes):

Writing |                                                    | 0% 0.00s ***failed;
Writing | ################################################## | 100% 0.05s

avrdude: 1 bytes of efuse written
avrdude: verifying efuse memory against 0xFD:
avrdude: load data efuse data from input file 0xFD:
avrdude: input file 0xFD contains 1 bytes
avrdude: reading on-chip efuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: WARNING: invalid value for unused bits in fuse "efuse", should be set to 1 according to datasheet
This behaviour is deprecated and will result in an error in future version
You probably want to use 0xf5 instead of 0xfd (double check with your datasheet first).
avrdude: 1 bytes of efuse verified
avrdude: reading input file "0xDA"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of hfuse written
avrdude: verifying hfuse memory against 0xDA:
avrdude: load data hfuse data from input file 0xDA:
avrdude: input file 0xDA contains 1 bytes
avrdude: reading on-chip hfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
avrdude: reading input file "0xFF"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.00s

avrdude: 1 bytes of lfuse written
avrdude: verifying lfuse memory against 0xFF:
avrdude: load data lfuse data from input file 0xFF:
avrdude: input file 0xFF contains 1 bytes
avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.01s

avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: reading input file "optiboot_atmega328.hex"
avrdude: input file optiboot_atmega328.hex auto detected as Intel Hex
avrdude: writing flash (32768 bytes):

Writing | ################################################## | 100% 0.05s

avrdude: 32768 bytes of flash written
avrdude: verifying flash memory against optiboot_atmega328.hex:
avrdude: load data flash data from input file optiboot_atmega328.hex:
avrdude: input file optiboot_atmega328.hex auto detected as Intel Hex
avrdude: input file optiboot_atmega328.hex contains 32768 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.03s

avrdude: verifying ...
avrdude: 32768 bytes of flash verified

avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DA
avrdude: safemode: efuse reads as F5
avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)

avrdude done.  Thank you.


Voilà c'est terminé. Le chargement d'une application (Blink par exemple) se fera dorénavant en choisissant l'option par défaut :
Outils / Processeur / ATmega328P
et non pas :
Outils / Processeur / ATmega328P (Old Bootloader).

Si l'on a choisi l'ancien bootloader, ce sera le contraire.

3. Se passer de bootloader

On peut parfaitement se passer de bootloader et utiliser un programmateur pour charger une application.
Dans ce cas on utilisera le menu Croquis / Téléverser avec un programmateur, en ayant choisi le programmateur au préalable dans le menu Outils / Programmateur.

On récupèrera du même coup l'espace occupé par le bootloader (2Ko). Ce n'est pas énorme, mais cela peut aider.

On pourra aussi conserver l'affichage sur le terminal (Moniteur Série) à travers le cordon USB.

4. Conclusion

J'espère avoir apporté ma petite contribution à la résolution des problèmes de bootloader que certains utilisateurs rencontrent.
Je suis bien conscient que le cas particulier de l'ARDUINO NANO n'est pas évident, mais il est difficile d'expliquer de manière plus simple, spécialement lorsque l'on travaille sous Windows.

Une dernière remarque : travailler sur ARDUINO avec une machine WINDOWS était une première pour moi, et cette première expérience n'a fait que confirmer mes (mauvaises) impressions :
  • lenteur remarquable
  • utilisation des '\' à la place de '/' dans le noms des répertoires, une option débile datant des années 1980, alors que sous UNIX le '/' était utilisé depuis 1969
  • installation nécessaire de drivers supplémentaires (USBASP, CH340, etc.), absolument inutiles sous LINUX.
  • installation de l'IDE ARDUINO dans C:\Program Files (x86), un nom avec espaces qui ne facilite pas les choses. Je recommande plutôt d'installer l'IDE à l'aide de la version ZIP, dans votre répertoire personnel, cela évitera bien des désagréments.

Cordialement
Henri

mardi 21 janvier 2020

Un logger analogique et digital (version WEB)



 Un logger analogique et digital

(version WEB)



Cet article d'août 2019 décrivait un logger analogique et digital :

https://riton-duino.blogspot.com/2019/08/un-logger-analogique-et-digital.html

Cet outil a une limitation : si l'on veut observer l'évolution des sorties d'un montage sur table à proximité d'un PC tout va bien, mais dans le cas d'un montage éloigné, il est difficile d'utiliser un câble USB de grande longueur. Et tout le monde ne possède pas un PC portable que l'on peut dédier à cette tâche.

Et si l'on étudiait une version WIFI ?

Ce projet est assez vaste et les sujets abordés sont plutôt variés :
  • sujet ESP32 :
    • serveur et client WEB
    • utilisation d'un INA226
    • créer un formulaire WEB
    • envoi de données à un serveur
  • sujet PC ou RASPBERRY PI : 
    • serveur WEB en PYTHON avec CHERRYPY
    • génération d'une page WEB à partir d'une template
    • utilisation de graphes HICHARTS
    • génération d'un fichier CSV et export

1. Le besoin

Mes besoins concernent principalement la mesure de différentes grandeurs :
  • tension d'alimentation et courant
  • sorties digitales
  • tensions diverses
Le système doit être capable de faire des relevés de mesures et de permettre la visualisation de graphes via un navigateur.

Il ne s'agit pas ici de bâtir un analyseur logique. Cet outil n'est pas fait pour observer des variations rapides de signaux, mais plutôt de tracer des variations sur la durée :
  • charge ou décharge d'une batterie
  • allumage d'une LED
  • activation d'un relais
  • etc.
La première idée qui vient à l'esprit est d'utiliser un ESP32, celui-ci possédant un grand nombre d'entrées / sorties et en particulier plusieurs canaux analogiques.

1.1. Mesure de la tension d'alimentation et du courant

Il s'agit ici de suivre l'évolution de la tension et du courant d'alimentation d'un montage, qu'il s'agisse d'une alimentation secteur ou d'une batterie.

Le système doit être capable de mesurer des tensions supérieures à celle de la tension 3.3V d'alimentation de l'ESP32.

Il doit également être capable de mesurer le courant circulant dans une batterie, aussi bien en décharge qu'en charge, ce qui implique une capacité à mesurer un courant négatif.

Pour réaliser cette opération un module INA226 est un bon choix :
C'est un composant I2C capable de mesurer une tension jusqu'à 36V et un courant positif ou négatif.
Généralement le shunt soudé sur la carte est un 10mΩ (marquage R010). Le courant maximal mesurable sera de 8A. Avec un shunt de 100mΩ (marquage R100) il sera de 800mA.

Avec un shunt de 100mΩ on obtiendra plus de résolution pour mesurer des courants faibles.
La tension maximale aux bornes du shunt est de 81.92mV, ce qui correspond avec un shunt de 100mΩ à un courant maximal mesurable arrondi de 820mA.
La résolution est donc de 820 / 32768 = 25µA.
Avec un shunt de 10mΩ elle sera 10 fois supérieure (250µA).
Tout dépend donc de ce que l'on cherche à mesurer. Personnellement je ne mesure jamais de courants forts, donc je remplace systématiquement le shunt 10mΩ par un 100mΩ (résistances CMS 2010 ou 2512).

A noter : le premier module INA226 que j'ai utilisé mesurait une tension de 4.3V sur une batterie LITHIUM-ION, pour une tension réelle de 4.1V. Je l'ai remplacé et j'ai bien obtenu 4.1V avec un deuxième module. Le premier exemplaire est probablement défectueux.

Afin de minimiser le bruit le temps de conversion choisi est de 8.144ms.
Une moyenne sur 16 échantillons est effectuée.

1.2. Entrées / sorties digitales

La surveillance de signaux logiques se fera à l'aide des entrées digitales de l'ESP32. Attention certaines ne sont pas libres. Voir le schéma plus bas.

1.3. Entrées analogiques

Les entrées analogiques de l'ESP32 pourront être utilisées pour la surveillance de tensions diverses.

1.4. Stockage des mesures

Afin de ne pas encombrer la FLASH de l'ESP32, et ne pas être limité en capacité de stockage,  la tâche de stockage des mesures est confiée à un serveur écrit en PYTHON. Ce logiciel peut être exécuté sur tout ordinateur : PC, MAC ou RASPBERRY PI.
Les données sont stockées en mémoire RAM. Une fonction d'export vers un fichier CSV existe.

Ce serveur de stockage et visualisation est appelé HOST dans la suite de l'article.

L'intérêt d'utiliser une RASPBERRY PI pour héberger ce serveur est assez clair : pouvoir enregistrer des mesures sur la durée sans monopoliser un PC, gros consommateur d'énergie.
Le PC pourra être utilisé uniquement pour la visualisation.

Les tâches sont donc réparties comme suit :

ESP32 :
  • serveur de mesure
  • interface homme machine
    • sélection adresse IP et port du serveur de stockage
    • choix de la période de mesure
    • sélection des mesures à effectuer
    • lancement des mesures
  • envoi des informations au host
HOST :
  • serveur de stockage
  • interface homme machine
    • visualisation des graphes
    • remise à zéro des données
    • export vers un fichier CSV
Comme on le voit l'ESP32 est donc implémenté sous la forme d'un serveur et d'un client WEB.

1.5. Visualisation des mesures

La visualisation se fait via un navigateur.

Si le serveur host tourne sur le même PC on utilisera l'URL 127.0.0.1:80.
S'il tourne sur un autre PC ou une RASPBERRY PI on utilisera l'adresse IP de cette machine.

Côté host l'affichage des graphes est confié à des objets HighCharts. Il s'agit d'une librairie JavaScript que j'utilise depuis pas mal d'années avec beaucoup de satisfaction.

Attention : cette librairie est gratuite pour les particuliers mais pas pour les entreprises.

Cette librairie a déjà été présentée dans cet article :
https://riton-duino.blogspot.com/2019/02/un-web-server-sur-ethernet.html

1.6. Conservation des mesures

Le logiciel est capable d'exporter les résultats sous forme de fichier CSV. Ils seront donc stockés sur le PC sur lequel est lancé le navigateur.

2. Le schéma


Le schéma est réalisé à l'aide de KICAD.

Pour récupérer le projet voir plus bas :  9. Téléchargements.

Le connecteur P1 permet le raccordement d'un convertisseur USB / série pour la programmation du module et les boutons EN et BOOT doivent être utilisés pour effectuer le chargement.

Le bornier P2 permet la mesure tension / courant via l'INA226, et le connecteur P3 regroupe les entrées / sorties du module ESP32.

3. Le matériel

Ce projet peut être réalisé soit avec un module ESP32 soudé sur PCB ou avec une carte ESP32.
Pour cette réalisation le matériel nécessaire est le suivant :
  • solution sur PCB :
    • 1 module ESP32-WROOM
    • 2 boutons poussoirs 6x6
    • 2 résistances de 10KΩ
    • 3 condensateurs film polyester de 100nF
    • 1 condensateur électrochimique 10µF 10V 
    • 1 connecteur 3 points au pas de 2.54
    • 1 connecteur JACK d'alimentation 
    • 1 LM3940
    • 1 condensateur film polyester de 470nF
    • 1 condensateur électrochimique 33µF 10V
  • ou
    • 1 carte ESP32
  • 1 module INA226
  • 1 condensateur film polyester de 100nF
  • 1 connecteur 20 points au pas de 2.54
  • 1 bornier 4 points au pas de 5.08

3.1. Solution avec PCB :

Si l'on désire réaliser un PCB il est préférable d'utiliser un module ESP32-WROOM :
Il est assez peu judicieux de choisir une carte ESP32 pour l'implanter sur un PCB car il existe une quantité de modèles importante et leur pérennité n'est pas forcément assurée.

Un montage sur plaquette à pastilles est parfaitement envisageable. Dans ce cas on peut utiliser une carte adaptatrice :
Si la solution PCB ou plaquette  à pastilles est choisie un convertisseur USB / série 3.3V ou 5V / 3.3V sera nécessaire :

3.2. Solution avec carte ESP32

On peut choisir une carte du type ESP32-DEVKIT :
Dans ce cas le schéma sera réduit à sa plus simple expression :
  • carte ESP32 (ESP32-DEVKIT, WEMOS D1, etc.)
  • module INA226
  • connecteurs P1 à P3.

3.3. Alimentation

L'énergie est fournie au montage par un adaptateur secteur 5V à 9V 1A grâce à la présence d'un connecteur JACK et d'un régulateur 3.3V.

3.3.1. Adaptateur secteur 5V
Le LM3940 est un régulateur Low Drop Out (sa tension de chute est de 800mV). Un LM7833 ne conviendra pas (sa tension de chute est de 2V).
Un MCP1827S ou un LF33CV peuvent convenir également.

3.3.2. Alimentation par batterie
Sur ce même JACK on peut raccorder aussi une ou plusieurs batteries 18650 en parallèle ou une batterie LIPO. Il faudra compter 2000mAH par journée de fonctionnement, ce qui est plutôt conséquent.

3.3.3. Adaptateur secteur 6V à 9V
Si l'on désire alimenter avec un adaptateur secteur de plus de 5V le LM3940 ne suffira pas (il supporte 5.5V maxi). Il faudra le remplacer par un LM7833 par exemple.

3.3.4. Adaptateur par USB
Si l'on adopte une carte ESP32 on pourra l'alimenter directement par le cordon USB.

4. La réalisation

Si l'on envisage d'utiliser une carte ESP32 on peut d'abord essayer très facilement ce montage sur breadboard, et passer ensuite sur une plaquette à pastilles.

Attention : pas mal de module INA226 sont mal sérigraphiés (SDA et SCL sont inversés).

Si l'on préfère la version PCB, il sera difficile de faire des essais sur breadboard, les cartes adaptatrices, avec leurs doubles rangées de broches, étant inadaptées :

Les modèle dual-in-line (deux rangées de 15 broches) existent mais sont plus difficiles à dénicher :
Par défaut il reste toujours la solution de faire les essais avec une carte ESP32 et de réaliser la solution finale avec un module nu sur PCB.

5. IDE ARDUINO

Il faudra installer la bibliothèque suivante :
Librairie INA226 : https://github.com/jarzebski/Arduino-INA226

Dans l'IDE ARDUINO on devra sélectionner les options suivantes :
  • Outils : type de carte : ESP32 Dev Module
  • Outils : Partition Scheme : Minimal (2MB FLASH)
On peut être amené à choisir une autre carte, WEMOS D1 par exemple, en fonction du modèle acheté.

6. Le code

Pour récupérer le projet voir plus bas : 9. Téléchargements.

Le code de l'ESP32 est situé dans le répertoire arduino qui contient deux fichiers source :
  • un sketch
  • un fichier HTML
Avant de charger le sketch il faudra modifier quelques constantes :
  • ssid : le SSID de la box
  • password : le mot de passe WIFI
  • INA226_I2CADDR : l'adresse I2C de l'INA226 
  • INA226_OHM : la valeur du shunt en ohms
  • INA226_AMP : le courant maximal mesurable
  • INA226_OFFSET :  l'offset de l'INA226
Il se peut que l'adresse I2C de l'INA226 (0x40) ne convienne pas. Pour la déterminer facilement je conseille d'exécuter ce sketch :
https://gist.github.com/tfeldmann/5411375

La valeur du shunt peut être ajustée en modifiant INA226_SHUNT. Lorsque l'on a affaire à un module équipé d'un shunt de 10mΩ la résistance des soudures intervient fortement. Il vaut mieux comparer la valeur mesurée à celle affichée par un multimètre.

Le courant maximal mesurable est dépendant du shunt soudé sur le module :
8A pour un shunt de 10mΩ (marquage R010).
0.8A pour un shunt de 100mΩ (marquage R100).

L'offset de l'INA226 à vide peut être obtenu en effectuant une mesure sans charge (voir plus loin : 8.3. Offset de l'INA226).

Le fichier HTML pourra être chargé à l'aide du menu :
Outils / ESP32 Sketch Data Upload

Le plugin permettant cette opération se trouve ici :
https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/tag/1.0
Les explications :
https://github.com/me-no-dev/arduino-esp32fs-plugin

7. Le HOST

La repository BitBucket contient également un répertoire raspberry :
  • deux scripts PYTHON : index.py et template.py
  • un fichier HTML
  • un fichier favicon

7.1. Les templates

Une petite explication pour ceux qui ne connaissent pas les templates s'impose, bien que ce ne soit pas indispensable à la mise en service du serveur.
Cela peut intéresser certaines personnes pour le développement de leurs propres applications.

Le fichier template.py permet de générer une page WEB à partir d'un fichier HTML template, c'est à dire un fichier contenant des identifiants (voir le fichier HTML) :
  • $XDATA : les données de l'axe des X
  • $CURRENT_DATA : les données de mesures de courant
  • $VOLTAGE_DATA : les données de mesures de tension
  • $GPIO_SERIES : les données de mesures de GPIOs
  • $ADC_SERIES : les données de mesures de ADC
Lorsque le serveur rencontre un mot clé commençant par $ il remplace cet identifiant par les données correspondantes. En d'autres termes il s'agit de générer des listes JavaScript :
Dans le code si le serveur trouve ceci :

        {
          name: 'Voltage',
          type: 'spline',
          data: [$VOLTAGE_DATA],
          yAxis: 0,
          tooltip: {
              valueSuffix: 'V'
          }
        }


Après interprétation on obtiendra ceci :

        {
          name: 'Voltage',
          type: 'spline',
          data: [4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08, 4.08],
          yAxis: 0,
          tooltip: {
              valueSuffix: 'V'
          }
        }


8. Installation et utilisation

8.1. L'ESP32

8.1.1. Chargement et configuration
Une carte ESP32 se charge via son connecteur USB.
Le module ESP32 nu nécessite d'être chargé via un convertisseur USB / série.
Pour le branchement du convertisseur USB / série voir plus bas :  11. Photos

Comme sur une carte ESP32 le sketch est chargé en utilisant la séquence habituelle :
  • appuyer sur le bouton BOOT
  • appuyer brièvement sur le bouton EN
  • relâcher le bouton BOOT
  • charger le sketch
Après avoir chargé le sketch dans l'ESP32 celui-ci affiche sur la console l'adresse IP par laquelle on va pouvoir communiquer avec lui :

Connected to ROUTER_XXXX
IP address: 192.168.1.18
MAC address: 3C:71:BF:47:A5:B0
MDNS responder started
HTTP server started 


Grâce à l'adresse MAC il est possible de fixer une adresse IP statique par configuration de la box internet. On sera ainsi certain de conserver toujours la même adresse. Sur une LiveBox : voir "Configuration Avancée".

8.1.2. La page de configuration
Dans le navigateur entrons l'URL : http://192.168.1.18/index.html en remplaçant 192.168.1.18 par la vraie adresse IP de l'ESP32 :

Cette page permet de sélectionner les valeurs à mesurer :
  • Power Monitor (INA226)
  • GPIOs
  • canaux ADC
A noter : lorsqu'une GPIO est cochée, le sketch de l'ESP32 configurera cette entrée en entrée avec PULLUP :

      pinMode(gpioNumber, INPUT_PULLUP);

Attention : si l'on a des sorties de microcontrôleur 5V à surveiller il est préférable de passer par des ponts diviseurs afin de ne pas risquer de griller les entrées de l'ESP32.

8.1.3. Le montage de test
Voici le montage de test utilisé :

Pour cet exemple j'ai raccordé une alimentation 5V sur la GPIO35 à travers un pont diviseur de tension 10KΩ + 10KΩ.

J'ai également relié GPIO26 à la broche 3.3V et GPIO27 à la broche GND.
On peut également connecter deux boutons poussoirs entre les GPIOs et GND pour faire varier les valeurs mesurées.

Les entrées de l'INA226 sont raccordées comme suit :
  • VBUS et V+: le pôle + d'une batterie 3.7V
  • V- : une résistance de charge entre V- et GND
  • GND : le pôle - de la batterie
R3 et RV1 forment une résistance de charge ajustable pour la batterie et il sera possible de jouer avec le potentiomètre pour faire varier le courant.

Le shunt de l'INA226, situé sur le module entre V+ et V-, est placé côté VBUS (high-side) sur le schéma ci-dessus. L'INA226 offre la possibilité de placer son shunt côté GND (low-side) :
Cela revient strictement au même.
8.1.4. Le formulaire
Dans le formulaire affiché par l'ESP32 nous allons devoir entrer certaines informations :
  • l'adresse IP du HOST et le port d'écoute (8080 dans mon cas)
  • la période de mesure
  • l'unité de temps (millisecondes, secondes, minutes)
  • Power Monitor : indique si l'on désire utiliser l'INA226
  • GPIOS :
    • cocher les GPIOs à surveiller
    • on peut entrer un libellé (ALIAS)
  • ADC
    • cocher les GPIOs à surveiller
    • on peut entrer un libellé (ALIAS)
    • renseigner le rapport de division éventuel
Les alias permettront de mieux se repérer dans les graphes produits. Plutôt que d'afficher GPIO26 et GPIO27, les libellés utilisés seront LED et RELAY, ce qui est plus parlant.

Le rapport de division est le coefficient multiplicateur à utiliser si l'on mesure une tension à travers un pont diviseur. Dans mon cas je mesure une tension de 5V à travers un pont diviseur 10KΩ + 10KΩ, donc un rapport de division de 2.
Si l'on n'utilise pas de pont diviseur on peut laisser ce champ vide.

Malgré qu'il soit alimenté en 3.3V l'INA226 n'a pas besoin de pont diviseur sur ses entrées. Il est capable de mesurer des tensions jusqu'à 36V.

8.1.5. Lancement des mesures
Après validation par le bouton OK le serveur est démarré :

On peut observer le déclenchement des mesures sur le moniteur série :

INA226: 4.100V, 3.400mA
ADC: 2953
DIVIDER: 2.00
GET /log?VOLTAGE=4.1&CURRENT=3.40&GPIO_RELAY=1&GPIO_LED=0&ADC_VCC=5.06& HTTP/1.1
Host: 192.168.1.121
Connection: close  


192.168.1.121:8080: unable to connect to host

Tant que le host n'est pas démarré, l'ESP32 ne parviendra pas à se connecter à lui. Le message "unable to connect to host" sera affiché, mais ce n'est pas important, on le lancera plus tard.

Voilà c'est tout pour l'ESP32.

8.2. Le HOST

8.2.1. Installation et configuration
On pourra installer les différents fichiers du répertoire raspberry dans un répertoire quelconque du PC ou de la RASPBERRY PI.

Le script PYTHON utilise le framework CHERRYPY. Il sera donc nécessaire d'installer ce module.

Sous DEBIAN ou UBUNTU c'est facile :
$ sudo aptitude install python-cherrypy

Sous Windows il faut télécharger l'archive et l'installer manuellement.

Le script PYTHON est configurable. Il est facile par exemple de changer le N° de port d'écoute dans le fichier web-power-monitor.conf :

[global]
server.socket_host = "0.0.0.0"
server.socket_port = 8080
server.thread_pool = 10


L'adresse IP 0.0.0.0 permet l'accès depuis n'importe quel poste du réseau.
Un serveur APACHE occupe déjà le port 80 sur mon PC. J'ai donc choisi 8080.

8.2.3. Lancement
Ensuite il suffit de lancer le script :

python ./index.py

8.2.4. Visualisation
Il ne reste plus qu'à lancer un navigateur pour visualiser les résultats. Si le script python tourne sur le même PC l'URL est 127.0.0.1:80 ou 127.0.0.1:8080 suivant le port choisi.

Au début - tant qu'il n'aura pas reçu de données de l'ESP32 - le navigateur va afficher une page pratiquement vide. Seul un titre et le bouton RESET apparaissent.
Lorsque l'on estime qu'il a reçu suffisamment de données, il suffit de rafraîchir la page :

Pour cet essai la période de mesure est de 2 secondes. L'axe des X représente le temps en secondes.

Si le Power Monitor n'a pas été sélectionné dans l'interface de l'ESP32, le premier graphe est absent.
Il en est de même pour les graphes GPIOs et ADC.

Cette image est incomplète. Un bouton d'export vers un fichier CSV est ajouté dans la version définitive :
Le nom du fichier, s'il n'est pas renseigné est "log.csv".
Lorsque l'on clique sur le bouton export, une boîte de dialogue apparaît :


On peut ainsi directement visualiser les données avec un tableur ou enregistrer le fichier.

En plaçant la souris sur un graphe on obtient les informations conçernant un point du graphe :

Il est possible également de zoomer en sélectionnant une zone :


En relâchant le bouton de la souris on obtient ceci :


Pour revenir à l'affichage précédent, utiliser le bouton "Reset Zoom".

Ces diverses possibilités sont offertes par la librairie HighCharts.

8.3. Offset de l'INA226

La mesure de courant de l'INA226 présente un offset faible de quelques 100µA.
On peut mesurer cet offset en effectuant une mesure sans charge. Il suffit ensuite de modifier la valeur de INA226_OFFSET dans le sketch, puis de le recharger dans l'ESP32.
On obtiendra ainsi une mesure plus exacte.

8.4. Vitesse de l'INA226

Comme dit plus haut :
Afin de minimiser le bruit le temps de conversion choisi est de 8.144ms.
Une moyenne sur 16 échantillons est effectuée.
Cela veut dire clairement que le temps de mesure est assez important, environ 260ms.

Si l'on désire diminuer le temps de mesure il est possible de modifier cette ligne de configuration dans le sketch ESP32 :

ina226.configure(INA226_AVERAGES_16, INA226_BUS_CONV_TIME_8244US, INA226_SHUNT_CONV_TIME_8244US, INA226_MODE_SHUNT_BUS_CONT);

Si l'on désire un temps de mesure inférieur à 5ms on pourra configurer l'INA226 comme ceci :

ina226.configure(INA226_AVERAGES_4, INA226_BUS_CONV_TIME_588US, INA226_SHUNT_CONV_TIME_588US, INA226_MODE_SHUNT_BUS_CONT);

Cela se fera cependant au détriment du bruit.

La datasheet de l'INA226 sera utile, en particulier le paragraphe :
7.4.1 Averaging and Conversion Time Considerations.

9. Téléchargements

Pour télécharger le projet :
https://bitbucket.org/henri_bachetti/web-power-monitor.git

Cette page vous donne toutes les informations nécessaires :
https://riton-duino.blogspot.com/p/migration-sous-bitbucket.html

10. Essais

Voici un petit essai réalisé avec une batterie 28650 et un chargeur TP4056 suivi d'un convertisseur step-up :
Voici les branchements :


L'INA226 mesure donc la tension de la batterie et le courant circulant entre la broche B- du TP4056 et la borne -  de la batterie.
La broche GPIO35 mesure la tension de sortie du convertisseur 5V à travers un pont diviseur.

Voici un zoom de la première partie :


Première partie de la manipulation (de 0 à 90 secondes) :
  • le port USB du TP4056 n'est pas branché
  • la sortie du convertisseur est chargée avec une résistance de 10Ω
Le convertisseur débite donc 500mA.
La tension batterie est de 3.7V et elle débite 780mA, ce qui est normal étant donné quelle doit fournir :
5V x 0.5A = 2.5W
2.5W / 3.7V = 0.675A
C'est en dessous de 780mA, mais le rendement du convertisseur n'est pas de 100%. Il a donc un rendement de 86%.

Deuxième partie de la manipulation (de 100 à 160 secondes) :
  • la sortie du convertisseur n'est plus chargée
Le convertisseur ne débite plus que 250µA dans le pont diviseur.
La tension batterie remonte à 3.97V puis à 4.01V. Elle ne débite que 600µA dans le convertisseur.

Troisième partie de la manipulation (à partir de 170 secondes) :
  • le port USB du TP4056 est branché
  • la sortie du convertisseur reste non chargée
Le convertisseur débite toujours 250µA dans le pont diviseur.
Au début de la charge la tension de la batterie est à 4.12V et le courant est de 255mA.
La tension batterie remonte lentement, et le courant diminue progressivement.
A la fin de la charge la tension de la batterie est à 4.2V et le courant est de 98mA.

Lorsque le TP4056 coupe la charge (à 1530 secondes) la tension de la batterie chute à 4.15V et celle-ci débite 500µA. La tension chute à 4.12V et se stabilise.

Quelques premières constatations à propos de cette manipulation :

Après avoir rafraîchi la page au bout d'une heure, la tension de la batterie est de 4.11V. Il va falloir attendre très longtemps pour que le TP4056 démarre une nouvelle charge de la batterie.
Le but de la manipulation est justement de déterminer la valeur de tension pour laquelle la charge va être déclenchée, ainsi que le temps que cela va prendre.

On peut remarquer que lorsque le convertisseur est chargé sa tension de sortie est au dessus de 5.5V, contre 5.3V sans charge.

Le courant de repos du convertisseur est faible ce qui confirme ce que j'ai déjà constaté ici au paragraphe 1.10 :
https://riton-duino.blogspot.com/2019/11/convertisseurs-stepup-stepdown.html
Ce courant est encore plus faible avec un pont diviseur 100KΩ + 100KΩ : 200µA.

Voici donc le genre de manipulation que l'on peut effectuer en très peu de temps avec cet outil de mesure. C'est extrêmement pratique et précis.

11. Photos

Voici une photo de la carte :


Ce prototype est réalisé sur un PCB simple face, ce qui est assez problématique pour les soudures de l'ESP32. Pour ce faire j'ai utilisé des broches fines traversantes soudées sur les pastilles sous le PCB et sur l'ESP32. L'ESP32 est rehaussé à l'aide d'une petite plaquette d’époxy :


C'est assez peu recommandable je l'avoue. Mais cela fonctionne.
Que l'on se rassure, dans le dossier KICAD, le routage est bien fait en double face avec trous métallisés.


Quelques petites étiquettes pour s'y retrouver dans les futurs branchements et les boutons.


Le bornier de raccordement INA226 est à gauche. Les branchements sont décrits aux paragraphes suivants :
  • 8.1.3. Le montage de test
  • 10. Essais.
Le connecteur de chargement de l'ESP32 est à droite. Les branchement sont les suivants (de gauche à droite) :
  • TX de l'ESP32 -> RX du convertisseur USB / série
  • RX de l'ESP32 -> TX du convertisseur USB / série
  • GND 
Bien entendu il faut un convertisseur 3.3V :

Câble FTDI TTL-232R-3V3


Ou un modèle supportant 5V et 3.3V :
FT232RL 5V / 3.3V
CH340 5V / 3.3V

12. Conclusion

Il n'y a plus qu'à installer le serveur sur la RASPBERRY PI où il tournera en permanence.
La première application envisagée est la surveillance d'une carte UPS DFRobot DFR0494, d'une UPS RPI PowerPack et d'autres solutions UPS, afin de vérifier leur comportement, en particulier le courant débité ou reçu par la batterie lorsque le secteur est présent.

Trois cas peuvent se présenter :
  • la batterie subit une recharge permanente (peu recommandé)
  • la batterie débite un courant plutôt faible et elle est rechargée périodiquement (c'est mieux)
  • la batterie ne débite aucun courant - ou celui-ci est extrêmement faible - et elle est rechargée très rarement (c'est encore mieux)
Voilà qui promet des séances de mesures longues et pleines d'enseignement.


Cordialement
Henri

13. Mises à jour

25/01/2020 : petite correction de schéma : le connecteur d'alimentation P5
                     était inversé (pôle - au milieu du JACK)
26/01/2020 : 10. Essais