Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[RTOS] - - kilka ogólnych pytań (na początek)

Jado_one 08 Feb 2013 18:26 4062 23
Computer Controls
  • #1
    Jado_one
    Level 22  
    Witam,

    Aby nie zaśmiecać innego wątku, to przenoszę się z tematem tutaj ;-)
    Mam kilka pytań natury ogólnej dotyczącej RTOS'ów.

    Od dłuższego czasu planuję przejście na RTOS'a, ale do tej pory jakoś radziłem sobie bez niego stosując maszyny stanów. Ponieważ jednak programy rozrastają się i panowanie nad nimi zaczyna być coraz bardziej skomplikowane wzrok mój padł na RTOS'a ;-) (a może po prostu przyszedł na niego czas).

    Ogólne zasady działania RTOS'a jak mi się wydaje znam, na szczegóły przyjdzie pora jak przysiądę do konkretnego systemu, ale żeby się trochę wciągnąć w temat - kilka pytań ogólnych:

    Jak właściwie wygląda programowanie pod RTOS'em w stosunku do zwykłego "bare metal" programowania?
    Powiedzmy, że mamy jakiś gotowy kod np. biblioteka FatFS - czy trzeba go jakoś dostosowywać do ram RTOS'a, czy daje się go "wrzucic" tak po prostu do systemu?
    Czy też każdą procedurę trzeba jakoś formatować, obudowywać, itd, itp....i dopiero tak przygotowana nadaje się do użycia jako program użytkownika?

    Jak wygląda np. makefile, pliki startowe, itp....czy są dostarczane z RTOS'em dla konkretnego procesora/rodziny?

    Jak wyglądają sprawy obsługi sprzętu pod RTOS'em? Czy są jakieś - może nie gotowce - ale chociaż przykłady jego obsługi? Czy też trzeba je pisać samemu?
    Mam na myśli tutaj np. obsługę SPI, I2C, itd.... Jeżeli trzeba by je pisać - pewnie muszą one spełniać jakieś reguły? (normalizacja).

    No i jeszcze: W którym momencie należy zastosować zwykłe programowanie, a kiedy należy już użyć RTOS'a? Czy jak raz się "wsiąknie" w RTOS'a to juz nawet do migania LED'em będzie się go używać? ;-)

    Jak jest z uniwersalnością RTOS'ów - czy mamy tylko kilka "portów" na kilka konkretnych procesorów, a do reszty już nie ma i trzeba by przystosowywać je do każdego nowego modelu procka?

    No i chyba tyle na początek :-) Może coś się jeszcze urodzi w dalszych dyskusjach.
  • Computer Controls
  • #2
    tmf
    Moderator of Microcontroller designs
    RTOS to przede wszystkim problemy. Każdy wątek jest jakby zupełnie oddzielną aplikacją. I to jest fajne i pozornie proste. Problem zaczyna się, kiedy wątki muszą się ze soba komunikować lub współdzielić zasoby. I tu zaczyna się jazda. Przede wszystkim sterowniki urządzeń i peryferii muszą być napisane w sposób wielowątkowy. Nie jest to jakiś straszny problem, ale zapewne większość będziesz musiał sobie napisać sam. Teraz debugowanie - potrzebujesz IDE ze wsparciem dla wybranego RTOSa, ze względu na różne hokus pokus, jakie trzeba stosować zwykłe debuggery nie specjalnie się nadają. Część IDE takie wsparcie ma, np. Atmel Studio i inne. Większość RTOSów na proste MCU wspiera tylko zupełnie podstawowe rzeczy, więc znowu sporo musiałbyś napisać sam. Zanim się za to zabierzesz zaopatrz się w porzątną literaturę na ten temat. I proponuję popisać najpierw na PC, poznasz smaczki pisania wielowątkowego. Przejrzyj sobie sterowniki np. z kernela linuksa, będziesz miał wstęp do piekiełka :) Na ARM, czy AVR32 masz za free parę RTOSów z niezłą dokumentacją, masz też gotowe biblioteki. Na małe MCU typu AVR8, RTOS to sztuka dla sztuki, są porty, ale w praktyce 90% musisz wydłubać sam. No i przede wszystkim zadaj sobie pytanie co chcesz osiągnąć? IMHO event driven programming jest w stanie w 90% zaspokoić potrzeby skłaniające do przejścia na RTOS.
  • #3
    Jado_one
    Level 22  
    Na razie to ja patrzę w kierunku RTOS'a i zastanawiam się czy dobrze robię brnąc dalej w kierunku dalszego rozwijania maszyn stanów (i tak tu muszę wszystko sam sobie pisać), czy czasem w RTOS'ie nie będzie to łatwiejsze.
    Jeżeli się okaże, że to jest równie trudne lub trudniejsze, a i tak wszystko trzeba samemu też pisać, to może zostanę przy maszynach stanów.
    Stąd też te pytania "przedwstępne" - na razie i tak mam inny projekt do skończenia w najbliższym czasie, więc RTOS, to akurat dobry temat na dyskusje - póki co :-)
    Z literatury jak na razie mam: "Real-Time Systems - Design Principles for Distributed Embeded Applications" by Hermann Kopetz.
  • #4
    tmf
    Moderator of Microcontroller designs
    Nie widzę w jakim zakresie RTOS miałby stanowić konkurencję dla maszyny stanów? To zupełnie inne filozofie programowania, w dodatku wcale się nie wykluczające. Pewne zadania wygodniej jest realizować na RTOS - szczególnie te, które zawierają wiele niezależnych od siebie, lub nieznacznie tylko zależnych procesów. Inne zadania wygodniej jest realizować w postaci maszyny stanów. Nie ma też przeszkód, aby w ramach RTOS stosować dla poszczególnych wątków maszynę stanów, nie ma też przeszkód, aby pewne elementy maszyny stanów implementować w postaci semi-RTOS, np. wykorzystując wielopoziomowe przerwania. Na pewno warto o RTOS poczytać, bo pewne elementy są uniwersalne i przydatne nawet jeśli RTOS nie wykorzystujemy, a robimy jego protezy typu różne poziomy przerwań. Niemniej RTOS nigdy nie jest uniwersalnym panaceum na wszelakie problemy.
  • #5
    Freddie Chopin
    MCUs specialist
    Nie przesadzajmy - nie jest to znowu taki wielki problem.

    Co do sterowników urządzeń, to przy prostym założeniu można sprawę zredukować do zwyczajnego kodu jaki każdy tworzy bez RTOSów - to założenie to "danego urządzenia używa tylko jeden wątek". To pozornie wielkie ograniczenie w większości wypadków jest całkowicie słuszne, bo np. jak by wyglądał program w którym 3 wątki chcą odczytywać coś z UARTa - no bezsens... Jeśli zaś faktycznie kilka wątków musi używać jednego urządzenia, to wracamy do przedstawionej przed chwilą zasady - tworzymy wątek odpowiedzialny za dane urządzenie, wszystkie "inne" wątki które chcą czegoś używać (np. SPI) gadają tylko z wątkiem "nadzorującym".

    Event driven to przecież mini-RTOS, w którym schedulerem jest "coś co wywołuje obsługę handlera danego Eventu" - jedyna różnica jest taka, że Eveny się nie wywłaszczają, ale takie coś można przecież zrobić w każdym RTOSie - ustawiając go na tryb nie-wywłaszczający. Czy da się w nim zrobić wszystko? Może tak, ale pod warunkiem że handlery eventów nie są długie - w przeciwnym wypadku responsivness spada do zera. Za to w przypadku RTOSa nie ma problemu żeby mieć jeden okrutnie czasochłonny wątek o niskim priorytecie (niech liczy w kółko FFT) i kilka wątków wysokiego priorytetu do robienia rzeczy krytycznych (choćby komunikacja z userem).

    Tak - RTOS to "bliskie spotkanie trzeciego stopnia" z problemami synchronizacji, nieznanymi w programowaniu "bez RTOSa". W skrócie - jest to rozciągnięcie problemu przerwania--i-main-współdzielą-zmienne-którym-brak-volatile na wszystkie współdzielone dane i volatile nic tu nie pomaga (; Ale - rozwiązanie jest bardzo proste i podobne do tego co pisałem o sterownikach powyżej - jak nie ma współdzielenia danych, to nie ma też problemu! A NIE-współdzielenie danych, enkapsulacja, separacja i inne fajne słowa to nie są modne hasła, tylko naprawdę ważne rzeczy w pisaniu programów - trzymając się takich zasad problemu synchronizacji naprawdę można uniknąć...

    Tak swoją drogą - te Twoje maszyny stanów są "płaskie" czy "hierarchiczne"? Bo płaskie to masakra generalnie jest, do czegoś bardziej skomplikowanego trzeba się tak powtarzać że szok. Za to hierarchiczne to inna bajka (; No a mając takiego RTOSa można mieć HSM (czy tam FSM) w każdym wątku! Osobne i niezależne! (;

    Jak wygląda FatFS w RTOSie - całkiem nieźle, ponieważ FatFS jest pisany z uwzględnieniem możliwości użycia RTOSa, więc ma wbudowaną synchronizację - trzeba tylko zdefiniować "obiekt" synchronizacyjny (mutexa), ze 3 opcje i gotowe. Oczywiście driver do SPI też musi być RTOS-ready, ale tutaj - patrz początek posta. Jeśli biblioteka nie jest przystosowana do RTOSa (są takie?) to po prostu całą bibliotekę pakujesz w jeden wątek i używasz jej TYLKO i wyłącznie poprzez interfejs do tego wątku (kolejkę, semafor, co tam masz pod ręką) - czyli generalnie znów wracamy do zasady z początku wątku.

    Makefile i pliki podstawowe nie zmieniają się zupełnie względem zwyczajnego projektu. Czy są dostarczane z RTOSem? Zależy z jakim. Np w przypadku FreeRTOSa generalnie nie, ale to nie jest problem, ponieważ uruchomienie tego systemu jest łatwe (; W przypadku kombajnów typu NuttX masz gotowe Makefile (kilkaset pewnie), które są generalnie lewe itd., więc lepiej chyba pod tym względem wypada FreeRTOS.

    W którym momencie zastosować RTOS? Jak najwcześniej (; Ja polecam - super sprawa (;

    Uniwersalność zależy od danego RTOSa - np. FreeRTOS ma porty na tak wiele architektur, że można rzec iż jest "uniwersalny", ChibiOS/RT np ma ich mniej. Jak nie ma danego portu na daną architekturę (czyli np ARM7, MSP430, Cortex-M3, PIC32) to masz problem (; Generalnie jak dobrze znasz daną architekturę (assembler na 99% będzie obowiązkowy) to może podołasz, jak nie, to raczej nie ma się co za to zabierać. Dlatego też wybierasz takiego RTOSa jaki jest dostępny dla twojej platformy.

    Na koniec jeszcze napiszę o debuggowaniu RTOSa - jest trochę trudniej, ale bez specjalnego wsparcia ze strony IDE czy debuggera jest to 100% możliwe. Nawet nie jest to specjalnie problematyczne, tylko trochę upierdliwe. Powiedzmy że jak debuggowanie kodu na -Os jest upierdliwe, to debuggowanie RTOSa jest trochę bardziej upierdliwe, ale możliwe (; Nawiasem mówiąc OpenOCD i Eclipse takie wsparcie dla kilku RTOSów mają (m.in. FreeRTOS i ChibiOS/RT ale też kilka innych - większych).

    Z RTOSami może być trochę tak jak z SPLem dla STM32 czy z C++ na mikrokontrolery. Jedni powiedzą że to super sprawa, inni że totalny bezsens (; Ja mówię że super sprawa, ale owszem - jest trudniej, są nowe problemy (niespotykane bez RTOSów), ale dzięki RTOSowi można zupełnie inaczej zacząć myśleć o swoich programach.

    Na sam koniec - jak aplikacja ma robić wiele rzeczy, które nie są od siebie specjalnie zależne (nie są zsynchronizowane np. na takiej zasadzie że pomiar-obliczenia-akcja-pomiar-obliczenia-akcja-...) i nie da się tego osiągnąć przerwaniami, to RTOS ma sens. Jeśli np. jednocześnie musimy obsługiwać jakieś LCD i prezentować na nim wyniki czy ustawienia, logować pomiary na karcie SD, monitorować jakieś mierzone wielkości - RTOS jak znalazł. Jeśli aplikację jesteś w stanie przedstawić "liniowo" (wspomniane wcześniej pomiar-obliczenia-akcja-...) to RTOS jest niezbyt uzasadniony, ale oczywiście mając go - jeśli w przyszłości będziesz chciał dołożyć coś więcej - będzie łatwiej taki program rozbudować.

    4\/3!!
  • Computer Controls
  • #6
    Jado_one
    Level 22  
    Freddie Chopin wrote:


    Tak swoją drogą - te Twoje maszyny stanów są "płaskie" czy "hierarchiczne"? Bo płaskie to masakra generalnie jest, do czegoś bardziej skomplikowanego trzeba się tak powtarzać że szok. Za to hierarchiczne to inna bajka (; No a mając takiego RTOSa można mieć HSM (czy tam FSM) w każdym wątku! Osobne i niezależne! (;

    4\/3!!


    Generalnie to mam niezłą mieszankę :-) Niektóre maszyny stanów są zagnieżdżone - tak gdzieś na 3 poziomy, a reszta jest na tym samym poziomie - każda z nich zajmuje się obsługą czego innego. Jedna maszyna wywołuje inną maszynę, tamta wykonuje swoje działanie i wraca do stanu wyjściowego, itd... Jak trybiki w przekładni od zegara z kukułką ;-)
    To co męczy to bezustanne sprawdzanie czy mogę wywołać inną maszynę stanów, czy wysyłanie bajtów np. przez SPI się zakończyło i można wysłać nową porcję, wciąż flagi i stany innych maszyn do sprawdzania.
    No i co gorsza - żeby zrobić jakiś ciąg zdarzeń należy wywołać kolejną maszynę stanów, która się wykona i zrobi co potrzeba.
    Tak więc np. pod klawiszem w obsłudze menu nie ma jakiegoś podprogramu, który się wykona po jego nacisnieciu - tam mam tylko ew. przeładowanie zmiennych i odp. numer stanu innej maszyny, która zostanie wyzwolona "z uśpienia" i spełni swoją funkcję.
    Z tego co piszecie, to widzę że i w RTOS'ach nie uniknę sprawdzania przeróżnych flag.
    Sciągnąłem sobie tego NuttX'a - Widzę, że są tam konfiguracje dla PIC32 i STM, więc to by mi pasowało. Widzę jednak , że są to porty robione pod konkretne devboards z określonym HW na pokładzie.
    A co jak ja mam swoje własne DevBoards z innymi zasobami? Pewnie trzeba to gdzies pokonfigurować, coś powyłaczać, coś podefiniować....
    Na razie to i tak mnie przerasta, ale od czegoś trzeba zacząć....:-)
    A może lepiej byłoby zacząć od czegoś prostszego taki FreeRTOS np?....
    W każdym razie dobrze byłoby trochę ten temat liznąc i sprawdzić i porównać jak się piszę pod RTOS'a, a jak z użyciem maszyn stanów.
  • #7
    tymon_x
    Level 30  
    Jado_one wrote:
    To co męczy to bezustanne sprawdzanie czy mogę wywołać inną maszynę stanów, czy wysyłanie bajtów np. przez SPI się zakończyło i można wysłać nową porcję, wciąż flagi i stany innych maszyn do sprawdzania.

    Czy RTOS czy FSM/HSM, używasz do tego drugiego jakiś metod IPC (Inter-processing Communication) ? Żeby pozbyć się tego problemu typu, poczekaj aż zakończony się transmisja SPI ? Może pomyśl o maszynie stanów zarządzającej SPI i kolejką danych. Tak i tak tego nie unikniesz kiedyś, czy RTOS czy FSM/HSM, problem zawsze zostanie ten sam.

    Kosztem zużycia pamięci RAM, można przyspieszyć znacząco albo i nie, zależy jak będzie się tego używać. Warto zrobić Sobie takiego managera i w tym managerze zawsze sprawdzać gotowość do dalszego przetwarzania. W metodach od kolejek dodać metody odpowiedzialne ile jest bajtów/wolnego miejsca w buforze, w FSM metody sprawdzające stan:
    Code: c
    Log in, to see the code

    RTOSem tego tak na dzień dobry nie załatwisz. Trzeba najpierw usprawnić styl tworzenia oprogramowania.
  • #8
    Freddie Chopin
    MCUs specialist
    Jado_one wrote:
    Z tego co piszecie, to widzę że i w RTOS'ach nie uniknę sprawdzania przeróżnych flag.

    Jak dobrze przemyślisz program, to tego sprawdzania flag jest mało. No i generalnie to nie jest sprawdzanie flag (zmiennych) tylko czekanie na semafory/mutexy/kolejki, bo jakbyś miał sprawdzać flagę (zmienną) którą ustawi inny wątek, to masz zablokowany system (; No chyba że obydwa mają taki sam priorytet (lub ten czekający ma niższy) i jeden wątek przerwie drugi.

    Jado_one wrote:
    A może lepiej byłoby zacząć od czegoś prostszego taki FreeRTOS np?....

    Wg mnie tak. Na początek NuttX jest zbyt rozbudowany.

    tymon_x wrote:
    RTOSem tego tak na dzień dobry nie załatwisz. Trzeba najpierw usprawnić styl tworzenia oprogramowania.

    Yup.

    No bo jak masz hierarchiczną maszynę stanów to ja nie wiem po co sprawdzać tam flagi - jak się z danego stanu nie da wyjść, to po prostu dany stan nie obługuje danego eventa i tyle. Dopiero przejście do innego stanu (np. poprzez timeout) pozwoli na wykonanie jakiejś akcji (np. rozpoczęcia nowej transmisji). Miej na uwadze to, że HSM to nie jest to samo co zagnieżdżone FSMy - http://en.wikipedia.org/wiki/Hierarchical_state_machine#Hierarchically_nested_states
    W typowej implementacji to musi być jeden twór, choć da się to zrobić jako zagnieżdżone FSMy, ale to musi trochę inaczej działać no i wtedy chyba trudniej zrobić wszystkie "opcje" UMLa (takie jak entry/exit actions na przykład).

    4\/3!!
  • #9
    Jado_one
    Level 22  
    Te moje maszyny stanów to na pewno nie jest "event driven programming" - a przynajmniej nie jest to świadomie przeze mnie robione :-)
    Mnie chodziło o co innego. Raczej porównałbym to z RTOS'em bez wywłaszczania - tyle że procedury same dzielą się na "kawałki" a nie robi to za nich scheduler czy inny zarządca.
    Kiedyś napisałem artykulik na ten temat: http://www.easy-soft.net.pl/artykuly/asembler...ne-pod-wzgledem-wykorzystania-czasu-procesora
    Może przegryzienie się przez RTOS'y zaowocuje też jakimś pomysłem na zarządzanie tymi moimi maszynami stanów.
    A może - jak mi podpasuje jakiś RTOS, porzucę ten kierunek programowania ;-)
    Jest jeszcze to co robi Quantum Leaps - ale to też wcale nie jest takie łatwe do ugryzienia. Chyba nie da się ot tak sobie przeskoczyć z niższego poziomu na wyższy - trzeba jakoś do tego dojrzeć, przemyśleć to i owo, nauczyć po drodze różnych rzeczy i dopiero wtedy człowiek jest gotowy.
  • #10
    tmf
    Moderator of Microcontroller designs
    Z tego co widzę to zamiast zaraz rzucać się na RTOS warto przejść etap pośredni, czyli event driven programming. W ten sposób masz pewną namiastkę RTOS (i pewną namiastkę spotykanych tam problemów), a jednocześnie jest to istotny krok naprzód. To, podobnie jak RTOS umożliwia eliminację znacznej liczby flag i np. oczekiwania na ich zmianę, co stanowi wąskie gardła programowania sekwencyjnego.
  • #11
    Jado_one
    Level 22  
    No dobrze, ale dla event driven programming to o ile dobrze myślę, to muszę mieć najpierw oprogramowaną cała warstwę sprzętową - w jakiś zunifikowany sposób i dopiero mogę zasiadać do zastanawiania się nad stanami obiektu.
    Jeżeli mam zrobić najprostsze zapalenie diody po naciśnięciu klawisza, to musi być oprogramowana klawiatura (z debouncingiem, najlepiej na przerwaniach) - ja tylko zastanawiam się, że jak stan jeden to ma być zapalona dioda, a jak stan dwa zgaszona, a już jak to fizycznie jest wykonane, to mnie w tym momencie nie interesuje.
    Dobrze myslę?
  • #12
    tmf
    Moderator of Microcontroller designs
    W RTOS musisz zrobić dokładnie to samo, chyba, że ktoś ci dostarczy odpowiednich sterowników. Tu jest to nieco prostsze, bo zdarzenie (np. przerwanie IO z danego pinu) wywołuje ISR (namiastkę procesu), który odpoowiedzialny jest za debouncing i ew. zapalenie diody. Wszystko odbywa się niezależnie od innych fragmentów kodu, więc masz namiastkę programowania wielowątkowego. Jednocześnie nie masz wszystkich narzutów RTOS. Oczywiście wszystko zależy jakie aplikacje piszesz - jak wcześniej koledzy zauważyli, RTOS ma sens stosować jeśli twoja aplikacja składa się z wielu równolegle wykonywanych, najlepiej niezależnych wątków. RTOS umożliwia też uniknięcie wąskich gardeł spowodowanych poolingiem, ale przy poprawnym programowaniu w oparciu o zdarzenia też ich unikasz.
  • #13
    Freddie Chopin
    MCUs specialist
    Ja może tylko powiem, że w RTOS można łatwo zrobić event-driven-programming (a nawet z ficzerami takimi jak publish-subscribe), za to w event-driven-programming się nie da zrobić RTOSa (;

    tmf chyba trochę demonizuje - PIC32 czy ARMy są wystarczająco "mocne", żeby takiego RTOSa z narzutem dużo poniżej 1% ogarnąć... Przecież tysiące ludzi stosuje SPL, który daje dużo większy narzut i nie marudzą (dopóki nie mają jakiegoś problemu [; ).

    Może to też być trochę tak jak z C++ - pisząc program obiektowo po prostu "sam wychodzi większy", bo stosuje się "fajniejsze rzeczy" (polimorfizm, funkcje wirtualne, ...), których by się nie zastosowało w zwyczajnym C, bo składnia jest zbyt skomplikowana i problematyczna. Nie znaczy to jednak, że C++ daje większy kod. Tak samo jak RTOS nie jest z założenia niesamowicie skomplikowany, dopóki ktoś nie chce w nim zorganizować w skomplikowany sposób skomplikowanego programu. Im wyższy poziom oprogramowania (obiekty, wielowątkowość, synchronizacja, ...) tym większe znaczenie ma dobrze wymyślona architektura, przemyślany podział na zadania czy obiekty. Program jednowątkowy w C zwykle pisze się prawie na zasadzie "extreme programming", czyli siadasz i tworzysz - coś z tego wychodzi. Z takim podejściem w RTOSach czy C++ też się oczywiście da, ale zwykle iteracji poprawkowych jest wtedy dużo więcej i dużo częściej (;

    Jado_one - wejdź na stronę FreeRTOSa i przeczytaj sobie bardzo fajny "poradnik" (tutorial?) dotyczący ogólnie RTOSów, to Ci się trochę rozjaśni sprawa - http://www.freertos.org/implementation/main.html (część pierwsza raczej tylko na początek), potem przejrzyj ogólnie stronkę. Potem ściągnij dystrybucję, zerknij na przykładowe kody dla PIC32 to zobaczysz jak to w rzeczywistości wygląda (możesz też popatrzeć na kody z NuttX, ale jak mówiłem ten system ma kilka poważnych wad moim zdaniem, więcej można wygrzebać w temacie - https://www.elektroda.pl/rtvforum/topic2403619.html ). Dyskusja teoretyczna o oprogramowaniu zbyt daleko Cię nie zaprowadzi, a jak zerkniesz jak to w rzeczywistości wygląda to od razu załapiesz. Potem napisz sobie programik który miga 5 diodkami w 5 wątkach (1 wątek == 1 dioda) i już ruszysz z kopyta.

    No i w sumie zapomniałem o najlepszym problemie dotyczącym RTOSów - reentrancy (; To jest dopiero hardcore [;

    4/3!!
  • #14
    tmf
    Moderator of Microcontroller designs
    Oczywiście masz 100% racji, ja się nieprecyzyjnie wyraziłem. Nie chodziło mi o narzuty czasowe, które mogą być minimalne, ale narzuty edukacyjne :) Np. konieczność poznania mutexów, problemów związanych z synchronizacją, wielowątkowością itd. IMHO prosty event driving programming umożliwia łagodniejsze przejście w ten świat, bez jakiś dramatycznych zmian we własnych programach. A takie edp zrealizowane w oparciu o wielopoziomowe przerwania to stopniowe zbliżanie się do problemów typowych dla RTOS, w efekcie zamiast dużego skoku robimy małe kroczki. Można też od razu wejść w RTOS bez korzystania ze wszystkich jego features. Na ARM to jest łatwe, na AVR bezsensowne. Może mój sceptycyzm jest związany z tym, że siedzę na 8-bitach :)
  • #16
    Jado_one
    Level 22  
    tmf wrote:
    Wszystko odbywa się niezależnie od innych fragmentów kodu, więc masz namiastkę programowania wielowątkowego.

    No to coś takiego mam teraz własnie na maszynach stanów zrobione - aczkolwiek tam gdzie jest dostęp do sprzętu np. na jednym SPI mam obsługę karty SD i wyświetlacza GLCD muszę dbać o to, żeby obie procedury nie wchodziły sobie w paradę, stąd nawet jeśli są zainicjowane do działania, najpierw sprawdzają czy jest wolny dostęp do zasobu "SPI" To przypomina własnie owy "dostęp atomowy" tyle, że rozciągający się na fragment/całą procedurę - inna, która chce skorzystać z SPI musi czekać na "wolną drogę" sprawdzając sobie np. stan innej maszyny stanów lub jakąś flagę (semafor).
    Oczywiście staram się maks. wykorzystać miejsca gdzie dostęp jest możliwy np. pomiędzy przesłaniami 512bajtów z SD mogę sobie wsadzić wysłanie 1000bajtów danych do GLCD...itp...
    Z drugiej strony starałem się też unikać spiętrzeń np. obsługa drugiego wyświetlacza LCD idzie przez I2C (via PCF8574) - i choć to dwa różne zasoby sprzętowe (i2C i SPI), to lepiej nie wywoływać ich jednocześnie ,więc staram się wywoływać obsługę LCD po zaniku obsługi SPI...
    Wydaje mi się, że RTOS by takie porządkowanie wywołań załatwił z definicji...
    Osobną sprawą jest to, że gdyby z jakiegoś powodu taki semafor został ustawiony i nie skasowany, to blokuje mi to tą drugą procedurę (choć oczywiście inne maszyny stanów działają bez zakłóceń).
    To miałem własnie gdy nie uwzlędniłem dostępu atomowego i któraś z flag zmieniała się nieprawidłowo. Po usunięciu tego błedu jest OK.

    Dodano po 9 [minuty]:

    Freddie Chopin wrote:
    Program jednowątkowy w C zwykle pisze się prawie na zasadzie "extreme programming", czyli siadasz i tworzysz - coś z tego wychodzi. Z takim podejściem w RTOSach czy C++ też się oczywiście da, ale zwykle iteracji poprawkowych jest wtedy dużo więcej i dużo częściej (;

    No właśnie ja doszedłem do momentu kiedy nie chcę pisać w ten sposób a robić to w bardziej planowy sposób (to chyba się zwie inżynieria oprogramowania - choć może w przypadku mikrokontrolerów to zbyt wielkie słowo).
    Mam nadzieje, że RTOS własnie to trochę sformalizuje i wymusi pewne działania mając ustalone swoje mechanizmy.
    W sumie za dużo tego wszystkiego jest - to chyba praca na kilka lat?
  • #17
    tmf
    Moderator of Microcontroller designs
    Na kilka lat to może nie, ale na jakiś czas to pewne :) Dużo zależy od twojego stylu programowania, jeśli jest poprawny, to przejście to tylko kwestia niewielkiej teorii. Dla użytkowników myślących "sekwencyjnie" takie przejście to wywrócenie działania mózgu do góry nogami, w efekcie może być nieosiągalne :) Ale z tego co piszesz zaliczasz się do pierwszej kategorii, więc za miesiąc, dwa powinniśmy mieć eksperta od RTOS :)
    BTW, co do twoich problemów z dostępem do peryferii - łatwo to rozwiązać wykorzystując transakcje. Warto przenieść moment rozstrzygania dostępu z warstwy fizycznej interfejsu, do warstw wyższych. To upraszcza dostęp, ułatwia debugowanie i jest wygodne dla aplikacji - np. wysyła dane do zapisu na SD i nie martwi się jakimiś flagami, po prostu po wykonaniu zapisu driver zwraca status w odpowiedniej strukturze opisującej transakcję, lub też po prostu zwalnia pamięć.
  • #19
    Jado_one
    Level 22  
    No chciałeś Freddie podyskutować, to masz :D

    Do tej pory moja filozofia programowania sprowadzała się do tego, aby pisać nieblokujące procedury tzn. - jeśli nie można natychmiast skorzystać z dostępu, to wyskocz i daj popracować w tym czasie innym procedurom - może one w tym czasie są wolne i mogą działać - a za jakiś czas sprawdź czy już wolne i jeśli tak do działaj.
    I maszyny stanów umożliwiają realizację takiego podejścia.
    Ale to jest takie niskopoziomowe spojrzenie - a chciałbym spojrzeć teraz z wyższej perspektywy.
    Poza tym - każda maszyna, każda obsługa jest zindywidualizowana - często zależy to od sprzętu.
    Wy stosujecie jakąś unifikację w tym względzie? Planową.

    No i nie ma w tym jakiegoś zarządzania czasem - po prostu jedno z drugim się przeplata (pomijając niektóre moje zabiegi z flagami blokującymi wywołania jednych czasożernych procedur jak są w tym czasie wywołane inne czasożerne procedury), i jak wyjdzie, tak wyjdzie. A jest to asynchroniczne, to o spiętrzenia nietrudno.

    Ale może nie da się tego uniknąć - w końcu i Windows, jak ma za dużo zadań na raz, to "przywiesza się" - a tam przecież system operacyjny mamy.

    Problem jest też taki, że na który poziom abstrakcji by się nie wznosił, to np. brak dostępu do zasobu jest brakiem dostępu do zasobu - i tak muszę czekać.
    Ale tego chyba nikt nie przeskoczy - chyba, że np. zastosujemy więcej kanałów SPI, I2C, itd....
  • #20
    Freddie Chopin
    MCUs specialist
    Spróbuj zrobić coś na RTOSie to się przekonasz jak to wygląda. Wydaje mi się, że część swoich problemów rozwiążesz tym sposobem, ale cześć oczywiście pozostanie... Brak możliwości skorzystania z SPI "natychmiast" nie jest problemem jeśli zrobisz jak radzi tmf - generujesz transakcję, wysyłasz i zapominasz. Zostanie obsłużona gdy nadejdzie odpowiedni czas. Jeśli chcesz czekać na zakończenie, to RTOS Cię tutaj wspomoże - po prostu częścią paczki z transakcją musi być semafor na który czeka wątek "nadający", a który zostaje ustawiony przez wątek "faktycznie coś robiący".

    4\/3!!
  • #21
    Jado_one
    Level 22  
    Freddie Chopin wrote:
    Brak możliwości skorzystania z SPI "natychmiast" nie jest problemem jeśli zrobisz jak radzi tmf - generujesz transakcję, wysyłasz i zapominasz. Zostanie obsłużona gdy nadejdzie odpowiedni czas. Jeśli chcesz czekać na zakończenie, to RTOS Cię tutaj wspomoże - po prostu częścią paczki z transakcją musi być semafor na który czeka wątek "nadający", a który zostaje ustawiony przez wątek "faktycznie coś robiący".

    4\/3!!

    No to chyba mniej więcej ja mam tak teraz zrobione - tyle, że ja zapuszczam maszynę stanów i ona sobie sprawdza czy może działać na zasobie. W którym momencie ona to zrobi, to już "jej sprawa" :-)
    Przykładowo mam bufor w RAM'ie na dane wysyłane do GLCD. Tyle bajtów, żeby wypełniły cały ekran wyświetlacza. Chce coś napisać na ekranie - wysyłam odp. bajty do pamięci RAM - to akurat zajmuje tak mało czasu, że nie ma stanu oczekiwania - a potem wyzwalam maszynę, która "wypycha" te dane do GLCD.
    Czyli teoretycznie jest OK. Ale dopóki trwa to "wypychanie" nie mogę pisać do bufora w RAM'ie bobym nadpisał dane (sprawdzam sobie flagę "wysyłanie do GLCD w trakcie"). Tak czy tak jest czekanie.
    No, ale to już zależy od samych transmisji i ich niezerowych czasów trwania.
    Tego nie przeskoczymy.

    Osobne pytanie się pojawia - co będzie jak przekroczymy max czas na wykonanie zadania. Mamy time out (jeśli jest zaimplementowany). Co zrobić z obsługą błedu - o tym dyskutowaliśmy w innym wątku, więc nie bedę powtarzał :-)

    No nic - przyjrzę się RTOS'owi, czy w dziedzinie zarządzania czasem jest on lepszy od maszyn stanów.
  • #22
    tymon_x
    Level 30  
    Jado_one wrote:
    Problem jest też taki, że na który poziom abstrakcji by się nie wznosił, to np. brak dostępu do zasobu jest brakiem dostępu do zasobu - i tak muszę czekać.
    Ale tego chyba nikt nie przeskoczy - chyba, że np. zastosujemy więcej kanałów SPI, I2C, itd....

    Jado_one wrote:
    Przykładowo mam bufor w RAM'ie na dane wysyłane do GLCD. Tyle bajtów, żeby wypełniły cały ekran wyświetlacza. Chce coś napisać na ekranie - wysyłam odp. bajty do pamięci RAM - to akurat zajmuje tak mało czasu, że nie ma stanu oczekiwania - a potem wyzwalam maszynę, która "wypycha" te dane do GLCD.
    Czyli teoretycznie jest OK. Ale dopóki trwa to "wypychanie" nie mogę pisać do bufora w RAM'ie bobym nadpisał dane (sprawdzam sobie flagę "wysyłanie do GLCD w trakcie"). Tak czy tak jest czekanie.
    No, ale to już zależy od samych transmisji i ich niezerowych czasów trwania.
    Tego nie przeskoczymy.

    Już dostałeś odpowiedź na Swoje "nie przeskoczymy":
    Freddie Chopin wrote:
    No to może czas zrobić maszynę stanów odpowiedzialną tylko za dane urządzenie? (; Oczywiście wtedy musisz się porozumiewać z danym urządzeniem (np. SPI) tylko poprzez interfejs do maszyny stanów.

    Sam stosuje takie managery/maszyny stanów. Każdy posiada kolejkę wejścia/wyjścia. Serializuje bajty z nagłówka, tak żeby znać rozmiar czy inne parametry oraz dane w jeden ciąg bajtów, umieszczam do to kolejki. Tam maszyna odbiera dane, rozkodowuje/parsuje i wykonuje akcje. Uwierz mi, sprawdza się to doskonale. Jeśli masz instancję co musi rysować w tym samym buforze i wypychać na ekran, bo nie możesz zrobić podwójnego buforowania, to wystarczy zrobić maszynę, co będzie posiadała możliwość odbierania komend i na nic nie czekasz.

    Pokaże o co biega na przykładzie. Mam funkcję do zmiany adresu odbiorcy w transeiverze. Jest FSM, który zarządza tym urządzeniem oraz FSM, który zarządza SPI. Nie interesuje mnie w którym ona stanie się znajduje, czy coś wysyła, odbiera czy cholipcia coś innego. Zapisuje rozkaz z danymi i niech się robi:
    Code: c
    Log in, to see the code

    Jedyną jaką informację dostaje, czy się udało czy nie. Tutaj decyduje tylko rozmiar bufora (FIFO, bufor cykliczny) i częstotliwość zapisu/odczytu. Mam takich maszyn wszędzie, są tak pisane że rybka, czy działają z RTOS czy bez niego. Tu chodzi właśnie o jakość oprogramowania, sposobie myślenia i podchodzenia do pewnych problemów.

    Wracając do Twojego rysowania, to bym zrobił tak jak w powyższej funkcji i niech cała magia dzieje się sama. A co mnie interesuje, że bufor używany czy nie. Żadnych flag, pollingów i innych nie potrzebnych rzeczy. Można ? Można !
  • #23
    Jado_one
    Level 22  
    Powiem Ci, że przemknęła mi przez głowę taka buforowana maszyna stanów. Jeśli chodzi o utratę danych (np. wprowadzanych z klawiatury), to rzeczywiście to powinno pomóc (o ile się nie zapełni całego bufora).
    Będę musiał zrobić sobie taką jedną i sprawdzić jak to działa.
    Bo w tej chwili jeżeli dostęp do maszyny stanów będzie akurat wolny, to OK - maszyna wykona swoje działanie. Ale jeżeli by akurat nie było dostępu, to następuje pominięcie/odrzucenie i koniec. Żeby tego uniknąc, stosuję drugą maszynę stanów, która ponawia access do tej pierwszej do skutku. To działa, ale te maszyny za bardzo się mnożą, co komplikuje program, a mnie męczy.
    Buforowanie mogłoby mi pomóc pozbyć się części takich maszyn.
    Dzięki za pomysł :-)

    W końcu wyjdzie na to, że zamiast zgłębiać RTOS zostanę przy maszynach stanów ;-)

    Dodano po 49 [minuty]:

    tmf wrote:
    nie ma też przeszkód, aby pewne elementy maszyny stanów implementować w postaci semi-RTOS, np. wykorzystując wielopoziomowe przerwania.

    Możesz coś więcej na ten temat? Chodzi o ideę.

    Dodano po 13 [minuty]:

    Freddie Chopin wrote:
    Nie przesadzajmy - nie jest to znowu taki wielki problem.
    Oczywiście driver do SPI też musi być RTOS-ready, ale tutaj - patrz początek posta.

    A jak wygląda sprawa "zmiany w locie" parametrów peryferiów.
    Przykładowo do obsługi karty SD używam początkowo zwykłego SPI - 8 bit (rozkazy, response z karty, itp), natomiast do transferu danych z karty zmieniam parametry np. używam DMA, albo odczytuje dane w trybie 4-bajtowym SPI, żeby przyspieszyć transfer.
    A na przykład do obsługi GLCD via SPI używam znowu innego trybu połączonego z generowaniem różnych stanów na pinach sterujących GLCD (rozkaz/dane/cs/reset).
    W tej chwili mam maszynę stanów w przerwaniu od SPI, która w zależności od tego "kto żąda danych" wybiera odp. rodzaj transferu danych przez SPI.

    Czy w RTOS'ie mogę zastosować to samo (też maszynę stanów)? Czy są jakieś inne mechanizmy?
  • #24
    Freddie Chopin
    MCUs specialist
    Możesz to zrobić jak chcesz [; Przecież takie parametry mogą być częścią transakcji i już.

    Bylebyś miał tylko jeden sposób "dojścia" do tego SPI, tzn. że każdy wątek gada przez jakiś interfejs, a nie każdy wątek sam sobie grzebie w rejestrach SPI.

    4\/3!!