Najpierw trochę tła. Gdy oprogramowanie układowe z jakiegokolwiek powodu ulegnie awarii (np. Przepełnienie stosu, uszkodzony wskaźnik funkcyjny ...) może się zdarzyć, że skacze gdzieś i rozpoczyna wykonywanie jakiegoś kodu. To prędzej czy później spowoduje reset watchdoga. MCU zresetuje się i wrócimy na właściwe tory. Chyba że ...Unikanie przypadkowego nadpisania oprogramowania układowego
Co powiesz na pytanie, kiedy mamy kod, który zapisuje do flashowania (np. Bootloader)? Teraz może się zdarzyć, że przypadkowo przejdziemy bezpośrednio do kodu zapisu flash - pomijając wszystkie kontrole. Zanim zadzwoni strażnik, skończy się uszkodzonym oprogramowaniem. Właśnie to mi się przydarzyło.
Teraz niektórzy mogą powiedzieć - naprawić błąd root, który spowodował, że nawet wskoczyliśmy do pisania kodu. Cóż, kiedy się rozwijasz, ciągle zmieniasz kod. Nawet jeśli w tej chwili nie ma takiego błędu, może być jutro. Poza tym żaden kod nie jest wolny od błędów - a przynajmniej nie mój.
Więc teraz robię coś w rodzaju sprawdzania krzyżowego. Mam zmienną o nazwie "wen", którą ustawiłem na wartość 0xa5 przed zwykłymi sprawdzeniami (np. Sprawdź, czy cel jest prawidłowy). Następnie tuż przed wykonaniem właściwego kasowania lub zapisu sprawdzam, czy 'wen' jest rzeczywiście ustawiony na 0xa5. W przeciwnym razie oznacza to, że jakoś przypadkowo wskoczyliśmy do kodu pisania. Po pomyślnym zapisaniu "wen" zostaje wyczyszczone. Zrobiłem to w C i zadziałało dobrze. Ale nadal istnieje niewielka teoretyczna szansa, że doszłoby do korupcji, ponieważ istnieje kilka instrukcji od tej ostatecznej kontroli "wen" aż do zapisu do rejestru SPMCR.
Teraz chcę to poprawić, umieszczając tę kontrolę w zestawie, między poleceniem write to SPMCR a instrukcją 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"
);
Nie próbowałem jeszcze kodu, zrobię to jutro. Czy widzisz jakieś problemy? W jaki sposób/rozwiążesz taki problem?
Tak, wen jest wyczyszczone po pomyślnym zapisaniu. To wywołanie __assert faktycznie wyzwala resetowanie watchdoga (dodatkowo rejestruje pewne informacje o tym, co go wyzwoliło). Cieszę się, że ludzie używają takich metod :) – Stefan