Augmenter les fonctionnalités de la carte uPesy One
(Mis à jour le 13/06/2023)
Cet article explique comment programmer la nouvelle version de la puce Atmega328P, l’Atmega328PB avec l’écosystème Arduino. En effet, par défaut la carte uPesy One est vue par l’ordinateur comme une puce Atmega328P, pour assurer une compatibilité complète avec l’écosystème Arduino. Cependant pour les plus avancés, cela peut être frustrant d’avoir une carte avec une puce bridée au niveau logiciel. Ce tutoriel tente d’y remédier : vous pourrez programmer en langage Arduino tout en profitant des nouveautés apportées par la nouvelle version de l’Atmega.
MiniCore : un noyau Arduino alternatif amélioré
Actuellement, le core Arduino officiel ne supporte pas encore l’Atmega328PB (Ils le feront sûrement un jour lorsque l’Atmega328P ne sera plus fabriqué). Ainsi pour programmer la nouvelle version, on doit installer des outils supplémentaires, via le gestionnaire de cartes. L’outil de choix est MiniCore développé par MCUdude , qui supporte la quasi-totalité des puces Atmega.
Note
On peut très bien utiliser MiniCore pour une carte Arduino classique.
On peut l’utiliser sur le logiciel Arduino IDE ou sur PlatformIO .
Installer MiniCore sur l’Arduino IDE pour programmer l’Atmega328PB
La procédure d’installation est identique aux cartes ESP32 ou la Pi Pico :
-
On ajoute ce lien dans les préférences pour référencer MiniCore dans les cartes supplémentaires
Voici le lien à ajouter :
https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json
-
On cherche dans le gestionnaire de cartes (Outils → Type de carte → Gestionnaire de cartes ) la ligne MiniCore et on installe la dernière version.
Une fois l’installation automatique terminée, vous pouvez choisir l’Atmega328 dans le nouveau menu MiniCore.
-
Lorsque l’Atemega328P est sélectionné, de nouveaux paramètres apparaissent dans le menu Outils. Vous pouvez copier ces options suivantes :
Avertissement
Ces paramètres ne sont pas directement sauvegardés sur la carte, il faut flasher un nouveau bootloader pour qu’ils soient pris en compte.
C’est au niveau de l’option Variant que l’on choisit le modèle 328PB
.
Flasher un nouveau bootloader pour l’Atmega328PB
Si vous avez une carte uPesy One, le bootloader actuellement dessus, la fait passer pour un Atmega328P classique. Il faut donc le mettre à jour avec celui fournit par MiniCore pour que cela fonctionne.
Note
Vous avez donc besoin d’une carte Arduino supplémentaire ou un programmateur externe ICSP
pour réaliser cette manipulation. Cette carte Arduino supplémentaire doit contenir le programme Arduino : Exemples → 11. ArduinoISP → ArduinoISP . Vous pouvez suivre ce tutoriel pour cette étape .
Lorsque vous avez la carte source avec le programme ArduinoISP
et réalisé le câblage entre les 2 cartes, vous devez changer provisoirement le type de programmateur à “Arduino as ISP”.
Ensuite vous pouvez cliquer sur Graver la séquence d’initialisation pour flasher le nouveau bootloader.
C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\tools\avrdude\7.1-arduino.1/bin/avrdude -CC:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2/avrdude.conf -v -patmega328pb -cstk500v1 -PCOM8 -b19200 -e -Ulock:w:0xff:m -Uefuse:w:0b11110100:m -Uhfuse:w:0b11010110:m -Ulfuse:w:0b11111111:m
avrdude: Version 7.1-arduino.1
Copyright the AVRDUDE authors;
see https://github.com/avrdudes/avrdude/blob/main/AUTHORS
System wide configuration file is C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2\avrdude.conf
Using Port : COM8
Using Programmer : stk500v1
Overriding Baud Rate : 19200
AVR Part : ATmega328PB
Chip Erase delay : 10500 us
PAGEL : PD7
BS2 : PC2
RESET disposition : possible i/o
RETRY pulse : SCK
Serial program mode : yes
Parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Alias 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 1 0 4500 4500 0x00 0x00
hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00
calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00
Programmer Type : STK500
Description : Atmel STK500 version 1.x firmware
Hardware Version: 2
Firmware Version: 1.18
Topcard : Unknown
Vtarget : 0.0 V
Varef : 0.0 V
Oscillator : Off
SCK period : 0.1 us
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9516 (probably m328pb)
avrdude: erasing chip
avrdude: reading input file 0xff for lock
with 1 byte in 1 section within [0, 0]
avrdude: writing 1 byte lock ...
avrdude: 1 byte of lock written
avrdude: verifying lock memory against 0xff
avrdude: 1 byte of lock verified
avrdude: reading input file 0b11110100 for efuse
with 1 byte in 1 section within [0, 0]
avrdude: writing 1 byte efuse ...
avrdude: 1 byte of efuse written
avrdude: verifying efuse memory against 0b11110100
avrdude: 1 byte of efuse verified
avrdude: reading input file 0b11010110 for hfuse
with 1 byte in 1 section within [0, 0]
avrdude: writing 1 byte hfuse ...
avrdude: 1 byte of hfuse written
avrdude: verifying hfuse memory against 0b11010110
avrdude: 1 byte of hfuse verified
avrdude: reading input file 0b11111111 for lfuse
with 1 byte in 1 section within [0, 0]
avrdude: writing 1 byte lfuse ...
avrdude: 1 byte of lfuse written
avrdude: verifying lfuse memory against 0b11111111
avrdude: 1 byte of lfuse verified
avrdude done. Thank you.
C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\tools\avrdude\7.1-arduino.1/bin/avrdude -CC:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2/avrdude.conf -v -patmega328pb -cstk500v1 -PCOM8 -b19200 -Uflash:w:C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2/bootloaders/optiboot_flash/bootloaders/atmega328pb/16000000L/optiboot_flash_atmega328pb_UART0_115200_16000000L_B5.hex:i -Ulock:w:0xcf:m
avrdude: Version 7.1-arduino.1
Copyright the AVRDUDE authors;
see https://github.com/avrdudes/avrdude/blob/main/AUTHORS
System wide configuration file is C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2\avrdude.conf
Using Port : COM8
Using Programmer : stk500v1
Overriding Baud Rate : 19200
AVR Part : ATmega328PB
Chip Erase delay : 10500 us
PAGEL : PD7
BS2 : PC2
RESET disposition : possible i/o
RETRY pulse : SCK
Serial program mode : yes
Parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Alias 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 1 0 4500 4500 0x00 0x00
hfuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
efuse 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
lock 0 0 0 0 no 1 1 0 4500 4500 0x00 0x00
signature 0 0 0 0 no 3 1 0 0 0 0x00 0x00
calibration 0 0 0 0 no 1 1 0 0 0 0x00 0x00
Programmer Type : STK500
Description : Atmel STK500 version 1.x firmware
Hardware Version: 2
Firmware Version: 1.18
Topcard : Unknown
Vtarget : 0.0 V
Varef : 0.0 V
Oscillator : Off
SCK period : 0.1 us
avrdude: AVR device initialized and ready to accept instructions
avrdude: device signature = 0x1e9516 (probably m328pb)
avrdude: Note: flash memory has been specified, an erase cycle will be performed.
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2/bootloaders/optiboot_flash/bootloaders/atmega328pb/16000000L/optiboot_flash_atmega328pb_UART0_115200_16000000L_B5.hex for flash
with 484 bytes in 2 sections within [0x7e00, 0x7fff]
using 4 pages and 28 pad bytes
avrdude: writing 484 bytes flash ...
Writing | ################################################## | 100% 0.08s
avrdude: 484 bytes of flash written
avrdude: verifying flash memory against C:\Users\Alexis\AppData\Local\Arduino15\packages\MiniCore\hardware\avr\2.2.2/bootloaders/optiboot_flash/bootloaders/atmega328pb/16000000L/optiboot_flash_atmega328pb_UART0_115200_16000000L_B5.hex
Reading | ################################################## | 100% 0.00s
avrdude: 484 bytes of flash verified
avrdude: reading input file 0xcf for lock
with 1 byte in 1 section within [0, 0]
avrdude: writing 1 byte lock ...
avrdude: 1 byte of lock written
avrdude: verifying lock memory against 0xcf
avrdude: 1 byte of lock verified
avrdude done. Thank you.
Une fois que le bootloader a été flashé, vous pouvez utiliser l’Atmega328PB exactement comme une carte Arduino UNO.
Avertissement
N’oubliez pas de débrancher les fils de la carte ainsi que de remettre le programmateur “AVRSIP mkII” dans l’onglet Outils .
Lors de vos futurs téléversements via MiniCore, la carte est bien détectée avec la puce Atmega328PB.
Version PlatformIO
https://github.com/MCUdude/MiniCore/blob/master/PlatformIO.md
https://docs.platformio.org/en/latest/boards/atmelavr/ATmega328PB.html#board-atmelavr-atmega328pb
Utiliser les fonctionnalités supplémentaires offertes par la version PB
Les Fonctions Arduino apportées par MiniCore
La version MiniCore ajoute quelques fonctions Arduino pour gérer plus facilement les ports GPIO ainsi que les fonctions de mise en veille :
Les fonctions hardwares additionnels
Utiliser les broches PWM additionnelles
En théorie, il y a 3 broches PWM en plus. Mais puisque 2 sont situés sur les broches 0
et 1
, utilisées pour la communication Serial
avec l’ordinateur, il n’y a en pratique qu’une broche en plus réellement utilisable : la broche 2
.
int pwmPin = 2;
void setup(){
pinMode(pwmPin, OUTPUT);
}
void loop(){
for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){
analogWrite(pwmPin, dutyCycle);
delay(50);
}
}
Utiliser les timers additionnels
Il y a 2 timers 16bits en plus : TC3
et TC4
. Pour les utiliser, vous pouvez prendre des codes existants qui utilisent le Timer TC1
de 16bit de l’Atmega328P et de remplacer tous les 1
par des 3
ou 4
. Par exemple en reprenant, le code de cet article pour le timer TC3
, cela donne :
/*
Fichier : 1HzTimerSansInterruption.ino
Description : Permet de faire clignoter la LED embarquée sur un Atmega328PB, à une fréquence de 1 Hz, via le "timer3"
(c'est à dire la voir s'allumer 500ms, puis s'éteindre 500ms, en répétant cela à l'infini !)
Pour ce faire, on fera démarrer le timer à partir d'une certaine valeur, et on testera s'il y a débordement du timer à chaque bouclage du programme
Auteurs : Jérôme TOMSKI (https://passionelectronique.fr/)
Alexis (uPesy) / Version Atmega328PB Timer TC3
*/
void setup()
{
pinMode (LED_BUILTIN, OUTPUT); // On définit comme étant une "sortie", la pin où est branché la LED sur l'Arduino Uno
// Paramétrage du prescaler
CLKPR = 0b10000000; // Tout d'abord, on active le prescaler (en mettant son "1er" bit à 1, et tous les autres à 0)
CLKPR = 0b00000010; // Puis on inscrit le code "0000 0010", signifiant qu'on désire une division par 4 de la fréquence principale
// Paramétrage du "mode de fonctionnement" du timer3 en "Normal"
// -> c'est à dire que le compteur timer3 va compter jusqu'à son maximum, puis revenir à 0, en levant un drapeau au passage (bit TOV3)
// -> pour activer ce mode, il faut mettre les bits WGM30, WGM31, WGM32, et WGM13 à 0 (nota : les 2 premiers se trouvent dans le registre TCCR3A, et les 2 autres, dans TCCR3B)
// -> pour ce faire, on va se servir de la fonction arduino "bitClear", qui permet de mettre à "0" un bit spécifique, dans un registre donné
bitClear(TCCR3A, WGM30);
bitClear(TCCR3A, WGM31); // Nota : WGM30 et WGM31 se trouvent dans le registre TCCR3A
bitClear(TCCR3B, WGM32);
bitClear(TCCR3B, WGM33); // tandis que WGM32 et WGM13 se trouvent dans le registre TCCR3B
// Puis on paramètre le prédiviseur du timer3, pour qu'il divise la fréquence issue du prescaler par 64
// -> pour faire une division par 64, il faut mettre le bit CS32 à 0, CS31 à 1, et CS30 à 1 également (voir la partie sur les prédiviseurs, pour plus d'infos)
// -> et comme juste avant, on va se servir de la fonction "bitClear" pour mettre un bit à 0, et compléter cela avec la fonction "bitSet", pour mettre un autre bit à 1
bitClear(TCCR3B, CS32);
bitSet(TCCR3B, CS31);
bitSet(TCCR3B, CS30);
// Nota : ici, j'ai tout décomposé pour les "débutants". Mais sachez qu'on aurait pu directement renseigner les registres TCCR3A et TCCR3B, pour aller plus vite
// Pour cela, il aurait suffit d'écrire les 2 lignes suivantes, pour renseigner ces deux registres :
// TCCR3A = 0b00000000; // pour mettre WGM30 et WGM31 à 0
// TCCR3B = 0b00000011; // pour mettre WGM32 et WGM13 à 0, et activer la division par 64
// Enfin, on fait démarrer le timer3 non pas à 0, mais à la valeur 34286 (pour rappel, ce timer 16 bits compte jusqu'à 65535, puis revient à 0, en levant au passage le flag TOV3)
TCNT3 = 34286;
}
void loop()
{
// À chaque tour de boucle, on test si le bit drapeau "TOV3", contenu dans le registre TIFR3, est levé (c'est à dire à "1")
// Ainsi, on saura que le timer3 a compté un nombre précis de fois (depuis nos "34286" initiaux), correspondant à nos 500 ms (qui alternés, font bien nos 1 Hz voulus)
if (bitRead(TIFR3, TOV3) == 1)
{
// Pour commencer, on force la valeur du compteur timer3 à "34286" (correspondant à nos 500 ms de délais), parce qu'il a déjà recommencé à compter depuis 0
TCNT3 = 34286;
// On en profite pour rabaisser le drapeau ayant signalé l'overflow (bit TOV3), sinon il restera toujours à 1, et on se serait plus jamais averti
bitSet(TIFR3,TOV3); // Nota : chose très particulière ici, il faut renvoyer la valeur 1 sur le bit TOV3 pour qu'il passe à 0
// (c'est le constructeur qui impose cette méthode d'acquittement)
// Puis on inverse l'état de la LED (si elle était allumée, alors on l'éteint, et si elle était éteinte, alors on l'allume)
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
// Et... on boucle à l'infini !
}
Les périphériques additionnels
En théorie, la puce Atmega328PB bénéficie de plus de périphériques :
+1 Bus Série UART
+1 Bus I2C
+1 Bus SPI
Avertissement
Actuellement, sur les versions ≤0.4 de la carte uPesy One, les broches supplémentaires de l’Atmega328PB ne sont pas facilement accessibles. En conséquence, les bus I2C
et SPI
supplémentaires ne pourront pas être utilisés, sauf si vous soudez vous-même des fils directement sur les broches de l’Atmega328PB.
Utiliser le port série UART1
Pour l’utiliser, rien de plus facile : il suffit de rajouter un 1
devant les objets dans le code : Serial.xx
→ Serial1.xx
.
Voici un bref exemple :
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
Serial.println("-- uPesy One Demo --");
}
void loop() {
Serial.println("Message envoyé à l'ordinateur");
Serial1.println("Message envoyé à une autre carte");
delay(1000);
}
Avoir une liaison UART supplémentaire est très pratique pour communiquer avec une autre carte tout en ayant la carte uPesy One branchée à l’ordinateur (via l’UART de base).
Avertissement
Les broches de l’UART1 sont utilisées aussi par le bus SPI. On ne peut malheureusement pas utiliser les 2 en même temps.
Fonctionnalités et différences basses niveaux
La version PB possède également des différences basses niveaux, qui sont rarement visibles lorsqu’on programme en code Arduino. Pour ceux qui codent les Atmega en bas niveau, avec les instructions AVR, je vous recommande de consulter ce document qui explique en détail les différences entre l’Atmega328P et l’Atmega328PB :
Differences-between-ATmega328P-and-ATmega328PB_ApplicationNote_AT15007
Ainsi que la datasheet complète: