Cześć,
spotkałem się właśnie z kolejnym "ciekawym" problemem. W moim urządzeniu po wyłączeniu jest ono wybudzane raz na kilka ms lub za pomocą przerwania z zewnętrznego przycisku. W tym wybudzaniu sprawdzany jest stan baterii i w odpowiedni sposób mrugam ledem. Funkcja konfigurująca zachowanie urządzenia po wyłączeniu wygląda tak:
Natomiast funkcja rekurencyjna, która wywołuje tę funkcję i zajmuje się działaniem po wybudzeniu wygląda tak:
Czyli prosta sprawa - funkcja usypia mikrokontroler, po wybudzeniu czeka 1us (rodzaj prostego debouncingu dla interruptów z przycisku, które potrafią czasem aktywować się same w wyniku jakichś zakłóceń) wykonuje działania (kod poniżej) i jeśli przycisk nie jest wciśnięty to wywołuje się jeszcze raz, a jeśli jest, to resetuje mcu.
Problem pojawia się w przypadku kodu wykonywanego w środku tej funkcji. Kod działający wygląda tak:
A kod niedziałający tak:
Różnica jest tylko jedna w górnym przykładzie do dzielenia i jako max wartości używam 256 (bo to szybkie przesunięcie bitowe), a w dolnym 40. Jeśli w kodzie jest przykład dolny, to mimo, że nie wywołuje się nawet to co w if(!(PORTA.IN & PIN6_bm)) , to po chwili program się restartuje od początku, ale bez restartu mikrokontrolera. Sprawdziłem stany rejestrów i do resetu nie dochodzi. Czyli to musi być stack overflow. Zwłaszcza, że im częściej wybudzam (ustawiając wybudzenie od RTC), tym szybciej dochodzi do tego dziwnego restartu.
Dlaczego tak się dzieje? Domyślam się, że może to kwestia optymalizacji dokonywanej przez kompilator, że w jednym przypadku trzeba przechowywać jakieś zmienne między wywołaniami, co powoduje przepełnienie stosu, a w drugim nie?
No i w jaki sposób do tego podejść, żeby problem rozwiązać? Czy da się to zrobić jakoś bez rekurencji, tzn. wykonywać działania co wybudzenie a potem usypiać ponownie? Może jest jakieś oczywiste rozwiązanie, które mi umyka...
Z góry wielkie dzięki!
spotkałem się właśnie z kolejnym "ciekawym" problemem. W moim urządzeniu po wyłączeniu jest ono wybudzane raz na kilka ms lub za pomocą przerwania z zewnętrznego przycisku. W tym wybudzaniu sprawdzany jest stan baterii i w odpowiedni sposób mrugam ledem. Funkcja konfigurująca zachowanie urządzenia po wyłączeniu wygląda tak:
Kod: C / C++
Natomiast funkcja rekurencyjna, która wywołuje tę funkcję i zajmuje się działaniem po wybudzeniu wygląda tak:
Kod: C / C++
Czyli prosta sprawa - funkcja usypia mikrokontroler, po wybudzeniu czeka 1us (rodzaj prostego debouncingu dla interruptów z przycisku, które potrafią czasem aktywować się same w wyniku jakichś zakłóceń) wykonuje działania (kod poniżej) i jeśli przycisk nie jest wciśnięty to wywołuje się jeszcze raz, a jeśli jest, to resetuje mcu.
Problem pojawia się w przypadku kodu wykonywanego w środku tej funkcji. Kod działający wygląda tak:
Kod: C / C++
A kod niedziałający tak:
Kod: C / C++
Różnica jest tylko jedna w górnym przykładzie do dzielenia i jako max wartości używam 256 (bo to szybkie przesunięcie bitowe), a w dolnym 40. Jeśli w kodzie jest przykład dolny, to mimo, że nie wywołuje się nawet to co w if(!(PORTA.IN & PIN6_bm)) , to po chwili program się restartuje od początku, ale bez restartu mikrokontrolera. Sprawdziłem stany rejestrów i do resetu nie dochodzi. Czyli to musi być stack overflow. Zwłaszcza, że im częściej wybudzam (ustawiając wybudzenie od RTC), tym szybciej dochodzi do tego dziwnego restartu.
Dlaczego tak się dzieje? Domyślam się, że może to kwestia optymalizacji dokonywanej przez kompilator, że w jednym przypadku trzeba przechowywać jakieś zmienne między wywołaniami, co powoduje przepełnienie stosu, a w drugim nie?
No i w jaki sposób do tego podejść, żeby problem rozwiązać? Czy da się to zrobić jakoś bez rekurencji, tzn. wykonywać działania co wybudzenie a potem usypiać ponownie? Może jest jakieś oczywiste rozwiązanie, które mi umyka...
Z góry wielkie dzięki!
