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

[Solved] STM32L476 - FatFS + SDIO(DMA) zapis Multiblock?

conkerkh 28 Dec 2016 17:02 1704 22
  • #1
    conkerkh
    Level 7  
    Witam serdecznie,
    pracuje obecnie nad projektem gdzie zapisuje okresowo wieksze ilosci danych na karte pamieci w postaci binarnej gdzie mam z gory ustalona dlugość każdego zdania zawierajacego dane. Zaznaczę, że FatFS działa bezproblemowo z kartami uSD w trybie SDIO DMA do momentu kiedy nie chcemy zapisac nie wiecej niz 512B na raz. W momencie kiedy zapisywane jest wiecej niz 512B w plikach zaczynaja sie dziac dziwne rzeczy, podczas zapisu multiblock albo zjadany jest bajt albo dodawany efekt jest taki ze moje dane sa "przesuniete" o jeden bajt do przodu lub do tylu. Jak wiadomo biblioteki HALa nie sa znane z bycia perfekcyjnymi natomiast nie moge sie dopatrzyc nigdzie bledu, ktory moglby powodowac takie zachowanie. Czy macie jakies pomysly co moze byc przyczyna? Kod jest wygenerowany po czesci przez CubeMX.
  • Helpful post
    #2
    grko
    Level 33  
    @conkerkh Nie pokazałeś kodu. Mimo tego zabawię się w wróżbitę i obstawię, że transfery DMA nie są wyrównane do 4 bajtów.
  • #3
    michalko12
    MCUs specialist
    grko wrote:
    Mimo tego zabawię się w wróżbitę i obstawię, że transfery DMA nie są wyrównane do 4 bajtów.

    Ale tylko gdy ustawiony transfer jest 32b, a nie sądzę żeby w tym przypadku pojedynczy transfer był inny niż 8b.
  • #4
    conkerkh
    Level 7  
    Wedle tego co mowi RM0351:

    Quote:
    Program DMA2_Channel4 (or DMA2_Channel5) control register (memory increment, not peripheral increment, peripheral and source width is word size)


    czyli musimy ustawic na 32b jako ze mamy 32x32b fifo, nastepnie dlaczego zrodlo ma miec tez 32b nie wiem taki jest wymysl inzynierow ST bo tak sa napisane sterowniki, ktore jako bufor przyjmuja wskaznik uint32_t*. disk_write wyglada tak:

    Code: c
    Log in, to see the code


    Pytanie brzmi dlaczego fatfs dziala poprawnie gdy f_write() zapisuje mniej niz 512B a zle jak wiecej?
  • Helpful post
    #5
    grko
    Level 33  
    @conkerkh Z tego co pamiętam to fatfs nie zapewnia tego, że dane przekazywane do diskio_write są wyrównane do 4 bajtów. Na wszelki wypadek sprawdzałbym to.

    Code: c
    Log in, to see the code
  • #6
    conkerkh
    Level 7  
    Wyglada na to ze dobry trop sprawdzilem i faktycznie adres jest 0x2000b90d czyli przesuniety o jeden do przodu binarnie koncowka jest 01. Widocznie DMA wyrownuje do 00, jak to teraz najsensowniej naprawic zeby nie miec krzakow? malloc i kopiowac caly bufor czy jest jakis madrzejszy sposob na to?
  • #7
    grko
    Level 33  
    Malloc jest ok. Jak nie chcesz malloca to na stałe zarezerwuj bufor 512 bajty (wyrównany) i zapisuj po jednym bloku. To samo tyczy się funkcji odczytującej bloki.
  • #8
    conkerkh
    Level 7  
    Dobra dzieki wielkie Panowie, pomysle ktora opcje wybrac bo musze spedzac jak najmniej czasu na samym zapisie na karcie.
  • #9
    grko
    Level 33  
    To jeszcze dorzucę trochę własnych doświadczeń z kartami SD. Specyfikacja mówi, że karta po zleceniu zapisu jednego bloku może być zajęta przez 250ms. W przypadku wielu bloków jest to 500ms. Zdarza się to stosunkowo rzadko jednak należy być na takie coś przygotowanym (odpowiednie buforowanie).
  • #10
    User removed account
    User removed account  
  • #11
    conkerkh
    Level 7  
    Dynamicznie pvPortMalloc bo korzystam z freertos
  • #12
    User removed account
    User removed account  
  • #13
    grko
    Level 33  
    @Piotrus_999 Nie rozumiesz problemu. Sama biblioteka nie gwarantuje przekazania wyrównanego adresu do funkcji disk_write (w naszym przypadku SD_write). Więc Twoje rozwiązanie, zresztą bardzo słabe, nie zadziała.
  • #14
    User removed account
    User removed account  
  • #15
    grko
    Level 33  
    1. pvPortMalloc zwraca wyrównany adres. W naszym przypadku nawet do 8 bajtów więc cała akrobacja z wyrównywaniem jest niepotrzebna.
    2. Powtórzę po raz trzeci. Przekazując wyrównany/niewyrównany bufor do funkcji f_write nie dostajesz żadnej gwarancji odnośnie wyrównania adresu przekazywanego do funkcji disk_write. Najprostszy dowód na to:
    1. Zapis do pliku 3 bajtów.
    2. Zapis do tego samego pliku zapis do pliku 2048B danych: wykonają się:
    - read-modify-write 1 bloku
    - zapis 3 bloków danych od offsetu 509 z bufora wejściowego (ups, tutaj chyba DMA nie zadziała)
    - read-modify-write 1 bloku: ostatnie 3 bajty z bufora wejściowego

    No chyba, że Ty masz jakąś lepszą wersję biblioteki, która załatwia tego typu rzeczy.
  • #16
    Freddie Chopin
    MCUs specialist
    Piotrus_999 wrote:
    Skoro jest słabe to proszę wskaż te słabe miejsca.

    Proszę:

    http://man7.org/linux/man-pages/man3/malloc.3.html:
    Quote:
    The malloc() and calloc() functions return a pointer to the allocated memory, which is suitably aligned for any built-in type.


    W praktyce oznacza to, że funkcje te zawsze zwracają blok pamięci, który jest wyrównany do maksymalnego wyrównania wymaganego przez jakikolwiek typ na danej architekturze. A tak naprawdę to zwykle są wyrównane jeszcze bardziej.

    Nie rozwiązuje to żadnego problemu, ponieważ w rzeczywistości pewnie jest tak, że pamięć alokowana jest gdzieś indziej, a FatFs przekazuje do zapisu jedynie FRAGMENT zaalokowanego bloku.
  • #17
    grko
    Level 33  
    Freddie Chopin wrote:

    Nie rozwiązuje to żadnego problemu, ponieważ w rzeczywistości pewnie jest tak, że pamięć alokowana jest gdzieś indziej, a FatFs przekazuje do zapisu jedynie FRAGMENT zaalokowanego bloku.


    Z tego co pamiętam to FatFS ma wewnętrzny bufor o wielkości 1 bloku na którym będzie wykonywane read-modify-write. Przy zapisie większej ilości danych biblioteka przekaże bezpośrednio bufor wejściowy z pewnym offsetem. I tutaj już nie ma żadnej gwarancji co do wyrównania.
  • #18
    conkerkh
    Level 7  
    Piotr grko wytlumaczyl na czym polega problem, dodatkowo FatFS zaznacza ostatni sektor do ktorego zapisywal jako dirty chyba ze zostal on w calosci zapelniony, jesli nie to przy nastepnym zapisie jest dopelniany. Jesli sektor ten byl zapelniony ilosca bajtow nie rownana do 32 to masz problem bo po dopelnieniu tego sektora twoim buforem, wypluje ci niewyrownany adres znowu. Na tym polega caly problem. Generalnie to gdyby sie uwazalo na zapisywanie za kazdym razem ilosci bajtow wyrownanej do 32 to wtedy problem by nie wystepowal, ale takie zalozenie jest bez sensu. W efekcie zmodyfikowalem to tak:

    Code: c
    Log in, to see the code


    Wszystko dziala jak nalezy i szybko smiga.
  • #19
    Freddie Chopin
    MCUs specialist
    conkerkh wrote:
    Wszystko dziala jak nalezy i szybko smiga.

    Tylko że wyrównywanie bloków zwracanych przez malloc() nie ma żadnego sensu, ponieważ one już są wyrównane. Chyba że pvPortMalloc() jest równie durny jak większość kodu FreeRTOSa, to wtedy faktycznie trzeba...
  • #20
    User removed account
    User removed account  
  • #21
    Freddie Chopin
    MCUs specialist
    Piotrus_999 wrote:
    Proponuję zrobić co innego, powinno zalatwić sprawę:

    Widzę że jednak będziesz szedł w zaparte do końca świata i jeden dzień dłużej. Przecież fragment pliku ff.h który wrzuciłeś wyraźnie pokazuje, że ten bufor JEST WYRÓWNANY! Nawet komentarz o tym jest - "/* Force 32bits alignement */". (swoją drogą brawo dla ST za modyfikowanie kodu biblioteki i za dobry angielski (; )
  • #22
    grko
    Level 33  
    Nikt tu nie twierdzi, że wewnętrzny bufor w strukturze pliku jest niewyrównany. Tylko twierdzimy, że biblioteka może przekazać niewyrównany adres do funkcji diskio_write. Widać niektórym trzeba pisać 5 razy to samo.
  • #23
    conkerkh
    Level 7  
    Bufor wysylany do DMA musi byc wyrownany do 4 bajtow.