Dzień dobry! Jesteśmy w projekcie uruchomiliśmy Qt na STM32F7-Discovery i chcielibyśmy o tym opowiedzieć. Wcześniej opisaliśmy, jak udało nam się uruchomić .
Qt — to wieloplatformowy framework, który obejmuje nie tylko komponenty graficzne, ale także takie rzeczy jak QtNetwork, zestaw klas do pracy z bazami danych, Qt for Automation (w tym do realizacji IoT) i wiele innych. Twórcy zespołu Qt z góry przewidzieli wykorzystanie Qt w systemach wbudowanych, dlatego biblioteki są dość dobrze konfigurowalne. Jednak do niedawna niewielu myślało o portowaniu Qt na mikrokontrolery, prawdopodobnie dlatego, że zadanie to wydaje się skomplikowane — Qt jest duże, a MCU małe.
Z drugiej strony, obecnie istnieją mikrokontrolery, które są przeznaczone do pracy z multimediami i przewyższają pierwsze Pentiumy. Około roku temu na blogu Qt pojawił się . Twórcy zrealizowali port Qt na system RTEMS i uruchomili przykłady z widgetami na kilku płytkach z systemem stm32f7. To nas zainteresowało. Było zauważalne, i sami twórcy o tym piszą, że Qt zwalnia na STM32F7-Discovery. Zastanawialiśmy się, czy uda nam się uruchomić Qt pod Embox, przy tym nie tylko narysować widget, ale uruchomić animację.
W Embox od dawna portowano Qt 4.8, więc postanowiliśmy spróbować na nim. Wybór padł na aplikację moveblocks — przykład sprężystej animacji.
Qt moveblocks na QEMU
Na początek konfigurujemy Qt z minimalnym zestawem komponentów potrzebnych do wsparcia animacji. W tym celu istnieje opcja “-qconfig minimal,small,medium …”. Podłącza ona plik konfiguracyjny z szeregiem makr — co włączyć / co wyłączyć. Po tej opcji dodajemy do konfiguracji inne flagi, jeśli chcemy coś dodatkowo wyłączyć. Oto przykład naszej .
Aby Qt działało, trzeba dodać warstwę zgodności z systemem operacyjnym. Jednym ze sposobów jest realizacja QPA (Qt Platform Abstraction). Za podstawę wzięliśmy gotowy już plugin fb_base z Qt, na bazie którego działa QPA dla Linuksa. W efekcie powstał mały plugin emboxfb, który zapewnia Qt ramkę buforową Embox’a, a dalej rysuje już tam bez pomocy zewnętrznej.
Tak wygląda tworzenie pluginu
QEmboxFbIntegration::QEmboxFbIntegration()
: fontDb(new QGenericUnixFontDatabase())
{
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
const char *fbPath = "/dev/fb0";
fbFd = open(fbPath, O_RDWR);
if (fbFd setPhysicalSize(QSize(fbWidth, fbHeight));
mScreens.append(mPrimaryScreen);
this->printFbInfo();
}
Oto jak będzie wyglądać odświeżenie
QRegion QEmboxFbScreen::doRedraw()
{
QVector rects;
QRegion touched = QFbScreen::doRedraw();
DPRINTF("QEmboxFbScreen::doRedrawn");
if (!compositePainter) {
compositePainter = new QPainter(mFbScreenImage);
}
rects = touched.rects();
for (int i = 0; i drawImage(rects[i], *mScreenImage, rects[i]);
}
return touched;
}
W rezultacie, z włączoną optymalizacją kompilatora pod względem rozmiaru pamięci -Os, obraz biblioteki wyniósł 3.5 MB, co oczywiście nie mieści się w pamięci STM32F746. Jak już pisaliśmy w naszym innym artykule o OpenCV, na tej płycie mamy:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Ponieważ dla OpenCV już dodano wsparcie dla wykonywania kodu z QSPI, postanowiliśmy zacząć od załadowania obrazu Embox z Qt do QSPI w całości. I hurra, wszystko prawie natychmiast uruchomiło się z QSPI! Ale, jak w przypadku OpenCV, okazało się, że działa to zbyt wolno.

Dlatego zdecydowaliśmy, aby zrobić tak - najpierw kopiujemy obraz do QSPI, następnie ładujemy go do SDRAM i wykonujemy stamtąd. Z SDRAM stało się trochę szybciej, ale wciąż daleko od QEMU.

Następnie pojawił się pomysł włączenia jednostki zmiennoprzecinkowej - w końcu Qt wykonuje pewne obliczenia współrzędnych prostokątów w animacji. Próbowaliśmy, ale tutaj nie uzyskaliśmy zauważalnego przyspieszenia, chociaż w deweloperzy Qt twierdzili, że FPU przynosi znaczący wzrost wydajności dla "animacji przeciągania" na ekranie dotykowym. Może w moveblocks jest znacznie mniej obliczeń z użyciem zmiennoprzecinkowej, a to zależy od konkretnego przykładu.
Najbardziej efektywnym pomysłem okazało się przeniesienie bufora ramki z SDRAM do pamięci wewnętrznej. W tym celu zmieniliśmy wymiary ekranu z 480×272 na 272×272. Ponadto obniżyliśmy głębię koloru z A8R8G8B8 do R5G6B5, tym samym zmniejszając rozmiar jednego piksela z 4 do 2 bajtów. Uzyskaliśmy rozmiar bufora ramki 272 * 272 * 2 = 147968 bajtów. Dało to znaczące przyspieszenie, chyba najbardziej zauważalne, animacja stała się prawie płynna.
Ostatnią optymalizacją było uruchomienie kodu Embox z RAM, a Qt z SDRAM. W tym celu najpierw jak zwykle linkujemy statycznie Embox razem z Qt, ale segmenty text, rodata, data i bss biblioteki umieszczamy w QSPI, aby następnie skopiować je do SDRAM.
section (qt_text, SDRAM, QSPI)
phdr (qt_text, PT_LOAD, FLAGS(5))
section (qt_rodata, SDRAM, QSPI)
phdr (qt_rodata, PT_LOAD, FLAGS(5))
section (qt_data, SDRAM, QSPI)
phdr (qt_data, PT_LOAD, FLAGS(6))
section (qt_bss, SDRAM, QSPI)
phdr (qt_bss, PT_LOAD, FLAGS(6))
Dzięki uruchomieniu kodu Embox z ROM również uzyskaliśmy dostrzegalne przyspieszenie. W rezultacie animacja stała się dość płynna:

Już na samym końcu, przygotowując artykuł i próbując różnych konfiguracji Embox’a, okazało się, że Qt moveblocks świetnie działa również z QSPI i buforem ramki w SDRAM, a wąskim miejscem był właśnie rozmiar bufora ramki! Najwyraźniej, aby pokonać początkowe „slajdshow”, wystarczyło przyspieszenie o 2 razy dzięki banalnemu zmniejszeniu rozmiaru bufora ramki. Udało się osiągnąć taki wynik tylko poprzez przeniesienie kodu Embox do różnych szybkich pamięci, ale rezultat nie był na poziomie 2, lecz w przybliżeniu 1.5 razy.
Jak spróbować samemu
Jeśli posiadasz STM32F7-Discovery, możesz samodzielnie uruchomić Qt pod Embox. Możesz przeczytać, jak to zrobić w naszym .
Podsumowanie
Ostatecznie udało nam się uruchomić Qt! Trudność zadania, naszym zdaniem, jest nieco przesadzona. Oczywiście należy uwzględnić specyfikę mikrokontrolerów i w ogóle rozumieć architekturę systemów obliczeniowych. Wyniki optymalizacji wskazują na znany fakt, że najsłabszym ogniwem w systemie obliczeniowym jest nie procesor, a pamięć.
W tym roku weźmiemy udział w festiwalu . Tam bardziej szczegółowo opowiemy i pokażemy Qt, OpenCV na mikrokontrolerach oraz inne nasze osiągnięcia.
Źródło: habr.com
