Skocz do zawartości

Użycie DMA i UART generuje dodatkowe znaki w ciągu, STM32F103


mobbed

Pomocna odpowiedź

Cześć, już od dłuższej chwili walczę z problemem wysyłania danych przez UART z użyciem DMA, skończyły mi się pomysły, więc może ktoś inny będzie mógł mi pomóc. Mianowicie, mam klasę uart'a (projekt jest w C++), w której znajduje się bufor danych:

char tx_buffer[MAX_TX_BUFFER_SIZE];

Przy każdym użyciu funkcji wysyłającej dane, przekazany cstring jako argument kopiowany jest do tego bufora i następnie wykonywana jest procedura opisana w dokumentacji dotycząca użycia DMA i UART'a.  

        void DmaTransferProcedure()
        {
            dma->SetPeripheralAddr((uint32_t)&usart_periphal->DR);
            dma->SetMemoryAddr((uint32_t)tx_buffer);
            dma->SetDataSize(strlen(tx_buffer));
            usart_periphal->SR &= ~(USART_SR_TC);
            dma->Enable();
        }

Gdy DMA zakończy pełny transfer to wywoływane jest przerwanie i w tym przerwaniu wyłączany jest moduł + procedura resetująca flagi klasy, etc.

    if (CheckBit(DMA1->ISR, DMA_ISR_TCIF7))
    {
        DMA1->IFCR |= 1 << DMA_IFCR_CGIF7_Pos;
        dispatcher_list[static_cast<uint8_t>(Dispatchers::USART2_Dispatcher)]->DataTransmittedEvent();
    }
virtual void DataTransmittedEvent() override
{
	if (dma != nullptr) dma->Disable();
            
	memset(tx_buffer, 0, MAX_TX_BUFFER_SIZE);
	is_enabled = false;
	usart_periphal->CR1 &= ~(USART_CR1_TE);
	usart_periphal->CR1 &= ~(USART_CR1_UE);
}

I teraz ciekawy fakt, gdy wysyłam tekst "TEST\n\r" a rozmiar bufora wynosi 10, to wszystko działa jak należy, gdy tylko zwiększę bufor do np. 100 to ciągle dodawane są do tekstu losowe znak, jakby były wstawiane zamiast \n\r, ale to nie jest chyba żadna zależność:

image.thumb.png.374bb49194648a61caa912c46b7ca666.png

Moja pula rozwiązań i pomysłów się wyczerpała, gdzieś czegoś po prostu nie zauważam, albo przeoczyłem czytając dokumentację. Dzięki za każdą pomoc 😉

@edit Doczytałem gdzieś w dokumentacji, że mogą być dostawiane flagi błędów do każdego bajtu, przez chwilę myślałem, że to to, ale jak włączyłem przerwania przy błędzie transmisji to nigdy się ono nie wywołuje, więc pewnie odpada.

Edytowano przez mobbed
Link do komentarza
Share on other sites

(edytowany)
7 minut temu, ethanak napisał:

Nie widzę jak cstring jest kopiowany do bufora. Na pewno razem z kończącym NUL?

 

Tak.  Tekst przekazuje jako cstring "".

void SendData(const char *data)
{
	strncpy(tx_buffer, data, MAX_TX_BUFFER_SIZE);
  	...

 

Edytowano przez mobbed
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

(edytowany)
8 minut temu, ethanak napisał:

A możesz w jakiś sposób sprawdzić, co naprawdę siedzi w tx_buffer?

Tak, mogę na debugu - tak wygląda bufor po skopiowaniu, natomiast oczywiście na debugu wszystko działa jak skaczę po breakpointach, zapomniałem dopisać wyżej.

image.thumb.png.0701d2336d0846d2eeebf76f7bdd88ae.png

Edytowano przez mobbed
Link do komentarza
Share on other sites

(edytowany)

Może skoro na debugu działa, to może gdzieś wsadzić po prostu opóźnienie w pętli... 😄

@edit Okej...dodałem krótkie opóźnienie po wyłączeniu DMA i wszystko działa, ale dlaczego to nie mam zielonego pojęcia.

Edytowano przez mobbed
Link do komentarza
Share on other sites

28 minut temu, mobbed napisał:

Okej...dodałem krótkie opóźnienie po wyłączeniu DMA i wszystko działa, ale dlaczego to nie mam zielonego pojęcia.

To nie jest rozwiązanie. Nie po to robisz coś na DMA, żeby potem pętle opóźniające robić. Natomiast to podsuwa pomysł co się faktycznie dzieje.

Do zakończenia transmisji wykorzystaj zdarzenie od detekcji zajętości linii. USART_SR_IDLE. W przerwaniu od zakończenia transmisji DMA USART uruchamiasz przerwanie od detekcji linii i w ten sposób dopiero ustawiasz flagę zakończenia transmisji. Wtedy to dopiero bufory są puste. Jeśli tego nie sprawdzasz i za szybko uruchamiasz kolejną transmisję to śmieci z pozostałej zostają w buforze i lądują na magistralę.

Link do komentarza
Share on other sites

(edytowany)
54 minuty temu, Zealota napisał:

To nie jest rozwiązanie. Nie po to robisz coś na DMA, żeby potem pętle opóźniające robić. Natomiast to podsuwa pomysł co się faktycznie dzieje.

Do zakończenia transmisji wykorzystaj zdarzenie od detekcji zajętości linii. USART_SR_IDLE. W przerwaniu od zakończenia transmisji DMA USART uruchamiasz przerwanie od detekcji linii i w ten sposób dopiero ustawiasz flagę zakończenia transmisji. Wtedy to dopiero bufory są puste. Jeśli tego nie sprawdzasz i za szybko uruchamiasz kolejną transmisję to śmieci z pozostałej zostają w buforze i lądują na magistralę.

A przerwanie IDLE nie działa czasami tylko dla linii odbiorczej?

Dla TX:

image.thumb.png.9a7554fedbf20496a897c298d4ce366b.png

Dla RX:

image.thumb.png.607dda46ecc2eaf0e61685f70edc91df.png

Edytowano przez mobbed
Link do komentarza
Share on other sites

Chwila, chyba pomyliłem procki i procedurę.. 

Clue to jest badanie TC i trzeba je zrobić poprawnie:

image.thumb.png.de95fdce4259f129a76b3f681e7213d7.png

Nie widzę u Ciebie nic co by sprawdzało flagę USART_SR_TC.

Przerwanie od TC powinno świadczyć od całkowitego zakończenia transmisji.

Link do komentarza
Share on other sites

(edytowany)
6 godzin temu, Zealota napisał:

Chwila, chyba pomyliłem procki i procedurę.. 

Clue to jest badanie TC i trzeba je zrobić poprawnie:

image.thumb.png.de95fdce4259f129a76b3f681e7213d7.png

Nie widzę u Ciebie nic co by sprawdzało flagę USART_SR_TC.

Przerwanie od TC powinno świadczyć od całkowitego zakończenia transmisji.

No właśnie przerwanie od TC wykonuje się przed przerwaniem od DMA o skończeniu przesyłania danych i tak w sumie mało co mi to daje, bo jedyna manipulacja to ustawienie priorytetów DMA nad UART, a nie bardzo mi to leży na rękę. 

Ogólnie wydaje mi się to dziwne, że mając te same priorytety przerwanie o zakończonej transmisji jest wywoływane zanim DMA prześle potwierdzenie, że przesłał wszystkie bajty...

@edit Chociaż dokumentacja pokazuje, że sytuacja powinna być kompletnie odwrotna niż opisuje, no ale ja ewidentnie dostaję przerwanie od TC przed DMA.

@edit2 Dobra, długa walka ale się udało. Jak widać, na załączonym przez Ciebie zdjęciu załączenie bitu odpowiedzialnego na transmisje generuje stan wysoki na linii TXE, pomimo, że nic nie jest przesyłane to wrzuca też wtedy automatycznie flagę TC na high i generuje przerwanie od TC, które sypało mi resztę kodu, bo nie sprawdzałem w przerwaniu przy fladze TC czy UART jest w ogóle włączony....Dodałem wcześniej wspomnianego if'a, a w elsie dałem po prostu odczytanie i wpisanie nulla do rejestru DR co kasuje dwie wyżej wspomniane flagi TC i TXE no i potem transmisja przez DMA przebiega identycznie jak na poniższym zdjęciu.

image.thumb.png.72d1c39daeaedf0cf9456b0241ddef6d.png

Edytowano przez mobbed
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.