Tout d'abord, un peu de contexte. Quand un firmware se plante pour une raison quelconque (par exemple débordement de pile, pointeur de fonction corrompu...), il peut arriver qu'il saute quelque part et commence à exécuter du code. Ceci résultera tôt ou tard en une réinitialisation du chien de garde. Le MCU se réinitialisera et nous serons de nouveau sur la bonne voie. A moins que...
Qu'en est-il lorsque nous avons du code qui écrit sur la flash (par exemple le bootloader) ? Maintenant il peut arriver que l'on saute accidentellement directement dans le code d'écriture flash - sautant toutes les vérifications. Avant que le chien de garde n'aboie, vous vous retrouverez avec un firmware corrompu. C'est exactement ce qui m'est arrivé.
Maintenant, certains pourraient dire - fixer le bug de la racine qui a causé que nous avons même sauté dans le code d'écriture. Eh bien, lorsque vous développez, vous modifiez constamment le code. Même s'il n'y a pas de bogue à ce moment-là, il pourrait y en avoir un demain. De plus, aucun code n'est exempt de bogues - ou du moins pas le mien.
Alors maintenant, je fais une sorte de vérification croisée. J'ai une variable nommée "wen" que je fixe à 0xa5 avant les contrôles habituels (par exemple, vérifier que la destination est valide). Ensuite, juste avant de procéder à l'effacement ou à l'écriture, je vérifie que 'wen' est bien à 0xa5. Sinon, cela signifie que nous avons accidentellement sauté dans le code d'écriture. Après une écriture réussie, 'wen' est effacé. J'ai fait cela en C et cela a bien fonctionné. Mais il y a toujours une petite chance théorique qu'une corruption se produise, car il y a peu d'instructions entre cette vérification finale de 'wen' et l'écriture dans le registre SPMCR.
Maintenant je veux améliorer cela en mettant cette vérification dans l'assemblage, entre l'écriture à SPMCR et l'instruction spm.
__asm__ __volatile__
(
"lds __zero_reg__, %0\n\t"
"out %1, %2\n\t"
"ldi r25, %3\n\t"
"add __zero_reg__, r25\n\t"
"brne spm_fail\n\t"
"spm\n\t"
"rjmp spm_done\n\t"
"spm_fail: clr __zero_reg__\n\t"
"call __assert\n\t"
"spm_done:"
:
: "i" ((uint16_t)(&wen)),
"I" (_SFR_IO_ADDR(__SPM_REG)),
"r" ((uint8_t)(__BOOT_PAGE_ERASE)),
"M" ((uint8_t)(-ACK)),
"z" ((uint16_t)(adr))
: "r25"
);
Je n'ai pas encore essayé le code, je le ferai demain. Voyez-vous des problèmes ? Comment faites-vous/feriez vous pour résoudre ces problèmes ?