Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[STM32][STM32F407] - [DMA][USART]złączenie dwóch kanałów USART, wysłanie trzecim

17 Cze 2013 21:06 2241 4
  • Poziom 15  
    Witam, w tym temacie https://www.elektroda.pl/rtvforum/viewtopic.php?p=12427233#12427233 opisałem partyzanckie podejście - gdy się nad nim męczyłem zacząłem czytać o DMA.

    Pytanie: czy jest możliwe z użyciem wbudowanej w STM32 jednostki DMA zrealizowanie: weź dwa strumienie danych wejściowych z USARTów i wyślij trzecim?
  • Pomocny post
    Specjalista - Mikrokontrolery
    Na 99% nie. Można kombinować z auto-reload i transmisją jednego bajtu, o ile uda się przekonać DMA, że docelowy UART jest pamięcią, a nie peryferialem i o ile będziesz miał pewność, że nigdy dane nie będą równocześnie nadchodziły w takim tempie, żeby zapchać nadajnik. Czyli: nawet gdyby się udało, to jest to rozwiązanie wysoce niepewne i zawodne. Co za problem zrobić to uczciwie na przerwaniach? Ze 30 linii kodu powinno załatwić sprawę.

    Pierwszy błąd w Twoim kodzie z przerwaniami to to, że wskaźniki modyfikowane przez procedury przerwań UART nie są zadeklarowane jako volatile.
  • Poziom 35  
    BlueDraco napisał:
    [...]o ile uda się przekonać DMA, że docelowy UART jest pamięcią, a nie peryferialem[...]

    Nie trzeba go przekonywać. Dla DMA jest wszystko jedno pod jakie adresy mają się zapisać dane. Ale nie jest mu wszystko jedno, w jakich okolicznościach ma to robić. W przypadku UART TX, DMA request jest generowany za kazdym razem, gdy flaga TXE==1 (jesli UART ma włączony DMA oczywiscie). Wtedy DMA transferuje wartość spod adresu podanego w CMAR do adresu podanego w CPAR (dla DIR ustawionego na "read from memory").
    Adres podany w CPAR nie musi byc rejestrem DR w UARTcie ;] Można zrobić sobie "mem2mem" wyzwalany dowolną linią requestową z dowolnego peryferiala, tylko po co...

    My way:
    - dwa bufory, po jednym dla kazdego z UARTów wejsciowych
    - oba te UARTy mają włączony DMA RX w trybie circular
    - trzeci 'wysylkowy' UART z wlaczonym DMA TX, aktywowanym w arbitrze lub w przerwaniu od wlasciwego kanalu DMA, DMA w trybie liniowym (nie circular)
    - arbiter, który:
    a) na podstawie liczników CNDTR dowiaduje sie, ile danych przybyło od ostatniego sprawdzenia, dla obu buforów
    a') xoruj flage mowiaca o tym, ktory bufor wejsciowy ma zostac wlasnie wyslany
    b) konfiguruj DMA TX - zmien mu adres skad ma zaczac czytac, i wpisz mu ile ma do wyslania (i.e. czytaj bezposrednio z bufora, do ktorego zapisuje - przez DMA - inny UART!)
    b') detekcja 'przekrecenia' sie indeksu zapisu, jesli tak, konfiguruj DMA zeby wysylal tylko do konca bufora (DMA nie umie natywnie adresowac modulo, tryb circular to nie jest natywne adresowanie modulo...)
    c) zapamietac nowe indeksy odczytu dla buforow wejsciowych

    ...i to w sumie tyle.
    Implementacja arbitra w przerwaniu od DMA TX pozwoli na 'lawine', odczyt bedzie chcial za wszelka cene dogonic zapis /sam z siebie/ (jedno wywolanie arbitra pociagnie za soba nastepne i nastepne, az nie braknie danych do wysylania).
    Jest wtedy potrzebny dodatkowa funkcja wywolywana cyklicznie (np. co 200ms), ktora sprawdzi, czy DMA TX pracuje, i jesli nie, to recznie ustaw flage pending w NVICu zeby wymusic wykonanie sie arbitra...

    P.S. dla czepliwych
    oczywiscie powyzszy sposób nie jest fail-safe, i mozliwosc przepelniania sie buforow jesli sumarycznie danych przybywa szybciej niz sie ich pozbywa. I te przepelnienia sa trudne do detekcji (wrecz niemozliwe, bo automat). Ale 'do pewnych predkosci' odbioru bedzie dzialac. Wystarczy zagwarantowac, ze strumien wyjsciowy bedzie o 5% szybszy niz suma strumieni wejsciowych, a overflow nie wystapi nigdy.
  • Specjalista - Mikrokontrolery
    Chciałbym tylko nieśmiało zauważyć, że ten programowy arbiter plus obsługa DMA - to więcej kodu niż obsługa transmisji na przerwaniach z buforem cyklicznym bez DMA. ;)
  • Poziom 35  
    Kodu więcej - ale co się bardziej opłaca ;] Zmarnować kilkadziesiąt cykli co kilkadziesiąt ms, czy kilkanaście cykli co 100us (dla 115200)?
    Kazde wejscie w ISRa to 12 cykli. Jesli 2 UARTy ładują znak co 100us, to srednio co 50us masz przerwanie. W kazdej sekundzie na samo wejscie do ISRów idzie 240k cykli... + (szacuję) 10 cykli kodu /co znak/ *20k = 200k. W sumie 440k cykli. Plus obsługa TXa...

    Dobrze napisany arbiter nie pożre więcej niz 50 cykli. A nie ma powodu wywolywac go czesciej niz co 10ms, co daje nam 5k cykli/s. Za całość ;] (zakladam brak efektu 'lawiny', nie ma zastosowania w tym przypadku, wiec tylko timer). Wystarczy zastosowac odpowiednio glebokie bufory.

    No więc 5k cykli vs. 440k cykli (sam RX!) - zwycięża? ;]