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

Jak efektywnie zarządzać przerwaniami i zadaniami w dużych projektach na uC?

marcin1990 28 Cze 2013 10:21 6189 39
Najlepsze odpowiedzi LABEL_AI_GENERATED

Jak zaprojektować architekturę dużego programu na mikrokontrolerze z wieloma ADC/DAC, menu, komunikacją i ciężkimi obliczeniami typu RMS/FFT, żeby sensownie podzielić przerwania i zadania?

W takim projekcie najlepiej zaplanować czasowo cały system i trzymać się architektury nieblokującej: w przerwaniach wykonuj obsługę danych i inicjuj kolejne kroki, a ciężkie obliczenia typu FFT przenieś do RTOS-a albo do prostego scheduler/PendSV; jeśli nie używasz RTOS, oprzyj logikę o maszyny stanów zamiast delayów i aktywnego czekania [#12470604][#12471306][#12473120] Jeśli ISR robi tylko ustawianie flagi, to samo przerwanie jest zbędne; lepiej, żeby obsługa ADC od razu pobierała wynik, przełączała kanał i startowała następną konwersję, a komunikację i inne szybkie źródła zdarzeń utrzymywała możliwie krótko [#12466368][#12464931] Dla większych projektów część osób rekomenduje RTOS, bo daje kolejki, semafory i łatwiejsze zarządzanie kodem, pamiętając o kosztach RAM i typowych problemach współdzielenia zasobów [#12473120] Podejście pętli zdarzeń jest sensowne raczej w mniejszych projektach; przy usypianiu procesora i wielu asynchronicznych zdarzeniach robi się trudne do poprawnego zrobienia i łatwo o opóźnienia albo zgubienie zdarzeń [#12474490][#12474850]
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
  • #1 12464799
    marcin1990
    Poziom 14  
    Posty: 152
    Pomógł: 10
    Witam,
    Do tej pory pisałem wiele programów na uC według jednej znanej mi koncepcji która sprawdzała się w mniejszych projektach.
    Koncepcja polegała na tym aby przerwania były jak najkrótsze więc zazwyczaj ograniczało się to do ustawiania flag np.
    PPRZEWANIE_TIMERA1{
    Flag_timer1=1;
    }

    Po czym w głównej pętli sprawdzałem każdą zmienną i wykonywałem stosowne działania w stylu:
    
    void main (){
    
    while(1){
    
    if(Flag_timer1=1){
    //odśwież wyświetlacz
    //przelicz coś itp;
    }
    
    if( GetKeys()){
    //idź do menu 
    //zmień stan portu itp.
    }
    
    //i tak dalej 
    
    }
    }
    

    Koncepcja była niezła, sprawdzała się w prostych aplikacjach ale do czasu. Obecnie piszę dość duży projekt i już wiem, że ta koncepcja się nie sprawdzi.

    Mam do obsłużenia 6 DAC`ów 6 ADC do obliczenia z każdego RMS może jakieś FFT Rozbudowane menu, komunikacje z PC, 2 wyświetlacze graficzne i zastanawiam się jak do tego pojeść. Czy może ktoś polecić jakąś literaturę/strony na ten temat
    ? Nie chodzi tu o to jak obsłużyć dane peryferie czego jest wiele w internecie tylko jak projektować większe programy. Mam nadzieje, że obejdzie się bez RTS. Oczywiście mogę to rozbić na kilka uC ale nie chcę iść na skróty.
  • #2 12464809
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    Nie no bez przesady rozbijać na kilka uC -> użyć jakiegoś RTOSa.
  • #3 12464839
    Konto nie istnieje
    Konto nie istnieje  
  • #4 12464931
    Tomasz Gumny
    Poziom 28  
    Posty: 890
    Pomógł: 102
    Ocena: 34
    Ja staram się w przerwaniach zrobić wszystko co możliwe bez zbędnego oczekiwania. Na podstawie uzyskanych w przerwaniach kompletnych danych, w głównej pętli aktualizowany jest stan wyświetlaczy.
    Na przykład w przerwaniu od ADC odczytuję wynik konwersji, ustawiam kolejny kanał i uruchamiam konwersję. Jeśli wynik jest alarmujący, np. za wysoki prąd lub temperatura, natychmiast jest wykonywana odpowiednia instrukcja.
    Przerwanie od timera aktualizuje stan liczników czasu, odczytuje stan klawiszy i inicjuje lub sekwencyjnie wykonuje akcje z nimi związane.
    Przerwania od portów komunikacyjnych są zwykle najkrótsze, tzn. ustawiają tylko znaczniki, ale w razie potrzeby obsługują od razu bufor.
    Procedury obsługi robię zawsze tak, żeby zajmowały jak najmniej czasu procesora, często wykorzystuję gotowe tablice, instrukcje switch lub rozbijanie jakiejś czynności na kilka etapów.
  • #5 12466368
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Jeżeli jedyną czynnością wykonywaną w przerwaniu jest ustawienie znacznika, to to przerwanie jest całkowicie zbędne - w końcu każdy timer czy UART ustawia sprzętowo bit, który można programowo testować w pętli głównej.

    Przy czasochłonnych obliczeniach takich jak FFT sensownie jest użyć RTOSa. Gdyby nie to, struktura z kilkoma przerwaniami bez pętli głównej byłaby właściwa. Pętla zdarzeń - to raczej rozwiązanie dla początkujących i do b. prostych programów demonstracyjnych,a nie do rzeczywistego użytku.
  • #6 12467048
    marcin1990
    Poziom 14  
    Posty: 152
    Pomógł: 10
    Może trochę przesadziłem z tymi krótkimi przerwaniami.
    Oczywiście, że w przypadku przerwania z ADC zapisuje wynik w tablicy (ewentualnie go przeliczam), zmieniam kanał itp. Głównie chodzi mi o "problem" z bardziej czasochłonnymi operacjami typu fft, wykresy, ewentualne filtry. Timera używam np. do odświeżania wyświetlacza, obsługi DS18b20 który potrzebuje prawie sekundę na pomiar(zazwyczaj robię to na osobnym timerze sprzętowym lub softowym).
    Chodzi mi o to, że nie jestem pewien czy pętla zdarzeń to właściwy kierunek rozwoju ?
    Czy jest coś lepszego niż wykonywanie pętli zdarzeń i sprawdzania wielu warunków za każdym obiegiem a łatwiejszego niż RTOS ? Przyznam, się że jeszcze nie bawiłem się żadnym RTOS i zawsze podchodziłem do tego z dystansem.
  • #7 12467126
    dondu
    VIP Zasłużony dla elektroda
    Posty: 13906
    Pomógł: 1292
    Ocena: 809
    Odpowiadając na pytanie z tematu, to pisz tak program, by w pętli głównej było tylko usypianie mikrokontrolera.
    Tak, usypianie choćby do najprostszego trybu. To ograniczenie wymusi na Tobie pisanie programu w oparciu wyłącznie o przerwania. Ja tak robię i bardzo chwalę sobie tę metodę :)
  • #9 12467158
    dondu
    VIP Zasłużony dla elektroda
    Posty: 13906
    Pomógł: 1292
    Ocena: 809
    Freddie Chopin napisał:
    No to czekamy na jakiś program który w przerwaniach liczy FFT, a wynik formatuje przy użyciu sprintf().

    Ależ, żaden problem - od tego są właśnie ISR_NOBLOCK, czyli dokładnie to co dzieje się w pętli głównej pisząc "w zwykły sposób". Zysk jest w sposobie pisania pozostałej części programu, wymuszonej przez oparcie całości o przerwania. Chcieć, to móc ...
  • #10 12467242
    Konto nie istnieje
    Konto nie istnieje  
  • #11 12467285
    dondu
    VIP Zasłużony dla elektroda
    Posty: 13906
    Pomógł: 1292
    Ocena: 809
    Nawet jeżeli nie jest (nie wiemy o jakim kompilatorze mowa), to nie ma takiej potrzeby, by był - to kwestia organizacji programu.
    Znając ograniczenia odpowiednio pisze się oprogramowanie, a nie odwrotnie :)
  • #12 12467335
    Konto nie istnieje
    Konto nie istnieje  
  • #13 12467358
    dondu
    VIP Zasłużony dla elektroda
    Posty: 13906
    Pomógł: 1292
    Ocena: 809
    Pisanie w ten sposób, na pewno nie jest łatwe, ale autor pyta właśnie o coś "z wyższej półki". Należy brać pod uwagę zazębianie się procesów w budowanym układzie, ale przecież właśnie po to wymyślono przerwania, by je wykorzystywać. Ja to robię "na maksa" przez co łatwo jest mi budować np. urządzenia zasilane z baterii o długim czasie pracy. Ten nawyk przydaje się później także w prostych projektach, choć w ich przypadku oczywiście jego zastosowanie można stawać pod znakiem zapytania.

    Wspomniałeś o sprintf() - nie sprawdzałem, ale nie natknąłem się na ten problem ani w GCC, ani w HI-Tech C Microchipa. Może dlatego, że nigdy do takiej sytuacji nie dopuszczam, ale nieświadomie. :)
  • #14 12467380
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Freddie:

    Mam parę projektów, w których były potrzebne czasochłonne obliczenia, ale w sumie stopień komplikacji nie uzasadniał użycia RTOS. Na Cortexach można to rozwiązać zastępując pętlę zdarzeń obsługą PendSV, w której robi się to, co trwa długo. PendSV zgłasza się w obsłudze przerwania, której efektem mają być te dłuższe obliczenia lub inne czynności.

    W ten sposób elegancko wyrzucamy pętlę zdarzeń, procesor śpi kiedy nie ma nic do roboty, liczy się wtedy kiedy trzeba bez blokowania przerwań (PendSV chodzi na najniższym priorytecie). Jest ślicznie i bez RTOSa.
  • #15 12468182
    Tuxlab
    Poziom 13  
    Posty: 54
    Pomógł: 3
    Ocena: 2
    Z mojej dość długiej praktyki wynika jeden wniosek : nie da się napisać dobrego i optymalnego programu bez znajomości asemblera. Procedury obsługi przerwań napisane w kodzie działają zupełnie inaczej niż procedury napisane np. w C. Wynika to z ograniczeń i kompromisów które przyjęli twórcy kompilatora.

    pozdrowienia
    T
  • #16 12468239
    stanleysts
    Poziom 27  
    Posty: 838
    Pomógł: 115
    Ocena: 2
    Oczywiście, że można napisać dobry kod bez znajomości ASM.
  • #17 12468459
    marcin1990
    Poziom 14  
    Posty: 152
    Pomógł: 10
    Podsumowując każdy ma inny sposób pisania:
    stanleysts i BlueDraco - RTOS
    Tomasz Gumny i albertb - Klasyczna pętla zdarzeń (z odpowiednią obsługą przerwań) i powinno być ok
    dondu i BlueDraco - wsystko na przerwaniach i PendSV a w "mainie" usypianie procka

    Przyznam, że starałem się uniknąć RTOS i może się uda. Program będzie pisany na STM32F303 tak więc mocy obliczeniowej starczy. Na początek spróbuję zrobić co się da na przerwaniach a większe obliczenia w mainie. Jak się uda będzie super jak się nie uda to będzie trzeba się nauczyć RTOS`a
  • #18 12470375
    Konto nie istnieje
    Konto nie istnieje  
  • #19 12470604
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    marcin1990 napisał:
    Program będzie pisany na STM32F303 tak więc mocy obliczeniowej starczy.

    Pod warunkiem, że oprogramowanie będzie napisane w sposób nie blokujący - bez żadnych martwych pętli oczekiwania, delayów programowych, itp...
    Jeżeli Twoj program będzie inicjatorem działań, to można go ładnie ułożyć tak, żeby wszystko wykonywało się w miarę po kolei (lub przeplatalo). Jeżeli inicjatorami niektórych działań będą zdarzenia zewnętrzne mogące pojawić się asynchronicznie, to należy liczyć się z możliwością spiętrzeń - kiedy wszystkie te zdarzenia pojawią się jednocześnie.

    Tak ogólnie się zastanawiam, czy czasem pisania programu nie powinno się zaczynać od analizy czasowej - ile jakie procedury i obsługi zajmują i jak je wszystkie ładnie ułożyć, żeby nie występowały jednocześnie (o ile to możliwe).
  • #20 12471306
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Jado_one napisał:

    Tak ogólnie się zastanawiam, czy czasem pisania programu nie powinno się zaczynać od analizy czasowej - ile jakie procedury i obsługi zajmują i jak je wszystkie ładnie ułożyć, żeby nie występowały jednocześnie (o ile to możliwe).


    Nie zastanawiaj się. Właśnie od tego należy zacząć każdy projekt z uC, najpierw sprzętu, a potem oprogramowania. :)
  • #21 12471353
    tmf
    VIP Zasłużony dla elektroda
    Posty: 14318
    Pomógł: 2090
    Ocena: 2205
    Ja tam sobie myślę, że po to wymyślono kilka stylów programowania, aby dobierać optymalny do problemu, a nie na siłę próbować rozwiązać problem naginając go do "jedynie słusznego" stylu. Z pewnością część problemów świetnie rozwiązuje się tak jak kolega dondu napisał, wrzucając wszystko w przerwania. Niemniej jeśli problem wymaga ISR_NOBLOCK i jakiś sztucznych działań to mi się zapala czerwone światełko. Może wtedy lepiej jest wykorzystać RTOS? Zresztą RTOS RTOSowi nierówny. Można mieć cały OS, a można mieć prosty scheduler, który zajmuje się przełączaniem tasków, które coś tam sobie liczą (np. owe FFT), a całą resztę mieć w przerwaniach, zupełnie poza takim prostym RTOSem. Dzięki temu mamy połączenie przerwań z kilkoma taskami dla których możemy sobie ładnie priorytety ustalić, a wyniki ich działania potraktować tak, jakby to były właśnie nieblokujące przerwania.

    Dodano po 3 [minuty]:

    BlueDraco napisał:
    Jado_one napisał:

    Tak ogólnie się zastanawiam, czy czasem pisania programu nie powinno się zaczynać od analizy czasowej - ile jakie procedury i obsługi zajmują i jak je wszystkie ładnie ułożyć, żeby nie występowały jednocześnie (o ile to możliwe).


    Nie zastanawiaj się. Właśnie od tego należy zacząć każdy projekt z uC, najpierw sprzętu, a potem oprogramowania. :)


    Ja bym do tego dodał kilka iteracji :) Czyli myślimy jak softwarowo coś rozwiązać na ogólnym poziomie, gdzie są wąskie gardła, pod to dobieramy mniej więcej sprzęt, następnie wchodzimy nieco głębiej w soft, zastanawiamy się czy pewne elementy nie da się rozwiązać sprzętowo (lepszy dobór procka posiadającego odpowiednie wspomaganie), wracamy do programu itd.
    Inaczej możemy wybrać 32-bitowego kolosa, w BGA208, a może się okazać, że to co zajmuje czas da się rozwiązać całkowicie sprzętowo, a odpowiedni moduł ma ATTiny :)
  • #22 12472350
    marcin1990
    Poziom 14  
    Posty: 152
    Pomógł: 10
    Cytat:
    Pod warunkiem, że oprogramowanie będzie napisane w sposób nie blokujący - bez żadnych martwych pętli oczekiwania, delayów programowych, itp...

    To się rozumie samo przez się :)

    Cytat:
    Czyli myślimy jak softwarowo coś rozwiązać na ogólnym poziomie, gdzie są wąskie gardła, pod to dobieramy mniej więcej sprzęt, następnie wchodzimy nieco głębiej w soft, zastanawiamy się czy pewne elementy nie da się rozwiązać sprzętowo (lepszy dobór procka posiadającego odpowiednie wspomaganie), wracamy do programu itd.

    Właśnie jestem na tym etapie. Mam już powybierany cały hardware, co do procka to wybór padł na STM32F303 z kilku względów. Przede wszystkim zrobiłem już klika projektów na STM`ach poza tym ten procek ma wszystko czego potrzebuje i jest w miarę przystępnej cenie.

    Cytat:
    Inaczej możemy wybrać 32-bitowego kolosa, w BGA208, a może się okazać, że to co zajmuje czas da się rozwiązać całkowicie sprzętowo, a odpowiedni moduł ma ATTiny

    Tu dochodzimy do etapu gdzie im więcej jesteśmy w stanie wycisnąć z procka tym "słabszego" procka potrzebujemy ale jest też druga strona medalu. Im więcej chcemy wycisnąć z procka tym więcej czasu potrzebujemy a jak wiadomo czas to pieniądz (choć po kilku projektach na pewno się to zwróci) .

    Dziękuje wszystkim za dobre rady, jutro biorę się za klepanie kodu i zobaczymy co wyjdzie.
  • #23 12472550
    Jado_one
    Poziom 22  
    Posty: 650
    Pomógł: 43
    Ocena: 12
    Myślę, że warto pokusić się o bardziej planowe i przemyślane pisanie programu niż:
    Cytat:
    klepanie kodu i zobaczymy co wyjdzie.

    Mam nadzieję, że to też skrót myślowy ;-)
  • #24 12472582
    marcin1990
    Poziom 14  
    Posty: 152
    Pomógł: 10
    Oczywiście, był to skrót myślowy. Własnie kończę projekt programu. Tak więc jak by nie patrzeć będzie to zaplanowane choć itak zapewne w trakcie pisania wyjdą jakieś nieprzewidziane przypadki.
  • #25 12473120
    grko
    Poziom 33  
    Posty: 1386
    Pomógł: 247
    Ocena: 141
    To i ja może dorzucę coś od siebie. Preferuję kilka technik programowania jeżeli chodzi moje projekty:

    1) Jeżeli kod programu będzie większy niż 128 KB i nie potrzebuję super low power to biorę RTOS. Dla dużych projektów RTOS sprawdza się idealnie.
    + łatwiej ogarnąć kod
    + duża część kodu jest już gotowa (kolejki, mutexy...)
    + można blokować na kolejkach i semaforach i nie stracimy real-time

    - typowe problemy OS (współdzielenie zasobów, deadlock)
    - RTOS pożera pamięć RAM
    - ciężko zrobić system wykorzystujący inne tryby low power niż instrukcja idle (w przypadku cortexa wfi)


    2) Dla mniejszych projektów używam pętli zdarzeń (takie moje rozwiązanie,podobne do ProtoThreds Dunkelsa):
    + mniejsze zużycie RAM
    + łatwiej zrealizować zaawansowany system low power

    - trudniej napisać drivery nie blokujące, np robimy driver SPI, który wykorzystuje DMA no i można do problemu podejść na 2 sposoby:
    * robimy funkcje spi_transfer, która odpala transfer DMA i oczekuje na jego zakończenie
    * robimy funkcje spi_transfer która nie oczekuje na zakończenie transferu DMA i mamy dodatkowa funkcje spi_is_finished która sprawdza czy transfer się zakończył
    (w tym przypadku trzeba robić w aplikacji dodatkowa maszynę stanów)

    Jeśli chodzi o funkcję sprintf to ja używam implementację z ucLinuxa i wiem że jest reentrant i działa mi na każdym procku (ARM, Blackfin, SHARC).
  • #26 12473874
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Chciałbym zobaczyć ten low power z pętlą zdarzeń. Tzn. kiedyś były takie procesory, na których to się dawało zrobić poprawnie, ale już wyginęły. Na ogół jest ALBO low power ALBO pętla zdarzeń. Trzecie wyjście to low power i gubienie zdarzeń w pętli. ;)

    Nie bardzo też rozumiem, jak użycie pętli zdarzeń zmniejsza zajętość RAM - magia jakaś...
  • #27 12473923
    Konto nie istnieje
    Konto nie istnieje  
  • #28 12473968
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    A który się nadaje do usypiania w niepustej pętli bez gubienia zdarzeń? Ja znam jedną rodzinę, która miała taką cechę.
  • #29 12473988
    grko
    Poziom 33  
    Posty: 1386
    Pomógł: 247
    Ocena: 141
    Cytat:

    Nie bardzo też rozumiem, jak użycie pętli zdarzeń zmniejsza zajętość RAM - magia jakaś...


    Może niejasno napisałem ale chodziło mi o mniejsze zużycie w stosunku do RTOS.

    Cytat:

    Chciałbym zobaczyć ten low power z pętlą zdarzeń. Tzn. kiedyś były takie procesory, na których to się dawało zrobić poprawnie, ale już wyginęły. Na ogół jest ALBO low power ALBO pętla zdarzeń. Trzecie wyjście to low power i gubienie zdarzeń w pętli.


    A to niby dlaczego ? Miałem projekt na cortexie Energi Micro i nie było jakichś problemów z wykorzystaniem trybów low power.
  • #30 12474015
    BlueDraco
    Specjalista - Mikrokontrolery
    Posty: 6479
    Pomógł: 939
    Ocena: 421
    Ja tylko pytam, jak można napisać niepustą pętlę główną z usypianiem procesora i gwarancją, że nie zgubimy zdarzenia lub nie opóźnimy istotnie jego obsługi (np. do czasu wystąpienia następnego zdarzenia). To nie jest wcale proste, a na ogół jest to wręcz niemożliwe. Nie mówię o przypadku, gdy w pętli czekamy na jedyne możliwe przerwanie, bo wtedy łatwiej i lepiej da się to zrobić bez tej pętli, z samym przerwaniem.

Podsumowanie tematu

LABEL_AI_GENERATED
W dyskusji poruszono wyzwania związane z zarządzaniem przerwaniami i zadaniami w dużych projektach na mikrokontrolerach (uC). Użytkownik opisał swoje dotychczasowe podejście, które polegało na minimalizacji czasu przerwań poprzez ustawianie flag, co sprawdzało się w mniejszych projektach, ale okazało się niewystarczające w przypadku bardziej złożonych aplikacji. Uczestnicy dyskusji sugerowali różne podejścia, w tym wykorzystanie systemów operacyjnych czasu rzeczywistego (RTOS) oraz pętli zdarzeń. Podkreślono znaczenie efektywnej obsługi przerwań, aby uniknąć zbędnych opóźnień, a także omówiono techniki takie jak PendSV w architekturze Cortex, które mogą pomóc w zarządzaniu czasochłonnymi obliczeniami. Wskazano również na konieczność analizy czasowej i planowania, aby zminimalizować ryzyko gubienia zdarzeń oraz opóźnień w reakcji na przerwania.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA