Portowanie Qt na STM32

Portowanie Qt na STM32Dzień dobry! Jesteśmy w projekcie Embox uruchomiliśmy Qt na STM32F7-Discovery i chcielibyśmy o tym opowiedzieć. Wcześniej opisaliśmy, jak udało nam się uruchomić OpenCV.

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ę post. 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 QEMUPortowanie Qt na STM32

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

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.

Portowanie Qt na STM32

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.

Portowanie Qt na STM32

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 artykuł 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:

Odtwarzaj wideo

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

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 TechTrain. Tam bardziej szczegółowo opowiemy i pokażemy Qt, OpenCV na mikrokontrolerach oraz inne nasze osiągnięcia.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster