Skocz do zawartości

[STM32F411 + HAL] Ustawianie i wyzwalanie transmisji SPI po DMA


Pomocna odpowiedź

Napisano (edytowany)

Pracuję właśnie nad jednym projektem, w którym próbuję stworzyć generowanie monochromatycznego sygnału VGA, w celu wyświetlania terminalu tekstowego na starym monitorze. Założenie jest taki, że sygnały synchronizacji (HSYNC/VSYNC) będą generowane za pomocą timerów i PWM, a koniec "back porch" będzie wyznaczany przez OC na tych samych timerach. Same piksele będą natomiast wypychane na kanał jeden z kanałów RGB (konkretnie GREEN, bo zależy mi na zielonym tekście) za pomocą SPI, poprzez DMA, z bufora zawierającego aktualną linię.

W chwili obecnej sytuacja wygląda następująco:

Następuje wywołanie callbacka obsługującego horizontal back porch -> wołam HAL_SPI_Transmit_DMA(&hspi1, scanline, SCANLINE_LEN) -> SPI zaczyna wysyłać piksele.

Problem polega na tym, że HAL_SPI_Transmit_DMA to dość ciężka funkcja, która zawiera w sobie trochę logiki i chwilę się wykonuje. Efekt jest taki, że linie zaczynają być rysowane za późno i ich początek pojawia się dopiero w okolicy 1/4 ekranu.

Prawidłowe podejście powinno wyglądać następujaco:

Kończymy rysowanie poprzedniej linii (początek front porch) -> Ustawiamy kolejną transmisję DMA -> Następuje przejście do kolejnej linii i sygnał HSYNC -> Następuje wywołanie callbacka obsługującego horizontal back porch -> Inicjuję wcześniej ustawioną transmisję, żeby SPI zaczął jak najszybciej wysyłać piksele z bufora.

Ktoś orientuje się w jaki sposób coś takiego osiągnąć za pomocą HAL?

Edytowano przez atlantis86
  • 2 miesiące później...
  • 2 tygodnie później...
(edytowany)
Dnia 4.06.2026 o 21:50, _LM_ napisał:

Czy DMA w F411 ma przerwanie podczas wysyłania połowy bufora? 

Z tego co kojarzę ma. Finalnie jednak udało mi się rozwiązać problem w inny sposób.

Tak naprawdę złożyło się tam kilka różnych problemów. Po pierwsze trzeba było zupełnie przepisać funkcje obsługi przerwań timerów (HSYNC,VSYNC) i DMA, pozbywając się wszelkich zależności od HAL. Po drugie pewnych zmian wymagało buforowanie kolejnych linii, aby te były wypełniane do przodu, w pętli głównej, z odpowiednim zapasem. Pomocna okazała się też rezygnacja z FreeRTOS i przepisanie kodu na bare metal. Ostatnią rzeczą była rezygnacja z DMA w SDIO, bo tutaj dochodziło do konfliktu, który powodował drobną latencję i minimalne przesunięcie generowania niektórych linii.

Edytowano przez atlantis86
5 godzin temu, atlantis86 napisał:

Tak naprawdę złożyło się tam kilka różnych problemów. Po pierwsze trzeba było zupełnie przepisać funkcje obsługi przerwań timerów (HSYNC,VSYNC) i DMA, pozbywając się wszelkich zależności od HAL

Taka cena wygody, HAL nie jest zbyt oszczędny czasowo i w zajętości kodu wynikowego. 

5 godzin temu, atlantis86 napisał:
Dnia 4.06.2026 o 21:50, _LM_ napisał:

Czy DMA w F411 ma przerwanie podczas wysyłania połowy bufora? 

Z tego co kojarzę ma. Finalnie jednak udało mi się rozwiązać problem w inny sposób.

Dlatego pytałem bo pierwszą myślą było podwójne buforowanie.

5 godzin temu, atlantis86 napisał:

Ostatnią rzeczą była rezygnacja z DMA w SDIO, bo tutaj dochodziło do konfliktu, który powodował drobną latencję i minimalne przesunięcie generowania niektórych linii.

To ciekawe ale aż tak na STM32 się nie znam i pewnie nie zaradziłbym, to już wymaga wnikliwej analizy ds-a.

(edytowany)
4 godziny temu, _LM_ napisał:

Dlatego pytałem bo pierwszą myślą było podwójne buforowanie.

To był od początku docelowy plan. Na początku po prostu testowałem kod na stałym patternie linii (a potem na stałym framebufferze zapisanym we flashu) i już na tym etapie widziałem problemy wnikające z pozostałych kwestii.

4 godziny temu, _LM_ napisał:

To ciekawe ale aż tak na STM32 się nie znam i pewnie nie zaradziłbym, to już wymaga wnikliwej analizy ds-a.

Tutaj kwestia jest dość prozaiczna - SPI użyty do generowania obrazu i SDIO dzielą ten sam moduł DMA.
Tutaj też liczyłem się z tym, że mogą być problemy i założyłem, że w najgorszym razie po prostu będę wygaszał ekran podczas operacji wymagających dostępu do karty. Czytanie z pliku faktycznie powodowało, że tekst zaczynał "latać". Niestety był także jeszcze jeden problem - najwyraźniej sterownik karty SD regularnie się z nią komunikuje, przesyłając jakieś niewielkie ilości danych. Objawiało się to tym, że jedna konkretna linia była przesunięta o kilka pikseli, a więc coś opóźniało jej transmisję. Wykluczyłem problemy z przerwaniami o wyższym priorytecie, więc zostało tylko DMA. Najwyraźniej DMA było akurat cyklicznie zajmowane rozmawianiem z kartą i ta konkretna linia, w tym konkretnym momencie musiała chwilę poczekać. Po usunięciu DMA z konfiguracji SDIO problem momentalnie zniknął. 

Edytowano przez atlantis86
  • Lubię! 1

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...