Dobrý den! Jsme v projektu spustili Qt na STM32F7-Discovery a rádi bychom o tom pohovořili. Dříve jsme již popisovali, jak se nám podařilo spustit .
Qt je multiplatformní framework, který zahrnuje nejen grafické komponenty, ale také věci jako QtNetwork, sadu tříd pro práci s databázemi, Qt for Automation (včetně implementace IoT) a mnoho dalšího. Vývojáři týmu Qt se předem připravili na použití Qt v embedded systémech, proto jsou knihovny velmi dobře konfigurovatelné. Avšak do nedávna se málo kdo zamýšlel nad portováním Qt na mikrokontroléry, pravděpodobně proto, že tato úloha vypadá složitě — Qt je velké, MCU malé.
Na druhé straně v současné době existují mikrokontroléry určené pro multimediální práci, které překonávají první Pentia. Před asi rokem se na blogu Qt objevil . Vývojáři provedli port Qt pro OS RTEMS a spustili příklady s widgety na několika deskách pod správou stm32f7. To nás zaujalo. Bylo zřejmé, a sami vývojáři o tom píší, že Qt má na STM32F7-Discovery určité zpoždění. Zajímalo nás, zda dokážeme spustit Qt pod Embox, a to nejen nakreslit widget, ale spustit animaci.
V Emboxu už dlouho portovali Qt 4.8, takže jsme se rozhodli to zkusit. Vybrali jsme aplikaci moveblocks — příklad pružné animace.
Qt moveblocks na QEMU
Nejprve konfigurováme Qt co nejvíce s minimálním souborem komponent, potřebných pro podporu animace. K tomu existuje volba “-qconfig minimal,small,medium …”. Ta připojuje konfigurační soubor ze složení Qt s množstvím maker — co zapnout / co vypnout. Po této volbě přidáváme do konfigurace další vlajky, pokud nechceme něco vypnout navíc. Tady je příklad naší .
Aby Qt fungovalo, je třeba přidat vrstvu kompatibility s OS. Jeden z způsobů — implementovat QPA (Qt Platform Abstraction). Jako základ byl použit již hotový plugin fb_base ze složení Qt, na jehož základě funguje QPA pro Linux. Výsledkem je malý plugin emboxfb, který poskytuje Qt framebuffer Emboxu, a dále už to kreslí bez cizí pomoci.
Takto vypadá vytvoření 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 vypadat překreslení
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;
}
V důsledku aktivace optimalizace kompilátoru pro paměť -Os se obraz knihovny ukázal jako 3.5 MB, což rozhodně nepobírá hlavní paměť STM32F746. Jak jsme již psali v našem jiném článku o OpenCV, na této desce je:
- 1 MB ROM
- 320 kB RAM
- 8 MB SDRAM
- 16 MB QSPI
Protože byla do OpenCV již přidána podpora vykonávání kódu ze QSPI, rozhodli jsme se začít tím, že jsme natáhli obraz Embox s Qt do QSPI vcelku. A hurá, vše se téměř okamžitě spustilo z QSPI! Ale stejně jako v případě OpenCV se ukázalo, že to funguje příliš pomalu.

Proto jsme se rozhodli dělat to takto — nejprve kopírujeme obraz do QSPI, pak ho nahráváme do SDRAM a odtud se vykonáváme. Z SDRAM bylo trochu rychlejší, ale stále daleko od QEMU.

Dále byl nápad zapnout plovoucí desetinnou čárku — protože Qt provádí některé výpočty souřadnic čtverců při animaci. Zkoušeli jsme to, ale nedosáhli jsme viditelného zrychlení, ačkoliv v vývojáři Qt tvrdili, že FPU přináší významný nárůst rychlosti pro "animaci táhnutí" na dotykové obrazovce. Možná, že v moveblocks je výrazně méně výpočtů s plovoucí desetinnou čárkou, a to závisí na konkrétním příkladu.
Nejúčinnějším řešením se ukázalo být přesunutí framebufferu z SDRAM do interní paměti. Pro tento účel jsme změnili rozměry obrazovky z 480×272 na 272×272. Dále jsme snížili hloubku barev z A8R8G8B8 na R5G6B5, čímž jsme zmenšili velikost jednoho pixelu ze 4 na 2 bajty. Výsledný velikost framebufferu byla 272 * 272 * 2 = 147968 bajtů. Tímto došlo k významnému zrychlení, které bylo asi nejvíce patrné, animace se stala téměř plynulou.
Posledním zlepšením bylo spuštění kódu Embox z RAM a Qt ze SDRAM. Nejprve, jak je obvyklé, staticky linkujeme Embox spolu s Qt, ale segmenty text, rodata, data a bss knihovny umísťujeme do QSPI, abychom je následně mohli zkopírovat 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))
Spuštěním kódu Embox z ROM jsme také dosáhli znatelného zrychlení. Výsledkem je, že animace je dostatečně plynulá:

Na samém konci, při přípravě článku a zkoušení různých konfigurací Emboxu, se ukázalo, že Qt moveblocks funguje skvěle i z QSPI s framebufferem v SDRAM, přičemž užším místem byl právě velikost framebufferu! Zdá se, že pro překonání počátečního "slideshow" stačilo zrychlení 2x jednoduchým snížením velikosti framebufferu. A dosáhnout takového výsledku přesunutím pouze kódu Embox do různých rychlých pamětí se nepodařilo (zrychlení bylo ne 2x, ale přibližně 1,5x).
Jak to vyzkoušet sám
Pokud máte STM32F7-Discovery, můžete spustit Qt pod Embox sami. Přečíst si, jak na to, můžete na našich .
Závěr
Nakonec se nám podařilo spustit Qt! Obtížnost úkolu se nám na náš názor jeví jako poněkud přehnaná. Je samozřejmě třeba vzít v úvahu specifika mikrokontrolérů a vůbec rozumět architektuře výpočetních systémů. Výsledky optimalizace ukazují na známý fakt, že nejslabším článkem ve výpočetním systému není procesor, ale paměť.
Tento rok se zúčastníme festivalu . Na něm podrobněji přiblížíme a ukážeme Qt, OpenCV na mikrokontrolérech a další naše úspěchy.
Zdroj: habr.com
