[AVR] Firmware qui reboote continuellement sans logique apparente

Le
JKB
Bonjour Í  tous,

Je sèche depuis une quinzaine de jours sur un problème qui me semble
assez étrange. Je suis en train d'écrire un firmware devant aller
sur un ATMega 1284.

C'est du C pur, sans fioriture, compilé avec gcc version 5.4.0 et
utilisant la libc avr.

Ce firmware fonctionne bien dès que je retire le code accédant au
module LoRaWAN. Si je le rajoute, le code dysfonctionne. En fonction
es compilations, il peut très bien fonctionner normalement, ou
rebooter en boucle (mais toujours au même endroit tant qu'il n'est
pas recompilé).

Bref, D'une compilation Í  une autre, il ne plante pas forcément au même
endroit.

J'ai passé plusieurs jours sur le listing, Í  chercher une corruption
de la mémoire, j'ai tenté simavr+gdb, je ne trouve pas ce qui
coince Í  tel point que j'en suis Í  envisager de mettre cela sur un
problème de compilo (je compile actuellement un GCC 11 pour la même
cible). J'avoue que je penche plus pour un problème dans mon code que
dans celui de GCC. J'ai aussi essayé de bissecter sans succès. De
temps en temps, ça fonctionne, mais je n'ai pas réussi Í  isoler ce
qui coince. Le firmware peut planter et un _ajout_ d'un stty_print()
de debug peut suffire Í  le faire fonctionner (!).

J'ai mis sur https://hilbert.systella.fr/public/firmware.tar.gz
un firmware avec un fichier elf résultant de la compilation.

Session simavr :

hilbert:[~/cvs/firmware] > simavr -m atmega1284 -f 16000000 firmware.elf
Loaded 101604 .text at address 0x0
Loaded 5736 .data
Loaded 2276 .eeprom
..
==..
Systella L100-A..
==..
..
Booting firmware 2021062117..
SPI initialized..
CLRC632 initialization..
CLRC632 reset done..
CLRC632 wait for ready..
CLRC632 ready..
CLRC632 wait for ready..
CLRC632 ready..
CLRC632 initialized..
Reset LORA..
Reset LORA done..
LoRaWAN 1.1..
Initialization SX1262..
Initialization SX1262 done..
0000000000000000..
MAC initialization..
LDL_MAC_addChannel:786>chIndex=0 freq†8100000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=1 freq†8300000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=2 freq†8500000 minRate=0 maxRate=5..
cb type..
processInit:992>set radio reset: ticks1..
processRadioReset:1007>clear radio reset: ticks1..
MAC initialization done..
tentative d'accès au lambda8..
après tentative d'accès au lambda8..
13..
00 00 00..
lora_send..
processStartRadioForEntropy:1057>listen for entropy: ticks2..
processEntropy:1077>read entropy: ticks2 entropy=0..
cb type=0..
LDL_MAC_ready..
LDL_MAC_otaa..
LDL_MAC_addChannel:786>chIndex=0 freq†8100000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=1 freq†8300000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=2 freq†8500000 minRate=0 maxRate=5..
avr_gdb_init listening on port 1234

Ça plante _exactement_ au même endroit sur la carte réelle. Je
fournis l'intégralité du firmware dans le tarball, mais la compilation en
fait un exemple assez minimal puisque le firmware se limite Í  :

- initialiser les entrées/sorties (io_config()) ;
- initialiser le bus spi (spi_init()) ;
- initialiser une horloge 32 bits (hz_init()) ;
- piloter un afficheur VFD ;
- cracher des informations sur le port série ;
- initialiser deux ou trois autres composants ;
- tenter d'accéder au composant gérant le réseau LoRa.

Tout se passe dans la fonction main() de main.c.

L'occupation mémoire est de :
-
Device: atmega1284

Program: 107340 bytes (81.9% Full)
(.text + .data + .bootloader)

Data: 6986 bytes (42.6% Full)
(.data + .bss + .noinit)

EEPROM: 2276 bytes (55.6% Full)
(.eeprom)

Il me reste donc 10 ko de RAM, ce qui est amplement suffisant
(normalement), pour gérer une pile LoRaWAN qui, d'après la doc,
demande 24 K de flash et Í  peu près 600 octets de RAM.
Il n'y a de mémoire qu'un seul malloc() (je sais, sur un
microcontrÍ´leur, ce n'est pas le pied) pour gérer des retours d'un
module GPS et ce code est inactif dans le code actuel.

Si quelqu'un avait une petite idée de la manière de débugguer cela,
merci de m'éclairer parce que je sèche totalement.

Bien cordialement,

JKB

--
Si votre demande me parvient en code 29, je vous titiouillerai volontiers
une réponse.
  • Partager ce contenu :
Vos réponses
Trier par : date / pertinence
JKB
Le #26575871
Le 21-06-2021, JKB
Bonjour Í  tous,
Je sèche depuis une quinzaine de jours sur un problème qui me semble
assez étrange. Je suis en train d'écrire un firmware devant aller
sur un ATMega 1284.
C'est du C pur, sans fioriture, compilé avec gcc version 5.4.0 et
utilisant la libc avr.
Ce firmware fonctionne bien dès que je retire le code accédant au
module LoRaWAN. Si je le rajoute, le code dysfonctionne. En fonction
es compilations, il peut très bien fonctionner normalement, ou
rebooter en boucle (mais toujours au même endroit tant qu'il n'est
pas recompilé).
Bref, D'une compilation Í  une autre, il ne plante pas forcément au même
endroit.
J'ai passé plusieurs jours sur le listing, Í  chercher une corruption
de la mémoire, j'ai tenté simavr+gdb, je ne trouve pas ce qui
coince Í  tel point que j'en suis Í  envisager de mettre cela sur un
problème de compilo (je compile actuellement un GCC 11 pour la même
cible). J'avoue que je penche plus pour un problème dans mon code que
dans celui de GCC. J'ai aussi essayé de bissecter sans succès. De
temps en temps, ça fonctionne, mais je n'ai pas réussi Í  isoler ce
qui coince. Le firmware peut planter et un _ajout_ d'un stty_print()
de debug peut suffire Í  le faire fonctionner (!).
J'ai mis sur https://hilbert.systella.fr/public/firmware.tar.gz
un firmware avec un fichier elf résultant de la compilation.
Session simavr :
hilbert:[~/cvs/firmware] > simavr -m atmega1284 -f 16000000 firmware.elf
Loaded 101604 .text at address 0x0
Loaded 5736 .data
Loaded 2276 .eeprom
..
=================..
Systella L100-A..
=================..
..
Booting firmware 2021062117..
SPI initialized..
CLRC632 initialization..
CLRC632 reset done..
CLRC632 wait for ready..
CLRC632 ready..
CLRC632 wait for ready..
CLRC632 ready..
CLRC632 initialized..
Reset LORA..
Reset LORA done..
LoRaWAN 1.1..
Initialization SX1262..
Initialization SX1262 done..
0000000000000000..
MAC initialization..
LDL_MAC_addChannel:786>chIndex=0 freq†8100000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=1 freq†8300000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=2 freq†8500000 minRate=0 maxRate=5..
cb type..
processInit:992>set radio reset: ticks1..
processRadioReset:1007>clear radio reset: ticks1..
MAC initialization done..
tentative d'accès au lambda8..
après tentative d'accès au lambda8..
13..
00 00 00..
lora_send..
processStartRadioForEntropy:1057>listen for entropy: ticks2..
processEntropy:1077>read entropy: ticks2 entropy=0..
cb type=0..
LDL_MAC_ready..
LDL_MAC_otaa..
LDL_MAC_addChannel:786>chIndex=0 freq†8100000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=1 freq†8300000 minRate=0 maxRate=5..
LDL_MAC_addChannel:786>chIndex=2 freq†8500000 minRate=0 maxRate=5..
avr_gdb_init listening on port 1234
Ça plante _exactement_ au même endroit sur la carte réelle. Je
fournis l'intégralité du firmware dans le tarball, mais la compilation en
fait un exemple assez minimal puisque le firmware se limite Í  :
- initialiser les entrées/sorties (io_config()) ;
- initialiser le bus spi (spi_init()) ;
- initialiser une horloge 32 bits (hz_init()) ;
- piloter un afficheur VFD ;
- cracher des informations sur le port série ;
- initialiser deux ou trois autres composants ;
- tenter d'accéder au composant gérant le réseau LoRa.
Tout se passe dans la fonction main() de main.c.
L'occupation mémoire est de :
----------------
Device: atmega1284
Program: 107340 bytes (81.9% Full)
(.text + .data + .bootloader)
Data: 6986 bytes (42.6% Full)
(.data + .bss + .noinit)
EEPROM: 2276 bytes (55.6% Full)
(.eeprom)
Il me reste donc 10 ko de RAM, ce qui est amplement suffisant
(normalement), pour gérer une pile LoRaWAN qui, d'après la doc,
demande 24 K de flash et Í  peu près 600 octets de RAM.
Il n'y a de mémoire qu'un seul malloc() (je sais, sur un
microcontrÍ´leur, ce n'est pas le pied) pour gérer des retours d'un
module GPS et ce code est inactif dans le code actuel.
Si quelqu'un avait une petite idée de la manière de débugguer cela,
merci de m'éclairer parce que je sèche totalement.

Bon, bug trouvé. C'est un bug du backend de GCC. Le code généré est
fautif (il écrase deux registres). J'ai trouvé un workaround en
rajoutant :
if (0) for(;;);
avant l'appel de fonction provoquant un jump Í  l'adresse nulle.
Et c'est un vieux bug, gcc 5.4.0 le contient, gcc 11.1.0 encore.
JKB
--
Si votre demande me parvient en code 29, je vous titiouillerai volontiers
une réponse.
Olivier Miakinen
Le #26575872
Le 23/06/2021 18:14, JKB a écrit :
Bon, bug trouvé. C'est un bug du backend de GCC. Le code généré est
fautif (il écrase deux registres).

Wow ! Félicitations pour avoir trouvé un bug de ce genre !
J'ai trouvé un workaround en rajoutant :
if (0) for(;;);

;-)
(par contre, pas de félicitations pour la porcinographie)
--
Olivier Miakinen
JKB
Le #26575873
Le 23-06-2021, Olivier Miakinen
(par contre, pas de félicitations pour la porcinographie)

J'ai écrit un truc qui dépasse ?
--
Si votre demande me parvient en code 29, je vous titiouillerai volontiers
une réponse.
Marc SCHAEFER
Le #26575874
JKB
Bon, bug trouvé. C'est un bug du backend de GCC. Le code généré est
fautif (il écrase deux registres). J'ai trouvé un workaround en
rajoutant :

J'avais pensé. Quand je développais sur microcontrÍ´leur (1996-2001),
j'avais eu exactement ce genre d'instabilités avec un compilateur Intel
très mauvais.
avant l'appel de fonction provoquant un jump Í  l'adresse nulle.
Et c'est un vieux bug, gcc 5.4.0 le contient, gcc 11.1.0 encore.

C'est aussi le cas en changeant les niveaux d'optimisation? C'est ainsi
que j'avais `workaroundisé' Í  l'époque ...
JKB
Le #26575875
Le 23-06-2021, Marc SCHAEFER
JKB
Bon, bug trouvé. C'est un bug du backend de GCC. Le code généré est
fautif (il écrase deux registres). J'ai trouvé un workaround en
rajoutant :

J'avais pensé. Quand je développais sur microcontrÍ´leur (1996-2001),
j'avais eu exactement ce genre d'instabilités avec un compilateur Intel
très mauvais.
avant l'appel de fonction provoquant un jump Í  l'adresse nulle.
Et c'est un vieux bug, gcc 5.4.0 le contient, gcc 11.1.0 encore.

C'est aussi le cas en changeant les niveaux d'optimisation? C'est ainsi
que j'avais `workaroundisé' Í  l'époque ...

Sauf que j'ai un souci de ce cÍ´té. Je ne peux utiliser que -Os ou
-O2 (la bibliothèque que j'utilise pour émuler un port série complet
avec RTS et CTS ne compile pas avec un autre niveau d'optimisation).
Mais j'ai un problème similaire avec -Os et -O2.
JKB
--
Si votre demande me parvient en code 29, je vous titiouillerai volontiers
une réponse.
Olivier Miakinen
Le #26575876
Le 23/06/2021 18:44, JKB a écrit (en ne citant que le strict nécessaire) :
J'ai écrit un truc qui dépasse ?

:-D
--
Olivier Miakinen
Poster une réponse
Anonyme