Dobrý deň Sme v projekte
Qt je multiplatformový rámec, ktorý zahŕňa nielen grafické komponenty, ale aj také veci ako QtNetwork, sadu tried pre prácu s databázami, Qt for Automation (vrátane implementácie internetu vecí) a oveľa viac. Tím Qt bol aktívny pri používaní Qt vo vstavaných systémoch, takže knižnice sú celkom konfigurovateľné. Až donedávna však len málo ľudí premýšľalo o portovaní Qt na mikrokontroléry, pravdepodobne preto, že takáto úloha sa zdá náročná - Qt je veľké, MCU sú malé.
Na druhej strane, v súčasnosti existujú mikrokontroléry určené na prácu s multimédiami a lepšie ako prvé Pentiá. Asi pred rokom sa objavil blog Qt
Qt 4.8 je už dlhší čas portovaný na Embox, tak sme sa rozhodli ho na ňom vyskúšať. Vybrali sme aplikáciu moveblocks - príklad pružnej animácie.
Pohyblivé bloky Qt na QEMU
Na začiatok nakonfigurujeme Qt, ak je to možné, s minimálnou sadou komponentov potrebných na podporu animácie. Na tento účel existuje možnosť „-qconfig minimal,small,medium...“. Spája konfiguračný súbor z Qt s mnohými makrami - čo povoliť / čo zakázať. Po tejto voľbe pridáme do konfigurácie ďalšie príznaky, ak chceme zakázať niečo iné. Tu je príklad nášho
Aby Qt fungovalo, musíte pridať vrstvu kompatibility OS. Jedným zo spôsobov je implementácia QPA (Qt Platform Abstraction). Ako základ sme vzali hotový doplnok fb_base zahrnutý v Qt, na základe ktorého funguje QPA pre Linux. Výsledkom je malý plugin s názvom emboxfb, ktorý poskytuje Qt framebuffer Emboxu a potom sa tam kreslí bez akejkoľvek 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 (fbPath < 0) {
qFatal("QEmboxFbIntegration: Error open framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
qFatal("QEmboxFbIntegration: Error ioctl framebuffer %s", fbPath);
}
fbWidth = vinfo.xres;
fbHeight = vinfo.yres;
fbBytesPerLine = finfo.line_length;
fbSize = fbBytesPerLine * fbHeight;
fbFormat = vinfo.fmt;
fbData = (uint8_t *)mmap(0, fbSize, PROT_READ | PROT_WRITE,
MAP_SHARED, fbFd, 0);
if (fbData == MAP_FAILED) {
qFatal("QEmboxFbIntegration: Error mmap framebuffer %s", fbPath);
}
if (!fbData || !fbSize) {
qFatal("QEmboxFbIntegration: Wrong framebuffer: base = %p,"
"size=%d", fbData, fbSize);
}
mPrimaryScreen = new QEmboxFbScreen(fbData, fbWidth,
fbHeight, fbBytesPerLine,
emboxFbFormatToQImageFormat(fbFormat));
mPrimaryScreen->setPhysicalSize(QSize(fbWidth, fbHeight));
mScreens.append(mPrimaryScreen);
this->printFbInfo();
}
A takto bude vyzerať prekreslenie
QRegion QEmboxFbScreen::doRedraw()
{
QVector<QRect> rects;
QRegion touched = QFbScreen::doRedraw();
DPRINTF("QEmboxFbScreen::doRedrawn");
if (!compositePainter) {
compositePainter = new QPainter(mFbScreenImage);
}
rects = touched.rects();
for (int i = 0; i < rects.size(); i++) {
compositePainter->drawImage(rects[i], *mScreenImage, rects[i]);
}
return touched;
}
Výsledkom bolo, že so zapnutou optimalizáciou kompilátora pre veľkosť pamäte -Os sa obraz knižnice ukázal ako 3.5 MB, čo sa samozrejme nezmestí do hlavnej pamäte STM32F746. Ako sme už písali v našom inom článku o OpenCV, táto doska má:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Keďže podpora pre spustenie kódu z QSPI už bola pridaná do OpenCV, rozhodli sme sa začať načítaním celého obrazu Embox c Qt do QSPI. A hurá, všetko začalo takmer okamžite od QSPI! Ale rovnako ako v prípade OpenCV sa ukázalo, že funguje príliš pomaly.
Preto sme sa rozhodli urobiť to takto - najprv skopírujeme obrázok do QSPI, potom ho načítame do SDRAM a odtiaľ spustíme. Z SDRAM sa to stalo trochu rýchlejšie, ale stále ďaleko od QEMU.
Ďalej bol nápad zahrnúť plávajúcu desatinnú čiarku - koniec koncov, Qt robí nejaké výpočty súradníc štvorcov v animácii. Snažili sme sa, ale tu sme sa nedočkali žiadneho viditeľného zrýchlenia, hoci v
Najúčinnejším nápadom bolo presunúť framebuffer z SDRAM do internej pamäte. Aby sme to dosiahli, vytvorili sme rozmery obrazovky nie 480x272, ale 272x272. Znížili sme aj farebnú hĺbku z A8R8G8B8 na R5G6B5, čím sme zmenšili veľkosť jedného pixelu zo 4 na 2 bajty. Výsledná veľkosť framebufferu je 272 * 272 * 2 = 147968 bajtov. To poskytlo výrazné zrýchlenie, možno najvýraznejšie, animácia sa stala takmer plynulou.
Poslednou optimalizáciou bolo spustenie kódu Embox z RAM a Qt kódu z SDRAM. Aby sme to urobili, najprv, ako obvykle, staticky prepojíme Embox spolu s Qt, ale textové, rodata, data a bss segmenty knižnice umiestnime do QSPI, aby sme ich potom skopírovali 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))
Spustením Embox kódu z ROM sme sa dočkali aj citeľného zrýchlenia. V dôsledku toho bola animácia celkom hladká:
Na samom konci, pri príprave článku a skúšaní rôznych konfigurácií Emboxu, sa ukázalo, že Qt moveblocks funguje skvele od QSPI s framebufferom v SDRAM a prekážkou bola práve veľkosť framebufferu! Na prekonanie počiatočnej „slideshow“ zrejme stačilo 2-násobné zrýchlenie v dôsledku banálneho zníženia veľkosti framebufferu. Ale prenosom iba Embox kódu do rôznych rýchlych pamätí sa takýto výsledok dosiahnuť nedal (zrýchlenie nebolo 2, ale asi 1.5-násobné).
Ako to vyskúšať sami
Ak máte STM32F7-Discovery, môžete spustiť Qt pod Emboxom sami. Ako sa to robí, si môžete prečítať u nás
Záver
V dôsledku toho sa nám podarilo spustiť Qt! Zložitosť úlohy je podľa nášho názoru trochu prehnaná. Prirodzene, musíte brať do úvahy špecifiká mikrokontrolérov a vo všeobecnosti pochopiť architektúru počítačových systémov. Výsledky optimalizácie poukazujú na známy fakt, že prekážkou vo výpočtovom systéme nie je procesor, ale pamäť.
Tento rok sa festivalu zúčastníme
Zdroj: hab.com