Popularny post Elvis Napisano Styczeń 28, 2020 Popularny post Udostępnij Napisano Styczeń 28, 2020 Jak wspominałem na początku, wśród programów przykładowych dostarczanych przez producenta wyświetlacza znajdziemy przykłady nie tylko dla Arduino, ale również STM32. Działanie z Arduino Uno już widzieliśmy, czas wypróbować jak nasz moduł będzie działał z mikrokontrolerem firmy STMicroelectronics. Spis treści: Sterowanie wyświetlaczem TFT - część 1 - wstęp, podstawowe informacje Sterowanie wyświetlaczem TFT - część 2 - analiza problemu Sterowanie wyświetlaczem TFT - część 3 - testy prędkości na STM32 Sterowanie wyświetlaczem TFT - część 4 - własny program Sterowanie wyświetlaczem TFT - część 5 - optymalizacja programu Uruchomienie kodu przykładowego Okazuje się, że program przykładowy ma kilka wad. Projekt został przygotowany dla kompilatora firmy Keil (obecnie ARM) - nie jest to może wada jeśli mamy licencję, ale jeśli jej akurat nie mamy to użycie gcc byłoby znacznie tańsze. Druga sprawa to wybrany model mikrokontrolera oraz płytka. Przykłady są dla STM32F103 oraz płytki XNUCLEO-F103RB produkcji WaveShare oczywiście... Niestety F103 ma "tylko" 20KB pamięci RAM, a jak pamiętamy bufor ekranu to ponad 40KB. Do tego płytka WaveShare nie jest chyba zbyt popularna, a na pewno mniej niż oryginalne płytki serii Nucleo. Ten wpis brał udział konkursie na najlepszy artykuł o elektronice lub programowaniu. Sprawdź wyniki oraz listę wszystkich prac » Partnerem tej edycji konkursu (marzec 2020) był popularny producent obwodów drukowanych, firma PCBWay. Na szczęście przeniesienie projektu do darmowego środowiska STM32CubeIDE oraz zmiana płytki na inną to bardzo proste zadanie. Wybrałem moją ulubioną płytkę NUCLEO-L476RG Mikrokontroler STM32L476 ma podobne do F103 taktowanie maksymalne (80MHz), ale dużo więcej pamięci RAM, bo aż 128KB, chociaż "tylko" 96KB dostępne domyślnie. To jednak powinno w zupełności wystarczyć. Dodatkowa zaleta to o wiele łatwiejsza konfiguracja zegarów - w przypadku L4 wszystkie magistrale mogą pracować z taką samą prędkością jak rdzeń, więc będzie łatwiej wszystko liczyć. Utworzenie projektu w CubeIDE jest bardzo proste, szczególnie wykorzystując wtyczkę CubeMX. Sam kod wymaga dosłownie kosmetycznych zmian i po chwili mamy gotowy projekt. Mikrokontroler jest taktowany maksymalną częstotliwością, czyli 80MHz, natomiast SPI pracuje z dzielnikiem 8, co daje równe 10MHz. Program podobnie jak w wersji dla Arduino Uno prawie nie wykorzystuje pamięci RAM. Jak łatwo się domyślić jest bardzo podobny do omawianego poprzednio... producentowi chyba nie chciało się go optymalizować pod inną platformę. Przy okazji ciekawostka - kto zgadnie jak wygląda i działa wersja dla Raspberry Pi ? Ale żeby nie przynudzać - uruchamiam program i... Pewnie nie tego się spodziewaliśmy po STM32. Porównajmy czasy rysowania i kasowania: Ciężko w to uwierzyć, mamy 32-bitowy mikrokontroler pracujący z częstotliwością 80MHz, a rysowanie raptem odrobinę szybsze niż poprzednio. Natomiast kasowanie działa dużo wolniej... Warto upewnić się że to nie błąd pomiarowy, podłączamy analizator: Pierwszy wykres potwierdza, że kasowanie zajmuje mnóstwo czasu. Na środkowym widzimy, że SPI faktycznie działa na 10 MHz, natomiast ostatni pokazuje przyczynę problemu. Między wysyłanymi bajtami są jeszcze większe przerwy niż na Arduino Uno! Optymalizacja Okazuje się, że CubeIDE faktycznie pozwala szybko utworzyć projekt. Jednak mogą w nim czaić się pewne niespodzianki. Pierwsza to ustawienia optymalizacji kodu: Domyślnie wybrany jest brak optymalizacji, czyli opcja kompilatora -O0. Arduino używało chociaż optymalizacji wielkości programu, czyli -Os. Niestety bez optymalizacji nawet o wiele szybszy procesor może słabo działać. Zmieniamy więc ustawienia i oglądamy rezultat (film nagrany przy maksymalnej optymalizacji, czyli -O3): Różnica między -Os (po lewej) i -O3 (po prawej) nie jest zbyt znacząca, ale obie wersje działają o wiele szybciej niż domyślny brak optymalizacji: Na Arduino Uno rysowanie zajmowało ponad 1200ms, teraz 530ms - jest więc dużo lepiej. Z drugiej strony dwie klatki na sekundę szału nie robią. Do tego to kasowanie, może warto mu się chwilę przyjrzeć. Biblioteka HAL Chyba wszyscy słyszeli zarówno o bibliotece HAL dla STM32, jak i bibliotekach Arduino. Co więcej na pewno wszyscy słyszeli że pierwsza jest świetna, profesjonalna i wydajna, a druga wręcz przeciwnie. Może się jednak okazać że to nie zawsze jest prawda. Przykładowy program wysyła dane po jednym bajcie. Kod który został dostarczony przez WaveShare wygląda następująco: uint8_t SPI_Write_Byte(uint8_t value) { #if 0 HAL_SPI_Transmit(&hspi1, &value, 1, 500); // unsigned char Read_Buf; // HAL_SPI_TransmitReceive(&hspi1, &value, &Read_Buf,1, 500); // return Read_Buf; #elif 0 char i; for(i = 0;i < 8;i++){ SPI_SCK_0; if(value & 0X80) SPI_MOSI_1; else SPI_MOSI_0; Driver_Delay_us(10); SPI_SCK_1; Driver_Delay_us(10); value = (value << 1); } #else __HAL_SPI_ENABLE(&hspi1); SPI1->CR2 |= (1)<<12; while((SPI1->SR & (1<<1)) == 0) ; *((__IO uint8_t *)(&SPI1->DR)) = value; while(SPI1->SR & (1<<7)) ; //Wait for not busy while((SPI1->SR & (1<<0)) == 0) ; // Wait for the receiving area to be empty return *((__IO uint8_t *)(&SPI1->DR)); #endif } Jak widać ktoś tam coś grzebał... W przykładach używam pierwszej opcji, czyli po prostu wywołuję HAL_SPI_Transmit. Na Arduino Uno to samo realizowało wywołanie SPI.transfer(__DATA). Jeśli ktoś zajrzy do implementacji HAL_SPI_Transmit, zobaczy ponad 170 linii kodu, który ciężko nazwać optymalnym: Natomiast Arduino to kilka linijek w dodatku oznaczonych jako inline: To tłumaczy dlaczego programiści WaveShare coś próbowali grzebać w rejestrach... Im też nie podobało się tak wolne działanie biblioteki. Użycie biblioteki LL, albo rejestrów zamiast HAL daje w tym miejscu ogromne przyspieszenie działania. Jednak takie optymalizacje w sumie i tak nie mają zbyt wiele sensu. Trzeba się pogodzić z rzeczywistością i napisać własną wersję biblioteki wyświetlacza. Biblioteka LL Jeszcze mały update - napisałem że optymalizacja nie ma sensu... ale sam chciałem się upewnić że winny powolnemu działaniu jest HAL. Myślałem, że skasowałem wersję z biblioteką LL, ale w repozytorium git-a nic nie ginie. Udało mi się więc odszukać i przetestować wersję z LL zamiast HAL: Jak pamiętamy kasowanie ekranu wymaga przesłania 160 x 128 x 16 = 327680 bitów danych. Ponieważ SPI pracuje z częstotliwością 10MHz, więc w idealnej sytuacji transmisja zajmuje niecałe 33ms. Nasz kod nie jest idealny, ale jak widać użycie biblioteki LL pozwoliło ze 128ms zejść do 45ms. No i uzyskać 3 klatki na sekundę... Podsumowanie W tej części zobaczyliśmy jak na STM32 działa program demonstracyjny dostarczany przez producenta wyświetlacza. Wiemy już że sama zmiana mikrokontrolera nie wystarczy, konieczna będzie również zmiana programu. O tym jak napisać własny program oraz użyć bufora w pamięci RAM napiszę za chwilę, w kolejnej części. Spis treści: Sterowanie wyświetlaczem TFT - część 1 - wstęp, podstawowe informacje Sterowanie wyświetlaczem TFT - część 2 - analiza problemu Sterowanie wyświetlaczem TFT - część 3 - testy prędkości na STM32 Sterowanie wyświetlaczem TFT - część 4 - własny program Sterowanie wyświetlaczem TFT - część 5 - optymalizacja programu 4
BlackJack Styczeń 28, 2020 Udostępnij Styczeń 28, 2020 (edytowany) Cóż, spodziewałem się szczerze po serii tych artykułów zwyczajnie.... więcej, choć może dopiero zaskoczenie nadejdzie Tytuł powinien brzmieć trochę inaczej "Przegląd standardowych błędów w sterowaniu wyświetlaczem TFT". Ogólnie czyta się to fajnie, ale na razie udowodniono tylko że nawet 80MHz STM32 jak się nie zoptymalizuje kodu się zadławi. Czy kolega ma zamiar poruszyć temat optymalizacji i sztuczek graficznych? Bez tego właściwie jest tylko przegląd podstawowych błędów przy programowaniu grafiki, z użyciem gotowców. No i te nieszczęsne czyszczenie ekranu, a.. aż ciarki mnie przechodzą jak to czytam po raz 3, to podstawowy błąd jak chcemy mówić o jakieś wydajności, ekrany się nadpisuje, żeby nie tracić czasu na ich czyszczenie, i uniknąć migotania. To chyba pierwsza i podstawowa rzecz, jakiej się uczy człowiek który chce w ogóle zająć się wyświetlaniem grafiki. Edytowano Styczeń 28, 2020 przez BlackJack
Elvis Styczeń 29, 2020 Autor tematu Udostępnij Styczeń 29, 2020 Jest mi bardzo przykro jeśli kogoś rozczarowałem. Prawdę mówiąc planowałem tylko napisać artykuł o tym jak działa wyświetlacz TFT podłączony do STM32... a później jakoś tak samo wyszło, żeby trochę temat rozwinąć, porównać z Arduino itd. Nie miał to być kurs pisania bibliotek graficznych, ani kompendium wiedzy o grafice komputerowej. Natomiast co do czyszczenia ekranu i migotania, to właśnie o to chodziło żeby pokazać (i co ważniejsze zmierzyć) ile czasu zajmuje rysowanie oraz kasowanie zawartości ekranu.
Treker (Damian Szymański) Styczeń 29, 2020 Udostępnij Styczeń 29, 2020 @BlackJack jeśli jeszcze nie widziałeś to zerknij do kolejnej części artykułu - tam efekty są (jak dla mnie) świetne: https://forbot.pl/forum/topic/17524-sterowanie-wyswietlaczem-tft-czesc-4/
BlackJack Styczeń 29, 2020 Udostępnij Styczeń 29, 2020 (edytowany) 11 godzin temu, Treker napisał: @BlackJack jeśli jeszcze nie widziałeś to zerknij do kolejnej części artykułu - tam efekty są (jak dla mnie) świetne: https://forbot.pl/forum/topic/17524-sterowanie-wyswietlaczem-tft-czesc-4/ Czytałem. teraz naprawdę można powiedzieć, że efekt jest. Czekam na cz.5 o optymalizacji. Edytowano Styczeń 29, 2020 przez BlackJack
Pomocna odpowiedź
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ę »