最初にいくつかの背景。何らかの理由でファームウェアがクラッシュすると (スタック オーバーフロー、関数ポインタの破損など)、どこかにジャンプして何らかのコードの実行を開始することがあります。これにより、遅かれ早かれウォッチドッグがリセットされます。MCU はリセットされ、軌道に戻ります。そうでもなければ...
フラッシュに書き込むコード (ブートローダなど) がある場合はどうでしょうか? ここで、すべてのチェックをスキップして、誤ってフラッシュ書き込みコードに直接ジャンプしてしまう可能性があります。ウォッチドッグが吠える前に、ファームウェアが破損することになります。これはまさに私に起こっていたことです。
今、一部の人は言うかもしれません - コードの記述に飛び込む原因となった根本的なバグを修正してください。開発中は常にコードを変更しています。現時点でそのようなバグがなくても、明日はあるかもしれません。その上、バグのないコードはありません - または少なくとも私のものではありません。
だから今、私はある種のクロスチェックを行っています。「wen」という名前の変数があり、通常のチェック (宛先が有効であることを確認するなど) の前に 0xa5 に設定します。次に、実際の消去または書き込みを行う直前に、「wen」が本当に 0xa5 に設定されているかどうかを確認します。それ以外の場合、これは何らかの形で誤ってコードの記述に飛び込んだことを意味します。書き込みが成功すると、「wen」はクリアされます。私はこれをCで行いましたが、うまくいきました。ただし、理論的には破損が発生する可能性がわずかにあります。これは、この「wen」の最終チェックから SPMCR レジスタへの書き込みまでの命令がほとんどないためです。
ここで、このチェックを SPMCR への書き込みと 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"
);
コードはまだ試していません。明日試してみます。問題はありますか?そのような問題をどのように解決しますか?