Bună ziua! Suntem în proiect am lansat Qt pe STM32F7-Discovery și am dori să povestim despre asta. Anterior, am discutat despre cum am reușit să lansăm .
Qt este un cadru multiplatformă care include nu doar componente grafice, ci și funcționalități precum QtNetwork, un set de clase pentru lucrul cu baze de date, Qt for Automation (inclusiv pentru implementarea IoT) și multe altele. Dezvoltatorii echipei Qt au anticipat utilizarea Qt în sisteme încorporate, așa că bibliotecile sunt destul de configurabile. Totuși, până de curând, puțini s-au gândit la portarea Qt pe microcontrolere, probabil pentru că această sarcină pare complicată — Qt este mare, iar MCU-urile sunt mici.
Pe de altă parte, în prezent există microcontrolere destinate lucrului cu multimedia și care depășesc primele Pentium. Aproape un an în urmă, pe blogul Qt a apărut . Dezvoltatorii au făcut un port Qt pentru sistemul de operare RTEMS și au lansat exemple cu widget-uri pe mai multe plăci bazate pe stm32f7. Asta ne-a interesat. A fost evident, iar dezvoltatorii au menționat că Qt rulează lent pe STM32F7-Discovery. Ne-a făcut curioși dacă am putea rula Qt pe Embox, și nu doar să desenăm un widget, ci și să lansăm o animație.
Qt 4.8 a fost deja portat pe Embox de mult timp, așa că am decis să încercăm pe el. Am ales aplicația moveblocks — un exemplu de animație elastică.
Qt moveblocks pe QEMU
La început, configurăm Qt cu un set minim de componente necesare pentru a susține animația. Pentru asta există opțiunea “-qconfig minimal,small,medium …”. Aceasta conectează un fișier de configurare din Qt cu multe macro-uri — ce să includem / ce să dezactivăm. După această opțiune, adăugăm alte semne de configurare, dacă dorim să dezactivăm și alte funcționalități suplimentare. Iată un exemplu al nostru .
Pentru ca Qt să funcționeze, trebuie să adăugăm un strat de compatibilitate cu sistemul de operare. Una dintre metode este să implementăm QPA (Qt Platform Abstraction). Am folosit un plugin existent numit fb_base din Qt, pe baza căruia se bazează QPA pentru Linux. În rezultat, a fost creat un plugin mic numit emboxfb, care oferă Qt un framebuffer de la Embox, iar mai departe acesta așa desenează fără ajutor extern.
Acesta este modul în care arată crearea unui plugin
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();
}
Așa va arăta redarea
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;
}
Ca urmare a activării optimizării compilatorului pentru dimensiunea memoriei -Os, imaginea bibliotecii a rezultat în 3.5 MB, ceea ce, desigur, nu încap în memoria principală a STM32F746. Așa cum am menționat în alt articol despre OpenCV, pe această placă se găsește:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Deoarece pentru OpenCV a fost adăugat deja suportul pentru execuția codului din QSPI, am decis să începem prin încărcarea imaginii Embox cu Qt în QSPI în întregime. Și, iată, totul a început să ruleze aproape imediat din QSPI! Dar, la fel ca în cazul OpenCV, s-a dovedit că funcționează prea încet.

Prin urmare, am decis să facem astfel — mai întâi copiem imaginea în QSPI, apoi o încărcăm în SDRAM și ne executăm de acolo. Din SDRAM a devenit puțin mai rapid, dar totuși foarte departe de QEMU.

Apoi a apărut ideea de a activa punctul flotant — deoarece Qt efectuează anumite calcule ale coordonatelor pătratelor în animație. Am încercat, dar nu am obținut o accelerare vizibilă, deși în dezvoltatorii Qt au susținut că FPU aduce un beneficiu semnificativ în viteza pentru „animația de tragere” pe touchscreen. Poate că în moveblocks există semnificativ mai puține calcule cu punct flotant, și acest lucru depinde de exemplul concret.
Cea mai eficientă idee s-a dovedit a fi mutarea framebuffer-ului din SDRAM în memoria internă. Pentru aceasta, am setat dimensiunile ecranului la 272×272 în loc de 480×272. De asemenea, am redus adâncimea culorii de la A8R8G8B8 la R5G6B5, astfel micșorând dimensiunea unui pixel de la 4 la 2 bytes. Am obținut o dimensiune a framebuffer-ului de 272 * 272 * 2 = 147968 bytes. Aceasta a dus la o accelerare semnificativă, probabil cea mai notabilă; animația a devenit aproape fluidă.
Ultima optimizare a fost executarea codului Embox din RAM și a Qt din SDRAM. Pentru aceasta, am legat static Embox împreună cu Qt, dar am plasat segmentele text, rodata, data și bss ale bibliotecii în QSPI, astfel încât să le putem copia ulterior în 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))
Prin executarea codului Embox din ROM, am obținut și o accelerare considerabilă. În final, animația a devenit destul de fluidă:

Chiar spre sfârșit, când pregăteam articolul și încercam diferite configurații ale Embox-ului, am descoperit că Qt moveblocks funcționează minunat și din QSPI cu framebuffer-ul în SDRAM, iar punctul slab era chiar dimensiunea framebuffer-ului! Se pare că pentru a depăși „slideshow-ul” inițial, era suficientă o accelerare de 2 ori datorită simplului fapt de a reduce dimensiunea framebuffer-ului. Rezultatul astfel nu a fost obținut doar prin mutarea codului Embox în diferite memorii rapide (accelerarea a fost nu de 2, ci de aproximativ 1.5 ori).
Cum să încerci singur
Dacă aveți un STM32F7-Discovery, puteți rula Qt sub Embox personal. Puteți citi cum se face acest lucru pe site-ul nostru .
Concluzie
În final, am reușit să rulăm Qt! Dificultatea problemei, în opinia noastră, este oarecum exagerată. Natural, trebuie să ținem cont de specificitatea microcontrolerelor și să înțelegem de asemenea arhitectura sistemelor computaționale. Rezultatele optimizării indică asupra faptului cunoscut că cel mai strâmtor loc dintr-un sistem computațional nu este procesorul, ci memoria.
Anul acesta vom participa la festivalul . Acolo vom vorbi și demonstra mai detaliat despre Qt, OpenCV pe microcontrolere și alte realizări ale noastre.
Sursa: habr.com
