Dobrý deň! Sme v projekte spustili Qt na STM32F7-Discovery a chceli by sme o tom porozprávať. Už sme hovorili, ako sa nám podarilo spustiť .
Qt — to je multiplatformový framework, ktorý zahŕňa nielen grafické komponenty, ale aj rôzne funkcie ako QtNetwork, sadu tried pre prácu s databázami, Qt for Automation (vrátane aplikácií pre IoT) a mnoho ďalšieho. Vývojári tímu Qt dopredu zohľadnili jeho použitie vo vstavaných systémoch, takže knižnice sa veľmi dobre konfigurovateľné. Napriek tomu do nedávna sa málokto zamýšľal nad portovaním Qt na mikrokontroléry, pravdepodobne preto, že táto úloha vyzerá zložitá — Qt je veľké, MCU malé.
Na druhej strane, v súčasnosti existujú mikrokontroléry určené na prácu s multimédiami, ktoré prekonávajú prvé Pentiumy. Asi pred rokom sa na blogu Qt objavil . Vývojári spravili port Qt pre OS RTEMS a spustili ukážky s widgetmi na niekoľkých doskách s riadením stm32f7. To nás zaujalo. Bolo zrejmé, a sami vývojári o tom píšu, že Qt spomaľuje na STM32F7-Discovery. Zaujímalo nás, či dokážeme spustiť Qt pod Embox, pričom nie len vykresliť widget, ale spustiť animáciu.
V Embox bola už dávno portovaná Qt 4.8, tak sme sa rozhodli to vyskúšať. Vybrali sme aplikáciu moveblocks — príklad pružinovej animácie.
Qt moveblocks na QEMU
Na začiatok konfigurovane Qt s minimálnym súborom komponentov potrebných pre podporu animácie. Na to existuje možnosť "-qconfig minimal,small,medium …". Pripojí konfiguračný súbor z Qt s množstvom makier — čo zapnúť / čo vypnúť. Po tejto možnosti pridávame do konfigurácie ďalšie príznaky, ak chceme niečo ďalšie vypnúť. Tu je príklad našej .
Aby Qt fungovalo, je potrebné pridať vrstvu kompatibility s OS. Jeden z spôsobov je implementovať QPA (Qt Platform Abstraction). Za základ sme vzali už hotový plugin fb_base z Qt, na základe ktorého funguje QPA pre Linux. Nakoniec sme dostali malý plugin emboxfb, ktorý poskytuje Qt framebuffer Emboxu, pričom ďalej to vykresľuje už bez vonkajšej pomoci.
Takto vyzerá vytvorenie 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();
}
Takto bude vyzerať prekreslenie.
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;
}
Nakoniec, s povolenou optimalizáciou kompilátora na veľkosť pamäti -Os, bol obraz knižnice veľký 3.5 MB, čo sa samozrejme nevojde do hlavnej pamäte STM32F746. Ako sme už písali v našom inom článku o OpenCV, na tejto doske máme:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Keďže pre OpenCV už bola pridaná podpora spúšťania kódu z QSPI, rozhodli sme sa začať tým, že sme nahrali obraz Embox s Qt do QSPI úplne. A hurá, všetko sa takmer okamžite spustilo z QSPI! Ale, ako to bolo aj v prípade OpenCV, ukázalo sa, že funguje príliš pomaly.

Preto sme sa rozhodli robiť to takto – najskôr skopírujeme obraz do QSPI, potom ho nahráme do SDRAM a odtiaľ ho spustíme. Zo SDRAM to bolo o niečo rýchlejšie, ale aj tak ďaleko od QEMU.

Ďalej bola myšlienka zapnúť plávajúcu čiarku – veď Qt vykonáva niektoré výpočty súradníc štvorcov v animácii. Skúsili sme to, ale tu sme nezískali viditeľné zrýchlenie, hoci v vývojári Qt tvrdili, že FPU poskytuje významný nárast rýchlosti pre "dragging animation" na dotykovej obrazovke. Možno, že v moveblocks je podstatne menej výpočtov s plávajúcou čiarkou a to závisí od konkrétneho príkladu.
Najefektívnejšou myšlienkou sa ukázalo presunúť frame buffer z SDRAM do vnútornej pamäte. Na tento účel sme zmenili rozmer obrazovky z 480×272 na 272×272. Ešte sme znížili hĺbku farby z A8R8G8B8 na R5G6B5, čím sme zmenšili veľkosť jedného pixelu zo 4 na 2 bajty. Dostali sme veľkosť frame bufferu 272 * 272 * 2 = 147968 bajtov. To viedlo k významnému zrýchleniu, pravdepodobne najvýraznejšiemu, animácia sa stala takmer plynulou.
Poslednou optimalizáciou bolo vykonávanie kódu Embox z RAM a Qt zo SDRAM. Začali sme klasicky staticky linkovať Embox spolu s Qt, ale segmenty text, rodata, data a bss knižnice sme umiestnili do QSPI, aby sme ich neskôr mohli skopírovať 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))
Vykonávaním kódu Embox z ROM sme taktiež dosiahli cítené zrýchlenie. Nakoniec animácia bola dosť plynulá:

Na konci, keď sme pripravovali článok a skúšali rôzne konfigurácie Emboxu, sme zistili, že Qt moveblocks skvele funguje aj z QSPI s frame bufferom v SDRAM, a užším miestom bol práve rozmer frame bufferu! Zdá sa, že na prekonanie počiatočného "slideshow" stačilo zrýchlenie 2-krát vďaka jednoduchému zmenšeniu veľkosti frame bufferu. A dosiahnuť taký výsledok presunom len kódu Embox do rôznych rýchlych pamätí sa nepodarilo (zrýchlenie bolo nie 2, ale približne 1,5 krát).
Ako to skúsiť sám
Ak máte STM32F7-Discovery, môžete spustiť Qt pod Embox sami. Prečítajte si, ako sa to robí, na našej .
Záver
Nakoniec sa nám podarilo spustiť Qt! Úroveň obtiažnosti úlohy je podľa nás trochu prehnaná. Samozrejme, treba zohľadniť špecifiká mikrokontrolérov a celkovo rozumieť architektúre výpočtových systémov. Výsledky optimalizácie ukazujú na známy fakt, že najúzkym miestom v výpočtovom systéme nie je procesor, ale pamäť.
Tento rok sa zúčastníme na festivale . Tam podrobnejšie porozprávame a ukážeme Qt, OpenCV na mikrokontroléroch a naše ďalšie dosiahnuté úspechy.
Zdroj: habr.com
