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

[STM32][C] Koniec transmisji DMA przez USART

07 Lut 2012 02:15 3080 8
  • Poziom 11  
    Przesyłam sobie dane przez RS485. Na linii są dwa urządzenia i oba mają mieć możliwość nadawania. W związku z tym, gdy jedno skończy nadawać, powinno wyłączyć układ sterujący linią. Niestety jest problem przy transmisji USARTem przez DMA. Przerwanie transfer complete generowane jest wtedy, gdy DMA skończy swoją pracę, natomiast jeszcze nie wszystko zdążyło się faktycznie wysłać. Gdy w tym przerwaniu wyłączam sterownik RS485, urządzenie odbiorcze nie dostaje dwóch ostatnich bajtów. Jeśli testowo usunę wyłączanie układu od RS485 to wszystko działa poprawnie, bajty się nie gubią, oczywiście z wyjątkiem tego, że drugie urządzenie nie może nadawać.
    Zastanawiam się, jak to rozwiązać. Można by w obsłudze przerwania transfer complete dodać krótkie opóźnienie, ale byłoby to trochę nieeleganckie. Można by też sprawdzać flagę USARTa, z tym, że skoro gubione są dwa ostatnie bajty, to sprawdzanie flagi rozwiązuje problem tylko przedostatniego bajtu, a ostatniego już nie. Można by też po prostu wysyłać o dwa bajty więcej, ale to chyba byłoby jeszcze brzydsze niż opóźnienie. Czy ktoś z Forumowiczów ma jakiś lepszy pomysł?
  • Poziom 23  
    Zawsze można po przerwaniu DMA odpalić timer i poczekać na jego przerwanie i tam przestawić stan linii, to rozwiązanie ma taką przewagę nad delayem, że nie blokuje programu.
  • Pomocny post
    Specjalista - Mikrokontrolery
    W przerwaniu od DMA oczekujesz na ustawienie flagi oznaczającej zakończenie transmisji (TC). Jeśli chcesz super elegancko, ale niekoniecznie lepiej, to w momencie rozpoczęcia transmisji DMA włącz przerwanie od tej flagi w module UART - nadajnik będziesz wyłączał dopiero w tym przerwaniu.

    4\/3!!
  • Poziom 11  
    Bardzo dziękuję za pomoc, skorzystałem ze sprawdzania flagi od DMA i śmiga. Swoją drogą, to nigdy bym nie pomyślał, że flaga ta ustawia się w innym momencie niż generowane jest przerwanie. A tu się okazuje, że TC to nie TC.
  • Specjalista - Mikrokontrolery
  • Poziom 11  
    Sprawdzałem flagę od DMA a nie od USARTa. Jak pisałem na początku, przy sprawdzaniu flagi od USARTa gubiło mi ostatni bajt. Teraz jednak przy sprawdzaniu flagi USARTa jest OK. Coś musiałem zmienić, ale nie mogę sobie przypomnieć co. W każdym razie teraz działa.
  • Poziom 11  
    A jednak nie działa poprawnie i problem nie był w moim roztargnieniu. Sytuacja jest taka, że pierwsza transmisja kończy się przedwcześnie, kolejne są w porządku. W pierwszej ucina się trochę ponad jeden bajt na końcu, tzn. przesyła się fragment przedostatniego i potem już nie.

    Wysyłanie:
    void startUSARTDMATransferTx(uint8_t * buffer) {
    DMA1_Channel4->CCR &= ~DMA_CCR1_EN;
    DMA1_Channel4->CMAR = (uint32_t)buffer;
    DMA1_Channel4->CNDTR = BUFFER_SIZE;
    GPIO_SetBits(GPIOA, GPIO_Pin_8);
    DMA1_Channel4->CCR |= DMA_CCR1_EN;
    }

    handler na koniec wysyłania:
    void DMA1_Channel4_IRQHandler(void)
    {
    //while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET){};
    while(!(USART1->SR & USART_FLAG_TC));
    DMA1->IFCR = DMA1_FLAG_TC4;
    GPIO_ResetBits(GPIOA, GPIO_Pin_8);
    }
  • Pomocny post
    Poziom 26  
    Spróbuj tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Poziom 11  
    Pomogło, dzięki!