lundi 10 février 2020

Les convertisseurs USB / série



Les convertisseurs USB / série


Lorsque l'on travaille avec des cartes ARDUINO PRO MINI ou des modules ESP8266 ou ESP32 dépourvus de convertisseur USB, on utilise généralement un convertisseur externe pour charger son application.

Tous les convertisseurs peuvent convenir, à partir du moment où l'on respecte bien la tension d'alimentation et la tension maximale des signaux que la carte peut supporter.

Pendant la phase de maquettage, il peut être pratique d'alimenter le montage complet à partir du convertisseur. Ceux-ci sont en général capables de fournir le courant nécessaire pour une carte PRO MINI et quelques modules peu consommateurs.

S'il s'agit d'une PRO MINI 16MHz, un convertisseur 5V est nécessaire. Une carte 16MHz ne tournerait pas sous 3.3V.

S'il s'agit d'une PRO MINI 8MHz 3.3V, on peut le faire avec un convertisseur 5V ou 3.3V.
Si des modules ne supportant pas 5V (NRF24L01 par exemple) sont connectés à l'ARDUINO, un convertisseur 3.3V est obligatoire.

Un ESP8266 ou ESP32 devra obligatoirement être chargé avec un convertisseur 3.3V, mais une alimentation délivrant au moins 500mA sera nécessaire.

Il faut bien distinguer tension d'alimentation et tension des signaux. En effet certains convertisseurs fournissant des signaux 3.3V ne fournissent pas forcément une tension d'alimentation de 3.3V (câble TTL-232R-3V3 par exemple).

Dans tous les cas, le câblage est le même :
  • GND du convertisseur sur GND de la carte
  • TX du convertisseur sur RX de la carte
  • RX du convertisseur sur TX de la carte
  • RTS ou DTR sur le DTR ou GRN de la carte (PRO MINI).
Dans certains cas la puissance fournie sur la broche 3.3V du convertisseur peut ne pas être suffisante (ESP8266 ou ESP32 par exemple). Il faudra donc alimenter le montage à l'aide d'une alimentation adaptée.

Nous allons examiner quelques modèles de convertisseurs.

Ensuite quelques paragraphes décrivent en détail certaines différences en fonction de l'OS utilisé (Linux, Windows).

1. Les convertisseurs 

Il faut prendre garde lors de l'achat de modules à la présence ou l'absence de broches telles que DTR ou RTS qui permettent le chargement automatique d'une carte ARDUINO PRO MINI. En effet bien que les chips proposent un certain nombre de lignes de contrôle, les modules convertisseurs ne les rendent pas forcément disponibles sur les connecteurs du module.

Sur une carte ARDUINO PRO MINI, la ligne DTR ou RTS du convertisseur doit être connectée sur la broche DTR ou GRN de la carte. En fait comme on le voit sur le schéma cette broche est reliée au RESET du microcontrôleur.
Si l'on utilise un convertisseur sans ligne DTR ni RTS, on peut appuyer sur le bouton RESET juste avant que le chargement ne commence.

Si l'on doit charger un ESP32 avec deux boutons EN et BOOT, RX et TX suffisent.

1.1. Le CH340 ou CH341

Ce chip est très commun. Il équipe souvent les cartes ARDUINO chinoises UNO, NANO, MEGA. Il a les caractéristiques suivantes :
  • interface : USB2
  • vitesse (baud) : 50bps à 2Mbps
  • tension 5V ou 3.3V
  • broche de sortie 3.3V
  • EEPROM interne (CH340B uniquement)
  • EEPROM externe (CH341)
On peut voir que seul le CH340B possède une EEPROM, bien pratique pour le stockage d'informations, le N° de série principalement.
Les autres modèles n'en possèdent pas, cela risque d'être handicapant. Nous verrons pourquoi au paragraphe 3. L'attribution des ports.

Le CH340 est disponibles sous forme de module :
CH340 5V / 3.3V
Ce modèle fournit une alimentation et des signaux 5V ou 3.3V en fonction de la position d'un cavalier.

En général ces modules ne proposent que les lignes RX et TX. Les lignes DTR ou RTS, bien pratiques pour charger une PRO MINI en automatique, sans appuyer sur le bouton RESET.

La plupart des modules sont équipé d'un CH340G. Je ne connais pas de module équipé d'un CH340B.

1.2. Le FT232R

Ce chip de la société FTDI a les caractéristiques suivantes :
  • USB2
  • vitesse (baud) : 300bps à 3Mbps
  • tension 5V ou 3.3V
  • broche de sortie 3.3V
  • EEPROM interne
  • tampon de réception et émission : 128 bytes et 256 bytes

La présence de deux tampons mémoire le rend plus performant dans les vitesses de transmission hautes.

Les modules sont très nombreux :



FT232R 5V / 3.3V


FT232R 5V / 3.3V

Ces deux modèle fournissent une alimentation et des signaux 5V ou 3.3V en fonction de la position d'un cavalier.
D'autres modèles proposent un interrupteur à bascule.

Je trouve le modèle rouge assez peu fiable. Les chargements échouent assez fréquemment.

En général ces modules proposent au moins une ligne DTR ou RTS.

Il est intéressant de fabriquer un câble directement enfichable sur la carte cible. Le câblage est dépendant du modèle de convertisseur utilisé :

Convertisseur avec connecteur enfichable sur ARDUINO PRO MINI


Câble FTDI TTL-232R
Ce câble existe aussi en version 3.3V : TTL-232R-3V3.

ATTENTION : la tension fournie par le fil VCC rouge est de 5V !
C'est indiqué dans la datasheet.

1.3. Le FT2232H et FT4232H

Pour les applications gourmandes FTDI propose également des convertisseurs à 2 et 4 ports.

Ils sont également disponibles sous forme de modules :
Les datasheets :
https://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf
https://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT4232H_Mini_Module.pdf

Une application JTAG :
http://www.avi-plus.com/images/fbfiles/files/HOWTO_JTAG_Interface_STMCLT_Clone_REV2.pdf

Une application personnelle (HUB 4 ports série) :
https://riton-duino.blogspot.com/2020/02/un-hub-4-ports-serie.html

On trouve également des modules chinois sur AliExpress :

FT4232 4 ports


FT4232 4 ports

Il a des possibilités intéressantes :
  • commutateur d'alimentation (USB ou JACK)
  • commutateur 5V / 3.3V sur RX / TX
  • 4 ports RX / TX / GND / VCC sur connecteurs JST
Le même en version FT2232 :
FT2232 2 ports

1.4. Le PL2303

Ce chip de la société PROLIFIC a les caractéristiques suivantes :
  • USB2
  • vitesse (baud) : 75bps à 12Mbps
  • tension 5V ou 3.3V
  • broche de sortie 3.3V
  • EEPROM interne
  • tampon de réception et émission : 128 bytes et 256 bytes
La présence de deux tampons mémoire le rend plus performant dans les vitesses de transmission hautes.

Les modules sont aussi très nombreux :
PL2303 5V / 3.3V
Ce modèle fournit une alimentation et des signaux 5V ou 3.3V en fonction de la position d'un cavalier.

Comme les modules CH340, en général ces modules ne proposent que les lignes RX et TX, pas de DTR ou RTS, bien pratiques pour charger une PRO MINI en automatique, sans appuyer sur le bouton RESET.

1.5. Le CP2102 ou CP2104

Ce chip de la société Silicon Labs a les caractéristiques suivantes :
  • USB2
  • vitesse (baud) : jusqu'à 921600Mbps
  • tension 5V ou 3.3V
  • broche de sortie 3.3V
  • EEPROM interne
  • tampon de réception et émission : 576 bytes et 640 bytes
La présence de deux tampons mémoire le rend plus performant dans les vitesses de transmission hautes.

Les modules sont aussi très nombreux :
CP2102 5V / 3.3V
Ce modèle fournit une alimentation et des signaux 5V ou 3.3V en fonction de la position d'un cavalier.

Apparemment si les FT232R avec commutateur 5V / 3.3V sont très répandus, il n'en va pas de même pour le CP2102 ou CP2104.
La majorité propose deux broches 5V et 3.3V mais qu'en est-il de la tension des signaux ? Cela demande à être approfondi.

En général ces modules proposent au moins une ligne DTR ou RTS.

2. Les drivers

Sous Windows il faudra les installer :
CH340 : http://www.wch.cn/download/CH341SER_EXE.html
FT232R : https://www.ftdichip.com/Drivers/VCP.htm
PL2303 : http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&pcid=41
CP2102 & CP2104 : https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers

Attention : il semblerait que certaines versions de PL2303 (PL-2303HXA et PL-2303X) ne soient pas compatibles avec Windows 8 et 10.
Voir la page de téléchargement.

Sous Linux il n'y a rien à faire. Les drivers font partie de la distribution et sont directement utilisables.

3. L'attribution des ports

Lorsque l'on branche un convertisseur ou une carte UNO ou NANO sur un PC, le comportement diffère en fonction de l'OS.

3.1. Windows

Windows attribue un port COMX en fonction du driver et surtout du chip convertisseur utilisé.

Avec un FT232R ou un PL2303 le port de COM attribué sera différent pour chaque convertisseur, et en rebranchant un convertisseur précédemment utilisé celui-ci retrouvera le même port de COM que lors de sa précédente utilisation.

Ceci explique que sur certains postes de développeurs on peut avoir sous Windows 50 ports de COM déjà attribués.

Avec un CH340 Windows attribuera le premier port de COM libre lors du premier branchement. Ensuite ce port sera réutilisé, s'il est libre, pour tous les convertisseurs CH340.
Il est donc impossible de distinguer un CH340 d'un autre CH340 par son port de COM.

Ceci explique que si l'on branche une UNO sur un PC, qu'on la débranche et qu'on en branche une autre, elle se voit attribuer le même port.

Oui mais pourquoi ? tout simplement parce que le CH340 ne possède pas de mémoire EEPROM pour y stocker un numéro de série.

Un FT232R ou un PL2303 possède une EEPROM et un numéro de série y est inscrit à la fabrication.
Celui-ci est même modifiable par l'utilisateur. Chez FTDI par exemple :
FT_PROG EEPROM Programming Utility

Il est possible sous Windows de changer un numéro de port à l'aide du Gestionnaire de Périphériques :
https://plugable.com/2011/07/04/how-to-change-the-com-port-for-a-usb-serial-adapter-on-windows-7/

Encore une fois cette modification, si le convertisseur est un CH340, s'appliquera à tous les CH340.

3.2. Linux

Linux attribue le premier port TTY libre en partant de ttyUSB0 (ttyACM0 pour certaines cartes, MEGA officielle par exemple).

Si on débranche un convertisseur pour en rebrancher un autre, le même port sera attribué de nouveau.
Si on a laissé un logiciel terminal connecté au port TTY précédent, le port suivant sera attribué.

On pourrait être tenté de dire : Linux c'est le bazar !
Non, la gestion est plus simple et plus fiable.

Sous Linux il est possible également de modifier le nom d'un port TTY USB et de le rendre persistant. Il sera nécessaire de passer par udev :

Pour mon exemple concret sur RASPBERRY PI j'ai choisi un port USB sur lequel est branchée une carte PRO MINI avec un émetteur / récepteur 433MHz. Le convertisseur est un FT232R.
Normalement, au boot, le device ttyUSB2 lui est attibué. Je désire ajouter un device ttyUSB433, car je sais que DOMOTICS ne me proposera que des devices commençant par ttyUSB, ttyACM ou ttyAMA.

La commande lsusb permet de lister les ports USB. Ici je recherche un FT232 :

$ lsusb | grep FT232
Bus 001 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC


On voit ici l'identifiant constructeur (0403) et identifiant produit (6001).

Ensuite il faut connaître le port TTY l'aide de la commande dmesg. Si le convertisseur vient d'être branché on verra plus facilement ses informations.
Sinon il faudra les rechercher le mot FT232 dans la console avec CTRL-SHIFT-F :

$ dmesg
...
[    3.562108] ftdi_sio 1-1.2:1.0: FTDI USB Serial Device converter detected
[    3.562271] usb 1-1.2: Detected FT232RL
[    3.563289] usb 1-1.2: FTDI USB Serial Device converter now attached to ttyUSB2


Si plusieurs FT232R sont présents on pourra lever le doute en débranchant  et rebranchant celui que l'on désire modifier. Le informations se retrouveront en fin de liste.

On peut ensuite utiliser la commande udevadm pour avoir plus d'informations :

$  udevadm info -n /dev/ttyUSB2
P: /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/ttyUSB2/tty/ttyUSB2
N: ttyUSB2
S: serial/by-id/usb-FTDI_FT232R_USB_UART_A104JP07-if00-port0
S: serial/by-path/platform-3f980000.usb-usb-0:1.2:1.0-port0
S: ttyUSB433
E: DEVLINKS=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A104JP07-if00-port0 /dev/serial/by-path/platform-3f980000.usb-usb-0:1.2:1.0-port0 /dev/ttyUSB433
E: DEVNAME=/dev/ttyUSB2
E: DEVPATH=/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2:1.0/ttyUSB2/tty/ttyUSB2
E: ID_BUS=usb
E: ID_MODEL=FT232R_USB_UART
E: ID_MODEL_ENC=FT232R\x20USB\x20UART
E: ID_MODEL_FROM_DATABASE=FT232 USB-Serial (UART) IC
E: ID_MODEL_ID=6001
E: ID_PATH=platform-3f980000.usb-usb-0:1.2:1.0
E: ID_PATH_TAG=platform-3f980000_usb-usb-0_1_2_1_0
E: ID_REVISION=0600
E: ID_SERIAL=FTDI_FT232R_USB_UART_A104JP07
E: ID_SERIAL_SHORT=A104JP07
E: ID_TYPE=generic
E: ID_USB_DRIVER=ftdi_sio
E: ID_USB_INTERFACES=:ffffff:
E: ID_USB_INTERFACE_NUM=00
E: ID_VENDOR=FTDI
E: ID_VENDOR_ENC=FTDI
E: ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd
E: ID_VENDOR_ID=0403
E: MAJOR=188
E: MINOR=2
E: SUBSYSTEM=tty
E: TAGS=:systemd:
E: USEC_INITIALIZED=49791


FT232R, 0403, 6001 : c'est bien le bon convertisseur.

Il faut relever :
  • l'identifiant constructeur : 0403
  • l'identifiant produit : 6001
  • le N° de série : AL008YL2
  • le port TTY : ttyUSB1
Ensuite il suffit de créer un fichier nommé 99-usb-serial.rules par exemple dans le répertoire /etc/udev/rules.d. Ce fichier doit être créé avec les droits administrateur (sudo).

/etc/udev/rules.d/99-usb-serial.rules : 
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A104JP07", SYMLINK+="ttyUSB433".

Il faut ensuite redémarrer udev :
On trouve beaucoup de commandes du genre :

$ sudo /etc/init.d/udev restart
$ udevadm control --reload-rules && udevadm trigger

Mais ces commandes n'ont pas l'air d'avoir le moindre effet.
Donc je redémarre :

$ sudo reboot

A chaque fois que le kernel verra un device TTY USB ayant ces identifiants et ce numéro de série il l'appellera ttyFT232-1.
Bien entendu il est possible d'ajouter autant de lignes que nécessaire pour différents convertisseurs.

Au redémarrage nous voyons note nouveau port TTY :

$ ls /dev/ttyU*
/dev/ttyUSB0  /dev/ttyUSB1  /dev/ttyUSB2  /dev/ttyUSB433


On peut remarquer que le ttyUSB2 est toujours présent. ttyUSB433 est en fait un lien symbolique sur ttyUSB2 (un alias).

Ici aussi cette modification, si le convertisseur est un CH340, s'appliquera à tous les CH340 car on ne peut pas préciser de N° de série. Dommage.

L'avantage avec Linux est que l'on peut nommer le port TTY à sa convenance. Dans l'exemple je l'ai appelé ttyUSB433.

Ensuite comment distinguer physiquement plusieurs FT232R entre eux ? avec une étiquette, portant le même nom, collée sur le module par exemple.

4. L'attribution des ports au boot

Au démarrage d'une machine, si plusieurs convertisseurs ou plusieurs cartes ARDUINO sont déjà branchés, le N° des ports attribués vont dépendre bien sûr de l'OS et du type de convertisseur.

Cela concerne principalement les machines utilisées comme serveur domotique, avec plusieurs cartes ARDUINO branchées en permanence :
  • passerelle RFLINK
  • passerelle NRF24L01 ou RFM69
  • etc.
Ce sont souvent des machines à base de RASPBERRY PI, sous Linux, mais pas seulement. Windows 10 tourne aussi sur cette plateforme (RASPBERRY PI 4).

4.1. Windows

Sous Windows c'est facile : tous les convertisseurs retrouveront le petit nom qu'ils portaient précédemment.

Si plusieurs CH340 sont présents, il y aura incertitude, mais en général l'informatique est déterministe et normalement les N° de ports COM seront les même que précédemment, sauf peut être si l'on a interverti les ports USB de deux cartes, ou si la chance n'est pas de notre côté.

L'idéal est donc de n'avoir au maximum qu'un seul CH340 branché au démarrage sur un serveur si l'on veut pouvoir retrouver facilement leurs ports respectifs.
Les autres convertisseurs FT232R ou PL2303 se verront toujours attribuer le même port de COM.

4.2. Linux

Là encore les ports TTY attribués à chaque convertisseur a de fortes chances de rester le même, mais ce n'est pas garanti.
La bonne méthode est d'attribuer soi-même avec udev un petit nom reconnaissable comme vu plus haut (3.2. Linux).
Ici aussi si plusieurs CH340 sont présents, il y aura incertitude.

4.3. Exemple

Sur ma RAPBERRY PI qui héberge un serveur DOMOTICZ il y a quatre cartes ARDUINO branchées en USB :
  • une passerelle RFLINK (ARDUINO MEGA officielle)
  • une passerelle MYSENSORS 2.4GHz (ARDUINO NANO + CH340)
  • une passerelle MYSENSORS 433MHz (ARDUINO PRO MINI + FT232R)
  • un récepteur infrarouge (ARDUINO NANO + CH340)
Si je me contente de laisser telle quelle cette configuration il y aura incertitude sur les deux NANOs et la PRO MINI. En effet les trois ports seront nommés ttyUSB0, ttyUSB1 et ttyUSB2, un peu au hasard.

La MEGA porte le nom /dev/ttyACM0, car c'est une officielle. Si l'on avait affaire à une carte chinoise équipée d'un CH340 il y aurait une incertitude de plus.

Par chance la PRO MINI utilise un FT232R. On peut donc renommer son port série. Il a été renommé ttyUSB-433 à l'aide d'une règle udev.

En général cela se passe bien et les ports sont attribués comme suit :
  • récepteur infrarouge : /dev/ttyUSB0
  • passerelle RFLINK : /dev/ttyACM0
  • passerelle MYSENSORS 2.4GHz : /dev/ttyUSB1
  • passerelle MYSENSORS 433MHz : /dev/ttyUSB433
Il reste donc une incertitude entre ttyUSB0 et ttyUSB1 (deux NANOs CH340).

Comme je ne peux rien faire pour résoudre ce problème, à chaque redémarrage (ce n'est pas fréquent) si les ports des deux NANOS sont inversés, je débranche les deux, et je rebranche la carte "récepteur infrarouge" en premier, et la carte "passerelle MYSENSORS 2.4GHz" en second. Tout rentre dans l'ordre.
L'idéal serait de remplacer les deux NANOs par des PRO MINI et un FT232R dont le port série porterait un nom parlant : ttyUSB24 (pour 2.4GHz) ou ttyUSB38 (pour infrarouge 38 KHz) par exemple.

J'ai récemment développé un HUB 4 ports série :
https://riton-duino.blogspot.com/2020/02/un-hub-4-ports-serie.html
Bâti autour d'un FT4232H (quadruple FT232R), celui-ci me permettra de résoudre tous ces problèmes plus facilement, et accessoirement de libérer au moins deux ports USB.

5. Le bitbang

Qu'est ce que le bitbang ? c'est la possibilité qu'offrent certains convertisseurs de contrôler leurs broches par logiciel.
On peut ainsi les transformer en extension d'I/O pour PC, moyennant l'utilisation d'un driver approprié ou non.

FTDI propose D2XX :
https://www.ftdichip.com/Drivers/D2XX.htm
FTDI propose également libftdi et pylibftdi :
https://github.com/lipro/libftdi
https://pypi.org/project/pyftdi/
Une documentation : https://www.ftdichip.com/Support/Documents/AppNotes/AN_373 Bit-Bang Modes for the FT-X Series.pdf

Un exemple ici avec pyftdi :
https://riton-duino.blogspot.com/2020/02/un-hub-4-ports-serie.html#python 

Chez Silicon Labs : https://www.silabs.com/community/interface/knowledge-base.entry.html/2018/07/25/how_to_control_gpios-Wot7

Il est facile ensuite de contrôler les broches du convertisseur en PYTHON par exemple en utilisant la librairie libusb et le module pyusb.

5.1. PYTHON

Amusons-nous à piloter un FT4232H avec un script PYTHON.
Bien entendu on peut faire la même chose avec des modules FT232R ou FT2232H, et je l'ai d'ailleurs fait avec des modules chinois.

Pour cela il nous faut au préalable installer la librairie pylibftdi :

pip install pylibftdi

Ce script bitbang.py fait clignoter une LED (en série avec un résistance de 470Ω) branchée sur le port AD0 (TX1) d'un FT4232H ou la broche TX d'un FT232R :

import time
from pylibftdi import Driver
from pylibftdi import BitBangDevice

def get_ftdi_device_list():
    """
    return a list of lines, each a colon-separated
    vendor:product:serial summary of detected devices
    """
    dev_list = []
    for device in Driver().list_devices():
        # list_devices returns bytes rather than strings
        dev_info = map(lambda x: x.decode('latin1'), device)
        # device must always be this triple
        vendor, product, serial = dev_info
        dev_list.append((vendor, product, serial))
    return dev_list

def blink_device(dev):
    """
    blink PORT0 of device
    """
    with BitBangDevice(device_id=dev) as bb:
        bb.direction = 0x01
        print bb.port

        while True:
            bb.port = 0x01
            time.sleep(1)
            bb.port = 0x00
            time.sleep(1)

if __name__ == '__main__':
    cnt = 0
    devices = get_ftdi_device_list()
    for device in devices:
        print "%d %s" % (cnt, device)
        cnt += 1
    dev = int(raw_input("select device: "))
    print dev
    if dev <= cnt:
        print "blink_device", dev
        blink_device(devices[dev][2])


Le script demande d'abord avec quel convertisseur il doit travailler, après avoir affiché ceux qu'il a trouvé :

$ python bitbang.py
0 (u'FTDI', u'FT4232H MiniModule', u'FTWEQGJE')
1 (u'FTDI', u'FT4232H MiniModule', u'FTWEQY84')
select device: 1
blink_device 1


Il trouve deux mini-modules, ce qui est vrai. Je choisis ne N° 1 et après cela la LED branchée sur le port AD0 clignote !

Cette manipulation peut être intéressante à plus d'un titre :

On peut par exemple écrire sur les entrées et consulter l'état des sorties d'un ARDUINO, afin de réaliser des tests, au lieu de faire ça avec des boutons et des LEDs.

Sous Linux, il faudra accorder les doits d'écriture sur le device USB :

$ cat /etc/udev/rules.d/98-ftdi.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE:="0666" 
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE:="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE:="0666"

Ce fichier de règles udev est OK pour FT2232H, FT4232H etFT232R (idProduct = 6010, 6011, 6001).

5.2. FT232 et I2C, SPI et autres

Une autre utilisation du bitbanging :
  • créer de toutes pièces un bus I2C ou SPI
  • générer un PWM
  • contrôler un PCF8574, un MCP23017, etc.
https://github.com/adafruit/Adafruit_Python_GPIO/tree/master/Adafruit_GPIO

Comme on le voit les possibilités sont nombreuses.

5.3. FT2232H et ESP32

Voici une dernière utilisation du bitbanging : un module FT2232H peut être utilisé pour réaliser une sonde JTAG pour ESP32. Il existe même un module ESP32-PROG spécialement conçu pour cette utilisation.
A tester ...

6. conclusion

J'espère avoir apporté des réponses à quelques questions que vous vous posiez peut-être à propos des convertisseurs USB.


Cordialement
Henri

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