Prima alcuni background. Quando il firmware per qualsiasi motivo si blocca (ad esempio overflow dello stack, puntatore a funzione corrotta ...) può accadere che salti da qualche parte e inizi ad eseguire del codice. Questo prima o poi porterà al reset del watchdog. MCU verrà ripristinato e siamo di nuovo in pista. A meno che ...Evitare la sovrascrittura del firmware accidentale
Che dire quando abbiamo il codice che scrive in flash (ad esempio bootloader)? Ora può succedere che salteremo accidentalmente direttamente nel codice di scrittura flash, saltando tutti i controlli. Prima che il cane da guardia abbaia, finirai con il firmware corrotto. Questo è esattamente quello che mi stava succedendo.
Ora alcuni potrebbero dire: risolvere il bug di root che ha causato il passaggio al codice di scrittura. Bene, quando stai sviluppando cambi continuamente il codice. Anche se al momento non ci sono bug di questo tipo, potrebbe esserci domani. Inoltre, nessun codice è privo di bug - o almeno non mio.
Quindi ora sto facendo una specie di controllo incrociato. Ho una variabile denominata "wen" che ho impostato su 0xa5 prima dei soliti controlli (ad esempio per verificare che la destinazione sia valida). Quindi, prima di eseguire la cancellazione o la scrittura effettiva, controllo che "wen" sia impostato su 0xa5. Altrimenti ciò significa che in qualche modo siamo saltati accidentalmente nel codice di scrittura. Dopo aver scritto con successo "wen" viene cancellato. Ho fatto questo in C e ha funzionato bene. Ma c'è ancora una leggera possibilità teorica di corruzione, perché ci sono poche istruzioni da questo controllo finale di "wen" fino a scrivere nel registro SPMCR.
Ora voglio migliorare questo mettendo questo controllo in assembly, tra le istruzioni di scrittura su SPMCR e 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"
);
Non ho ancora provato il codice, lo farò domani. Vedi qualche problema? Come/vuoi risolvere questo problema?
Sì, wen viene cancellato dopo una scrittura riuscita. Questa chiamata a __assert attiva effettivamente il reset del watchdog (in più registra alcune informazioni su cosa lo ha attivato). Felice di sentire che la gente usa effettivamente questi approcci :) – Stefan