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

FreeRTOS / Cortex-M3 - Jak najlepiej przekazywać dane przez kolejkę?

Freddie Chopin 03 Paź 2012 20:32 1563 4
REKLAMA
  • #1 11374361
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Witam!

    Pracuję obecnie nad zintegrowaniem stdio (streams) z różnymi peryferiami w ARMie (akurat jest to LPC1769) oraz z plikami (FatFS), a wszystko to "pod kontrolą" FreeRTOSa. Jak wiadomo (albo i nie), integracja taka to w głównej mierze napisanie własnych wersji syscalls - m.in. open, close, read, write. Za przykład problemu weźmy write - funkcja ma parametry typu bufor i rozmiar, zwraca ilość przesłanych faktycznie danych. Jeśli ilość przesłana jest mniejsza niż ilość żądana funkcja zostania wywołana raz jeszcze z odpowiednio przesuniętym buforem i zmniejszonym rozmiarem - innymi słowy będzie wywoływana dopóki nie uda się wysłać całych danych - ciągiem lub w kawałkach. No i teraz zakładając, że istnieje wątek który faktycznie zajmuje się wysyłaniem tych danych "gdzieś" (np. UART) należy w write() dane pakować do kolejki, a wątek sobie te dane odbierze.

    No i teraz powstaje pytanie - "jak lepiej?" - czy lepiej żeby w write() został zaalokowany (malloc()) jakiś odpowiednio duży bufor (powiedzmy że z ograniczeniami), w kolejce przesłany zostanie tylko wskaźnik na niego, a wątek odbierający po przesłaniu danych jest odpowiedzialny za skasowanie go, czy może lepiej zrobić tak, że kolejka ma swoje małe buforki (np o długośc 16-znaków) i w write() dane są partycjonowane na te poszczególne kawałki (po jednym kawałku na wywołanie write())?

    Jak jest lepiej, sensowniej, szybciej, bezpieczniej? Czy ktoś miał już kiedyś taki dylemat i doszedł do jakichś konstruktywnych wniosków?

    Z góry dzięki!

    4\/3!!
  • REKLAMA
  • Pomocny post
    #2 11375059
    gaskoin
    Poziom 38  
    Posty: 4159
    Pomógł: 436
    Ocena: 102
    Najlepiej jakby każda wartość wkładana do kolejki była wskaźnikiem (albo strukturą, która ma wskaźnik etc.) na dane. Jest to chyba najwygodniejsze/najprostsze w obsłudze. Żeby nie alokować pamięci non-stop i wciąż można zaadoptować Twój pomysł. Tzn stworzyć bufor raz (nawet nie musi być w takim przypadku dynamiczny) i przekazywać do kolejki strukturę, która zawiera długość danych oraz wskaźnik do odpowiedniego miejsca w tym buforze.
  • REKLAMA
  • #3 11375299
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Na razie mam zrobione pół-na-pół - odbiór danych z UARTa jest przez kolejkę która ma swoje małe buforki, wysyłanie danych do UARTa - przez dynamiczne wskaźniki. Zastanawiam się po prostu które z tych rozwiązań jest lepsze <;

    Swoją drogą jak fajnie jest móc zrobić tak:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    (;

    4\/3!!
  • REKLAMA
  • #4 11378963
    gaskoin
    Poziom 38  
    Posty: 4159
    Pomógł: 436
    Ocena: 102
    Na to pytanie ja Ci nie odpowiem, musisz zrobić pewne badanie:

    Ze statycznym buforem - bo alokacja pamięci wprowadza pewien narzut czasowy. To co musisz zrobić to tylko przydzielić do tego zadania pewien obszar pamięci na sztywno i poszczególne jego fragmenty opakowywać w strukturę. Tutaj pojawia się pytanie - co jeśli rozmiar bufora będzie zbyt mały ? Tzn nie wyślemy jeszcze żadnych danych a w buforze nie ma miejsca na nowe dane :) Można w sumie dopiero wtedy go realokować na większy. Rozwiązanie takie wprowadza trochę zamieszania, ponieważ trzeba się trochę bawić z indeksami i sprawdzać czy początek bufora został już opróżniony (żeby wstawić tam nowe dane jak na końcu już się nie da). Później można kombinować dalej, segmentować ten bufor itd, ale nie wiem czy jest to warte zachodu :) (pewnie nie)

    Drugie rozwiązanie jest chyba trochę lepsze, bo robisz malloca/new na tyle danych ile potrzebujesz, standardowo opakowujesz w strukturę i do kolejki. Pytanie - czy narzut czasowy alokacji pamięci będzie miał jakieś zasadnicze znaczenie ? Ja szczerze mówiąc nawet nie wiem jaki to rząd czasu na tę chwilę. W miejscu gdzie popychasz znaki na uart, musiałbyś tę pamięc zwolnić. Masz mniej zabawy i problemów typu "skończył się przeznaczony bufor". Jedyny problem jaki masz to narzut czasowy (pytanie jaki?) i brak pamięci w ogóle (czyli malloc zwracający nulla) :)

    Swoją drogą jak wrócę z pracy do domu to zrobię test, ile zajmuje malloc na CM3/CM4 dla różnych długości danych.
  • #5 11378973
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Jak sprawdzałem to dawno temu, to było około 100 cykli z tego co pamiętam (mowa o standardowym malloc() z newliba + syscalls z mojej stronki).

    EDIT: a co do tematu ogólnego, to przerobiłem to obydwie strony transmisji na dynamiczną alokację. W przypadku odbioru alokuję zawsze bufor o tym samym rozmiarze, nie chciało mi się na razie kombinować z realokacją, bo do tego są specjalne algorytmy - w jaki sposób "optymalnie" wybrać wartość przez którą mnożony jest poprzedni rozmiar bufora przy realokacji. Jak mi braknie tych 64kB RAMu to może będę kombinować, choć wtedy to jakaś część 128b mnie nie zbawi [;

    4\/3!!
REKLAMA