Primero algunos antecedentes. Cuando el firmware por cualquier motivo se bloquea (por ejemplo, desbordamiento de pila, puntero de función dañada ...) puede suceder que salte a algún lado y comience a ejecutar algún código. Esto tarde o temprano dará como resultado el reinicio del perro guardián. MCU se reiniciará y volvemos a la pista. A menos que ...Evitar la sobrescritura accidental del firmware
¿Qué sucede cuando tenemos un código que escribe en flash (por ejemplo, gestor de arranque)? Ahora puede suceder que saltemos accidentalmente directamente al código de escritura flash, omitiendo todas las comprobaciones. Antes de que watchdog ladre, terminará con firmware dañado. Esto es exactamente lo que me estaba pasando.
Ahora dirán algunos: solucione el error de raíz que provocó que incluso saltáramos al código de escritura. Bueno, cuando estás desarrollando estás constantemente cambiando el código. Incluso si no hay tal error en este momento, puede haber mañana. Además, ningún código está libre de errores, o al menos no es mío.
Así que ahora estoy haciendo algún tipo de comprobación cruzada. Tengo una variable llamada 'wen' que establecí en 0xa5 antes de las comprobaciones habituales (por ejemplo, verificar para asegurarse de que el destino sea válido). Entonces, justo antes de hacer el borrado real o escribir, verifico si 'wen' realmente está configurado a 0xa5. De lo contrario, esto significa que de alguna manera accidentalmente saltamos al código de escritura. Después de escribir con éxito, 'wen' se borra. He hecho esto en C y funcionó bien. Pero todavía hay una ligera probabilidad teórica de que la corrupción ocurra, porque hay pocas instrucciones de esta verificación final de 'wen' hasta que se escriba en el registro de SPMCR.
Ahora quiero mejorar esto poniendo esta verificación en el ensamblaje, entre la escritura en las instrucciones SPMCR y 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"
);
No he probado el código todavía, lo haremos mañana. ¿Ves algún problema? ¿Cómo resolvería usted/tal problema?
Sí, wen se borra después de escribir con éxito. Esta llamada a __assert realmente desencadena el restablecimiento de watchdog (además de que registra algo de información sobre lo que lo activó). Me alegra oír que las personas realmente usan tales enfoques :) – Stefan