logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

AVR-GCC - Uniknięcie hazardu (race condition) przy przerwaniach

szczupx 25 Mar 2014 22:31 1155 2
REKLAMA
  • #1 13443705
    szczupx
    Poziom 19  
    Procedura obliczenia() musi być wykonana po każdym przepełnieniu timera i tylko po przepełnieniu timera (musi się wykonać dokładnie tyle samo razy ile razy wystąpiło przerwanie timera). Wymagana jest też w szybka reakcja na inne przerwania - szybsza niż trwają obliczenia()

    Prawie dobre rozwiązanie nr 1(pseudokod):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Powyższe będzie działać, chyba że wydarzy się czarny scenariusz:
    1. procesor zostanie wybudzony przez inne niż timer przerwanie
    2. if(timer_flag) będzie niespełniony więc obliczenia() się nie wykonają
    3. w miejscu zaznaczonym komentarzem pojawi się przerwanie od timera
    4. procesor więc pójdzie spać, obliczenia() nie zostaną wykonane
    Wiem że prawdopodobieństwo wystąpienia tej sytuacji jest małe i prawdopodobnie to nigdy się nie zdarzy. Wolałbym jednak mieć pewność :)

    Rozwiązanie nr 2, z użyciem zagnieżdżonych przerwań:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wady:
    - zagnieżdżone przerwania to zło. Chociaż w tym przypadku mam mieszane uczucia, obliczenia() + obsługa ewentualnych innych przerwań spokojnie wyrobi się przed wystąpieniem kolejnego przepełnienia timera)
    - wszystkie zmienne na których działa obliczenia() trzeba będzie zadeklarować jako volatile

    Rozwiązanie nr 3, z sekcją krytyczną:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Według dokumentacji avr libc użycie konstrukcji z wykorzystaniem sleep_enable() gwarantuje wykonanie instrukcji po sei() zanim zostanie uruchomiona obsługa przerwania, więc to powinno działać.
    Wady:
    - nie jestem całkowicie pewien poprawności tego rozwiązania, i nie mam sposobu żeby je przetestować

    Proszę wytknięcie błędów, opinie który sposób uważacie za lepszy, może lepszy pomysł na rozwiązanie problemu?
  • REKLAMA
  • #2 13443893
    tmf
    VIP Zasłużony dla elektroda
    Rozwiązanie pierwsze jest bez sensu, bo po co ci przerwanie ustawiające flagę, która jest ustawiana sprzętowo (OVF)?
    Rozwiązanie drugie jest ok, aczkolwiek zamiast sei w przerwaniu lepiej zastosować ISR_NOBLOCK. Oczywiście to zadziała tylko pod warunkiem, że czas wykonywania obliczeń jest krótszy niż odstęp pomiędzy przerwaniami OVF. W przeciwnym przypadku nieuchronnie dojdzie do przepełnienia stosu. Sposób trzeci to wariacja sposobu pierwszego - zadziała, aczkolwiel lepiej po prostu sprawdzać flagę OVF i uniknąć niepotrzebnego przerwania.
    Są też inne sposoby - np. zastosowanie AVR z wielopoziomowym systemem przerwań (np. XMEGA), wtedy przerwaniu timera nadajesz najniższy priorytet, dzięki czemu nie blokuje ono innych przerwań, a masz też gwarancję, że dopóki się nie skończy nie zostanie obsłużone ponownie. To samo można też zaimplementować programowo.
  • #3 13444045
    szczupx
    Poziom 19  
    tmf napisał:
    Rozwiązanie pierwsze jest bez sensu, bo po co ci przerwanie ustawiające flagę, która jest ustawiana sprzętowo (OVF)

    Przerwanie jest mi potrzebne żeby obudzić uc.
REKLAMA