Dans l'activité HackerSpace, il est fréquent de devoir s'adapter à la situation.
Lors de l'utilisation d'un ATmega 328p sur une platine d'essai, le seul quartz disponible dans la boite à bidouille faisait 20MHz, mais le pack Arduino ne connait que 8MHz ou 16MHz comme fréquence standard....

Cet article présente une méthode qui permet de faire tourner un ATmega avec n'importe quel quartz en étant compatible avec les outils Arduino

 

Il faut tout d'abord comprendre le mécanisme de base des Arduino.

Sans rentrer dans les détails, lors de la mise sous tension, l'ATmega s'initialise et exécute le contenu de la mémoire.

Avec un Arduino, au début de la plage mémoire il y a un bootloader, en gros un jeu d'instructions qui correspond au BIOS d'un PC.

Ce bootloader va initialiser quelques trucs et marquer une petite pause en attendant un nouveau programme à travers le port série.

  • Si il reçoit un programme, il l'écrit en mémoire et reboot
  • Si il ne reçoit rien, il lance l’exécution du programme contenu en mémoire.

Si on flash l'ATmega328p en ISP avec un bootloader pour platine UNO ou assimilée, ça démarre normalement, mais impossible de charger un programme dans l'ATmega. En fait, ce qui pose problème, c'est que le port série n'est plus à la vitesse prévue !

La solution consiste à installer un bootloader modifié qui tient compte de la fréquence du quartz utilisé.

Pour faire les choses à peu près proprement, on va tout d'abord crée un nouveau modèle d'arduino, ça se fait en éditant le fichier /usr/share/arduino/hardware/arduino/board.txt

On ajoute une nouvelle définition portant le nom 'ATmega20MHz'

ATmega20MHz.name=ATmega @ 20MHz  # Nom humainement lisible dans l'interface
ATmega20MHz.upload.protocol=arduino
ATmega20MHz.upload.maximum_size=32256
ATmega20MHz.upload.speed=115200
ATmega20MHz.bootloader.low_fuses=0xff
ATmega20MHz.bootloader.high_fuses=0xde
ATmega20MHz.bootloader.extended_fuses=0x05
ATmega20MHz.bootloader.path=optiboot
ATmega20MHz.bootloader.file=optiboot_atmega328__20MHz.hex  # Nouveau bootloader
ATmega20MHz.bootloader.unlock_bits=0x3F
ATmega20MHz.bootloader.lock_bits=0x0F
ATmega20MHz.build.mcu=atmega328p
ATmega20MHz.build.f_cpu=20000000L  # Fréquence pour les 'sketches'
ATmega20MHz.build.core=arduino
ATmega20MHz.build.variant=standard

Ainsi, l'environnement Arduino dispose d'une nouvelle 'board' qui utilise un lanceur optiboot et tourne à 20MHz
Mais il faut à présent compiler ce nouveau bootloader, ça se fait assez simplement en allant dans /usr/share/arduino/hardware/arduino/bootloaders/optiboot/

On édite le fichier Makefile et on ajoute une nouvelle section

# 20MHz clocked platforms -- extra section
# for standalone ATMEGA328 on breadboard
# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue)
#

atmega328__20MHz: TARGET = atmega328__20MHz
atmega328__20MHz: MCU_TARGET = atmega328p
atmega328__20MHz: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega328__20MHz: AVR_FREQ = 20000000L
atmega328__20MHz: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328__20MHz: $(PROGRAM)_atmega328__20MHz.hex
atmega328__20MHz: $(PROGRAM)_atmega328__20MHz.lst

atmega328__20MHz_isp: atmega328__20MHz
atmega328__20MHz_isp: TARGET = atmega328__20MHz
atmega328__20MHz_isp: MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328__20MHz_isp: HFUSE = DE
# Low power xtal (16MHz) 16KCK/14CK+65ms
atmega328__20MHz_isp: LFUSE = FF
# 2.7V brownout
atmega328__20MHz_isp: EFUSE = 05
atmega328__20MHz_isp: isp

Il reste à compiler ce nouveau bootloader avec un

# make atmega328__20MHz

ça compile....

avr-gcc -g -Wall -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls -mmcu=atmega328p -DF_CPU=20000000L  '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'   -c -o optiboot.o optiboot.c
avr-gcc -g -Wall -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls -mmcu=atmega328p -DF_CPU=20000000L  '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib -o optiboot_atmega328__20MHz.elf optiboot.o 
avr-size optiboot_atmega328__20MHz.elf
text       data        bss        dec        hex    filename
502          0          0        502        1f6    optiboot_atmega328__20MHz.elf
avr-objcopy -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex optiboot_atmega328__20MHz.elf optiboot_atmega328__20MHz.hex
avr-objdump -h -S optiboot_atmega328__20MHz.elf > optiboot_atmega328__20MHz.lst
rm optiboot.o optiboot_atmega328__20MHz.elf

et on obtient un fichier optiboot__atmega328.hex

Maintenant qu'on à notre nouveau fichier, on ouvre l'outil Arduino, on connecte l'interface ISP (AVRUSB dans mon cas), on choisi notre board ATmega @ 20MHz et on écrit le nouveau bootloader.

Dans la fenètre de l'outil Arduino, on observe :

avrdude: Device signature = 0x1e950f
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 "optiboot_atmega328.hex"
avrdude: input file optiboot_atmega328.hex auto detected as Intel Hex
avrdude: ERROR: address 0x800a out of range at line 33 of optiboot_atmega328.hex
avrdude: read from file 'optiboot_atmega328.hex' failed

avrdude done.  Thank you.

En clair, on obtient un joli fail !


En fait, selon la version de GCC utilisé, une des options de compilation d'optiboot n'est pas valide, le terme 'naked' est invalide et doit être remplacé par 'OS_main'.

Heureusement, la solution est très simple, on va aller éditer le fichier /usr/share/arduino/hardware/arduino/bootloaders/optiboot/optiboot.c , et on fait la modification suivante

/* this line has to be modified to prevent overgrow bootloader with some GCC */
/* http://code.google.com/p/optiboot/source/detail?r=3aaa971abb56d72e34e49ec737330357c465a797 */
/* int main(void) __attribute__ ((naked)) __attribute__ ((section (".init9"))); */
/* Corredcted line is */
int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9")));

Et on recommence la compilation, puis on flash le nouveau bootloader.

 

Et voilà un Arduino-clone qui tourne à 20MHz ;)


Par contre, il semblerait que les mesures de temps, avec les instructions du type millis(), micros() et delay() nécessitent des ajustements, mais c'est à vérifier...