Jó napot Benne vagyunk a projektben
A Qt egy többplatformos keretrendszer, amely nemcsak grafikus összetevőket tartalmaz, hanem olyan dolgokat is, mint a QtNetwork, az adatbázisokkal való munkavégzéshez szükséges osztályok, a Qt for Automation (beleértve az IoT megvalósítását is) és még sok más. A Qt csapata proaktívan foglalkozott a Qt beágyazott rendszerekben történő használatával, így a könyvtárak meglehetősen konfigurálhatók. Azonban egészen a közelmúltig kevesen gondoltak arra, hogy a Qt-t mikrokontrollerekre portolják, valószínűleg azért, mert egy ilyen feladat nehéznek tűnik - a Qt nagy, az MCU-k kicsik.
Másrészt jelenleg léteznek olyan mikrokontrollerek, amelyeket multimédiával való együttműködésre terveztek, és jobbak az első Pentiumoknál. Körülbelül egy éve jelent meg a Qt blog
A Qt 4.8-at már régóta portolták az Emboxra, ezért úgy döntöttünk, hogy kipróbáljuk rajta. A Moveblocks alkalmazást választottuk – ez egy példa a ruganyos animációra.
Qt mozgásblokkok a QEMU-n
Először is beállítjuk a Qt-t, ha lehetséges, az animáció támogatásához szükséges minimális összetevőkészlettel. Ehhez van egy "-qconfig minimal,small,medium..." opció. Összekapcsolja a Qt konfigurációs fájlját sok makróval - mit kell engedélyezni / mit tiltani. Ezen opció után további jelzőket adunk a konfigurációhoz, ha valami mást szeretnénk letiltani. Íme egy példa a miénkről
A Qt működéséhez hozzá kell adni egy operációs rendszer kompatibilitási réteget. Az egyik módja a QPA (Qt Platform Abstraction) megvalósítása. A Qt-ben található kész fb_base plugint vettük alapul, amely alapján működik a QPA for Linux. Az eredmény egy emboxfb nevű kis plugin, ami ellátja a Qt-t az Embox framebufferével, majd külső segítség nélkül oda is rajzol.
Így néz ki egy plugin létrehozása
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();
}
És így fog kinézni az újrarajzolás
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;
}
Ennek eredményeként a fordító -Os memóriaméretre való optimalizálása mellett 3.5 MB-osnak bizonyult a könyvtár kép, ami természetesen nem fér bele az STM32F746 fő memóriájába. Ahogy azt az OpenCV-ről szóló másik cikkünkben már írtuk, ez a tábla a következőket tartalmazza:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Mivel a QSPI kód végrehajtásának támogatása már hozzáadásra került az OpenCV-hez, úgy döntöttünk, hogy kezdjük azzal, hogy betöltjük a teljes Embox c Qt képet a QSPI-be. És hurrá, szinte azonnal elkezdődött minden a QSPI-től! De mint az OpenCV esetében, kiderült, hogy túl lassan működik.
Ezért úgy döntöttünk, hogy így csináljuk - először a képet másoljuk a QSPI-be, majd betöltjük az SDRAM-ba, és onnan hajtjuk végre. SDRAM-ból kicsit gyorsabb lett, de még mindig messze van a QEMU-tól.
Ezután felmerült egy ötlet egy lebegőpontos beépítésre – elvégre a Qt elvégzi a négyzetek koordinátáinak számításait az animációban. Megpróbáltuk, de itt nem kaptunk látható gyorsulást, bár bent
A leghatékonyabb ötlet az volt, hogy a framebuffert az SDRAM-ból a belső memóriába helyezték át. Ennek érdekében a képernyő méreteit nem 480x272-re, hanem 272x272-re tettük. A színmélységet is csökkentettük A8R8G8B8-ról R5G6B5-re, így egy pixel méretét 4-ről 2 bájtra csökkentettük. A kapott framebuffer mérete 272 * 272 * 2 = 147968 bájt. Ez jelentős gyorsulást adott, talán a legszembetűnőbb, hogy szinte sima lett az animáció.
A legutóbbi optimalizálás az Embox kód futtatása volt a RAM-ból és a Qt kód az SDRAM-ból. Ehhez először a szokásos módon statikusan összekapcsoljuk az Emboxot a Qt-vel, de a könyvtár szövegét, rodata-ját, adatait és bss-szegmenseit elhelyezzük a QSPI-ben, hogy aztán az SDRAM-ba másoljuk.
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))
Az Embox kód ROM-ból történő végrehajtásával is érezhető gyorsulást kaptunk. Ennek eredményeként az animáció meglehetősen sima lett:
A legvégén a cikk előkészítése és a különböző Embox konfigurációk kipróbálása közben derült ki, hogy a Qt moveblocks remekül működik QSPI-ből SDRAM-ban lévő framebufferrel, a szűk keresztmetszet pedig pont a framebuffer mérete volt! Nyilvánvalóan a kezdeti „diavetítés” leküzdéséhez elegendő volt a 2-szeres gyorsítás a keretpuffer méretének banális csökkentése miatt. De nem lehetett ilyen eredményt elérni, ha csak az Embox kódot vittük át különböző gyors memóriákra (a gyorsulás nem 2, hanem körülbelül 1.5-szeres volt).
Hogyan próbáld ki magad
Ha rendelkezik STM32F7-Discovery-vel, saját maga is futtathatja a Qt-t az Embox alatt. Ennek mikéntjét olvashatja nálunk
Következtetés
Ennek eredményeként sikerült elindítani a Qt! A feladat összetettsége véleményünk szerint némileg eltúlzott. Természetesen figyelembe kell vennie a mikrokontrollerek sajátosságait, és általában meg kell értenie a számítógépes rendszerek architektúráját. Az optimalizálási eredmények rámutatnak arra a jól ismert tényre, hogy egy számítástechnikai rendszerben nem a processzor, hanem a memória jelenti a szűk keresztmetszetet.
Idén is részt veszünk a fesztiválon
Forrás: will.com