Poniższy artykuł poświęcono opisowi architektury i projektowania oprogramowania wbudowanego zgodnie z tzw. architekturą pierwszego planu i tła, znaną również jako: „superloop” lub „main+ISR”. To podstawowe ujęcie jest bardzo ważne i ułatwia zrozumienie wszystkich innych, bardziej zaawansowanych, takich jak systemy operacyjnego czasu rzeczywistego (RTOS).
Jak sama nazwa wskazuje, architektura składa się z dwóch głównych części: nieskończonej pętli while(True){…} w tle, wewnątrz funkcji main() oraz procedur obsługi przerwań (ISR) obejmujących działania na: „pierwszym planie”. Przerwania, operujące na pierwszym planie (np. SysTick_Handler()), wywłaszczają pętlę funkcjonującą w tle, ale zawsze wracają do punktu wywłaszczania. Dwie części systemu komunikują się za pośrednictwem wspólnych zmiennych (np. l_tickCtr). Aby uniknąć występowania tzw. wyścigu w dostępie do zmiennych, spowodowanego asynchronicznym uruchamianiem przerwań, wspólne muszą być chronione przez krótkie wyłączanie przerwań, związanych z akcesem do nich, gdy są one modyfikowane.
Blokowanie pętli w tle
Pętla tła może być ustrukturyzowana na wiele sposobów. Opcja: „Blinky” pokazana na początku wklejonego powyżej filmu demonstruje najprostszą strukturę sekwencyjną (używaną również w przykładzie dla Arduino Blink). Implementacja opiera się na funkcji BSP_delay(), której jedynym celem jest blokowanie pętli w tle (zapobieganie jej działaniu dalej). Taka struktura kodu nazywana jest sekwencyjną, ponieważ porządek oczekiwanych zdarzeń jest zakodowany na stałe w wywołaniach blokujących, z których każde wyraźnie czeka na określone zdarzenie. Np. po włączeniu diody wywołanie blokujące BSP_delay(BSP_TICKS_PER_SEC/4) oczekuje na zdarzenie timeout za 1/4 sekundy, a po jej wyłączeniu kolejne BSP_delay(BSP_TICKS_PER_SEC*3/4) wyczekuje na przekroczenie czasu przez następne 3/4 sekundy.
Kod sekwencyjny jest prosty, ale trudno go rozszerzyć. Pętla w tle zapchana wywołaniami blokującymi wykonuje się powoli (tylko raz na sekundę w przypadku Blinky). W konsekwencji żadne zdarzenie wymagające szybszej reakcji nie może zostać obsłużone w odpowiednim czasie.
Nieblokująca pętla w tle
Jednak możliwy jest również inny rodzaj ustrukturyzowania, co pokazano w przykładzie na końcu filmu. W takim przypadku pętla w tle stale sprawdza zdarzenia przekroczenia limitu czasu w zależności od bieżącego stanu diody LED (w materiale ON_STATE lub OFF_STATE). Dopiero po wykryciu odpowiedniego timeout, pętla wykonuje adekwatne akcje, takie jak włączenie lub wyłączenie diody LED, ponownie w zależności od stanu. Taka nieblokująca struktura kodu jest nazywana w filmie sterowaną zdarzeniami.
Najważniejszą zaletą kodu ww. rodzaju jest rozszerzalność, ponieważ pętla zdarzeń może obsłużyć dowolną ich sekwencję. Ceną za to jest to, że kod sterowany zdarzeniami jest znacznie mniej czytelny niż ten sekwencyjny, jako że oczekiwany porządek nie jest już łatwo widoczny (brak wywołań blokujących). Równie ważne jest to, że nieblokująca pętla tła działa bardzo szybko (kilka tysięcy razy na sekundę w przypadku omawianego tutaj i powyżej przykładu). Dzięki temu bez problemu poradzi sobie z wszelkimi nowymi zdarzeniami, także tymi wymagającymi dynamicznej reakcji.
Uwagi
W pełni blokujące i całkowicie nieblokujące pętle tła tworzą całe spektrum architektur pierwszego planu i tła. W praktyce, realne mieszczą się gdzieś pomiędzy tymi dwoma ideami. Typowa pętla w tle często zaczyna się od prostej struktury sekwencyjnej. Jednak w miarę dodawania nowych zdarzeń staje się coraz bardziej nimi sterowana, a czas jej trwania musi zostać skrócony. Nierzadko kończy się to najgorszym z obu światów — sekwencja zdarzeń staje się niewidoczna, ale program też nie do końca jest łatworozszerzalny, z powodu: „zatkania” przepływu sporadycznymi wywołaniami blokującymi. Próby zapobieżenia takiemu rozpadowi architektury wiodą w dwóch kierunkach: wysiłki mające na celu uratowanie struktury sekwencyjnej prowadzą do powstania Systemu Operacyjnego Czasu Rzeczywistego (RTOS), który omówić trzeba już zupełnie osobno. Starania na rzecz zapobiegania zbytniemu komplikowaniu kodu, wynikającemu z improwizowanego podejścia systemu: „sterowanego zdarzeniami”, zmierzają do programowania sterowanego zdarzeniami, maszyn stanowych i obiektów aktywnych, co również należy wyjaśnić oddzielnie.
Źródło: https://www.embedded.com/programming-embedded-systems-foreground-background-architecture-superloop/
Jak sama nazwa wskazuje, architektura składa się z dwóch głównych części: nieskończonej pętli while(True){…} w tle, wewnątrz funkcji main() oraz procedur obsługi przerwań (ISR) obejmujących działania na: „pierwszym planie”. Przerwania, operujące na pierwszym planie (np. SysTick_Handler()), wywłaszczają pętlę funkcjonującą w tle, ale zawsze wracają do punktu wywłaszczania. Dwie części systemu komunikują się za pośrednictwem wspólnych zmiennych (np. l_tickCtr). Aby uniknąć występowania tzw. wyścigu w dostępie do zmiennych, spowodowanego asynchronicznym uruchamianiem przerwań, wspólne muszą być chronione przez krótkie wyłączanie przerwań, związanych z akcesem do nich, gdy są one modyfikowane.
Blokowanie pętli w tle
Pętla tła może być ustrukturyzowana na wiele sposobów. Opcja: „Blinky” pokazana na początku wklejonego powyżej filmu demonstruje najprostszą strukturę sekwencyjną (używaną również w przykładzie dla Arduino Blink). Implementacja opiera się na funkcji BSP_delay(), której jedynym celem jest blokowanie pętli w tle (zapobieganie jej działaniu dalej). Taka struktura kodu nazywana jest sekwencyjną, ponieważ porządek oczekiwanych zdarzeń jest zakodowany na stałe w wywołaniach blokujących, z których każde wyraźnie czeka na określone zdarzenie. Np. po włączeniu diody wywołanie blokujące BSP_delay(BSP_TICKS_PER_SEC/4) oczekuje na zdarzenie timeout za 1/4 sekundy, a po jej wyłączeniu kolejne BSP_delay(BSP_TICKS_PER_SEC*3/4) wyczekuje na przekroczenie czasu przez następne 3/4 sekundy.
Kod sekwencyjny jest prosty, ale trudno go rozszerzyć. Pętla w tle zapchana wywołaniami blokującymi wykonuje się powoli (tylko raz na sekundę w przypadku Blinky). W konsekwencji żadne zdarzenie wymagające szybszej reakcji nie może zostać obsłużone w odpowiednim czasie.
Nieblokująca pętla w tle
Jednak możliwy jest również inny rodzaj ustrukturyzowania, co pokazano w przykładzie na końcu filmu. W takim przypadku pętla w tle stale sprawdza zdarzenia przekroczenia limitu czasu w zależności od bieżącego stanu diody LED (w materiale ON_STATE lub OFF_STATE). Dopiero po wykryciu odpowiedniego timeout, pętla wykonuje adekwatne akcje, takie jak włączenie lub wyłączenie diody LED, ponownie w zależności od stanu. Taka nieblokująca struktura kodu jest nazywana w filmie sterowaną zdarzeniami.
Najważniejszą zaletą kodu ww. rodzaju jest rozszerzalność, ponieważ pętla zdarzeń może obsłużyć dowolną ich sekwencję. Ceną za to jest to, że kod sterowany zdarzeniami jest znacznie mniej czytelny niż ten sekwencyjny, jako że oczekiwany porządek nie jest już łatwo widoczny (brak wywołań blokujących). Równie ważne jest to, że nieblokująca pętla tła działa bardzo szybko (kilka tysięcy razy na sekundę w przypadku omawianego tutaj i powyżej przykładu). Dzięki temu bez problemu poradzi sobie z wszelkimi nowymi zdarzeniami, także tymi wymagającymi dynamicznej reakcji.
Uwagi
W pełni blokujące i całkowicie nieblokujące pętle tła tworzą całe spektrum architektur pierwszego planu i tła. W praktyce, realne mieszczą się gdzieś pomiędzy tymi dwoma ideami. Typowa pętla w tle często zaczyna się od prostej struktury sekwencyjnej. Jednak w miarę dodawania nowych zdarzeń staje się coraz bardziej nimi sterowana, a czas jej trwania musi zostać skrócony. Nierzadko kończy się to najgorszym z obu światów — sekwencja zdarzeń staje się niewidoczna, ale program też nie do końca jest łatworozszerzalny, z powodu: „zatkania” przepływu sporadycznymi wywołaniami blokującymi. Próby zapobieżenia takiemu rozpadowi architektury wiodą w dwóch kierunkach: wysiłki mające na celu uratowanie struktury sekwencyjnej prowadzą do powstania Systemu Operacyjnego Czasu Rzeczywistego (RTOS), który omówić trzeba już zupełnie osobno. Starania na rzecz zapobiegania zbytniemu komplikowaniu kodu, wynikającemu z improwizowanego podejścia systemu: „sterowanego zdarzeniami”, zmierzają do programowania sterowanego zdarzeniami, maszyn stanowych i obiektów aktywnych, co również należy wyjaśnić oddzielnie.
Źródło: https://www.embedded.com/programming-embedded-systems-foreground-background-architecture-superloop/
Fajne? Ranking DIY
