Сначала немного фона.Когда происходит сбой встроенного программного обеспечения по какой-либо причине (например, переполнение стека, поврежденный указатель на функцию ...), может случиться так, что он куда-то перепрыгнет и начнет выполнять некоторый код.Это рано или поздно приведет к сбросу сторожевого таймера.MCU перезагрузится, и мы вернемся на правильный путь.Если только ...
Как насчет того, когда у нас есть код, который записывает на флэш-память (например, загрузчик)?Теперь может случиться так, что мы случайно прыгнем прямо в код записи флэш-памяти - пропуская все проверки.Прежде чем сторожевой таймер начнет лаять, вы получите поврежденную прошивку.Это именно то, что происходило со мной.
Теперь некоторые могут сказать - исправить ошибку root, из-за которой мы даже запрыгнули в код записи.Ну, когда вы разрабатываете, вы постоянно меняете код.Даже если сейчас нет такой ошибки, завтра может быть.Кроме того, ни один код не содержит ошибок - или, по крайней мере, не мой.
Так что теперь я делаю какую-то перекрестную проверку.У меня есть переменная с именем 'wen', которую я устанавливаю в 0xa5 перед обычными проверками (например, проверяю, чтобы убедиться, что пункт назначения действителен).Затем, перед тем как приступить к фактическому стиранию или записи, я проверяю, действительно ли значение 'wen' равно 0xa5.В противном случае это означает, что мы как-то случайно запрыгнули в код написания.После успешной записи 'Вен' очищается.Я сделал это в 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"
);
Код еще не пробовал, сделаем это завтра.Вы видите какие-либо проблемы?Как вы решите такую проблему?