Goedemiddag Wij zitten in het project
Qt is een platformonafhankelijk raamwerk dat niet alleen grafische componenten omvat, maar ook zaken als QtNetwork, een reeks klassen voor het werken met databases, Qt voor automatisering (inclusief voor IoT-implementatie) en nog veel meer. Het Qt-team is proactief geweest met het gebruik van Qt in ingebedde systemen, dus de bibliotheken zijn behoorlijk configureerbaar. Tot voor kort dachten echter weinig mensen aan het porten van Qt naar microcontrollers, waarschijnlijk omdat een dergelijke taak moeilijk lijkt: Qt is groot, MCU's zijn klein.
Aan de andere kant zijn er momenteel microcontrollers die zijn ontworpen om met multimedia te werken en superieur zijn aan de eerste Pentiums. Ongeveer een jaar geleden verscheen de Qt-blog
Qt 4.8 is al lange tijd overgezet naar Embox, dus we besloten het erop te proberen. We kozen voor de moveblocks-applicatie - een voorbeeld van verende animatie.
Qt verplaatst blokken op QEMU
Om te beginnen configureren we Qt, indien mogelijk, met de minimale set componenten die nodig is om animatie te ondersteunen. Hiervoor is er een optie “-qconfig minimaal,klein,medium...”. Het verbindt een configuratiebestand van Qt met veel macro's - wat moet worden ingeschakeld/wat moet worden uitgeschakeld. Na deze optie voegen we andere vlaggen toe aan de configuratie als we iets anders willen uitschakelen. Hier is een voorbeeld van onze
Om Qt te laten werken, moet u een OS-compatibiliteitslaag toevoegen. Eén manier is om QPA (Qt Platform Abstraction) te implementeren. Als basis hebben we de kant-en-klare plug-in fb_base genomen die in Qt zit, op basis waarvan QPA voor Linux werkt. Het resultaat is een kleine plug-in genaamd emboxfb, die Qt voorziet van de framebuffer van Embox, en vervolgens daarheen tekent zonder enige hulp van buitenaf.
Zo ziet het maken van een plug-in eruit
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();
}
En zo zal het hertekenen eruit zien
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;
}
Als gevolg hiervan bleek de bibliotheekimage, met de compileroptimalisatie voor geheugengrootte -Os ingeschakeld, 3.5 MB te zijn, wat uiteraard niet in het hoofdgeheugen van de STM32F746 past. Zoals we al schreven in ons andere artikel over OpenCV, heeft dit bestuur:
- 1 MB-ROM
- 320 KB RAM-geheugen
- 8 MB SDRAM
- 16 MB QSPI
Omdat ondersteuning voor het uitvoeren van code van QSPI al aan OpenCV is toegevoegd, hebben we besloten om te beginnen met het laden van de volledige Embox c Qt-image in QSPI. En hoera, alles begon vrijwel onmiddellijk vanuit QSPI! Maar net als bij OpenCV bleek dat het te langzaam werkt.
Daarom hebben we besloten om het op deze manier te doen: eerst kopiëren we de afbeelding naar QSPI, laden deze vervolgens in SDRAM en voeren het vanaf daar uit. Vanaf SDRAM werd het iets sneller, maar nog steeds ver verwijderd van QEMU.
Vervolgens was er een idee om een drijvende komma op te nemen - Qt voert immers enkele berekeningen uit van de coördinaten van vierkanten in animatie. We hebben het geprobeerd, maar hier kregen we geen zichtbare versnelling, hoewel binnen
Het meest effectieve idee was om de framebuffer van SDRAM naar het interne geheugen te verplaatsen. Om dit te doen, hebben we de schermafmetingen niet 480x272, maar 272x272 gemaakt. We hebben ook de kleurdiepte verlaagd van A8R8G8B8 naar R5G6B5, waardoor de grootte van één pixel werd verkleind van 4 naar 2 bytes. De resulterende framebuffergrootte is 272 * 272 * 2 = 147968 bytes. Dit gaf een aanzienlijke versnelling, misschien wel het meest opvallend: de animatie werd bijna vloeiend.
De nieuwste optimalisatie was om Embox-code uit te voeren vanuit RAM en Qt-code vanuit SDRAM. Om dit te doen, koppelen we eerst, zoals gewoonlijk, Embox statisch aan Qt, maar plaatsen we de tekst-, rodata-, data- en bss-segmenten van de bibliotheek in QSPI om deze vervolgens naar SDRAM te kopiëren.
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))
Door de Embox-code uit ROM uit te voeren, kregen we ook een merkbare versnelling. Het resultaat was dat de animatie behoorlijk soepel verliep:
Helemaal aan het einde, tijdens het voorbereiden van het artikel en het uitproberen van verschillende Embox-configuraties, bleek dat Qt moveblocks prima werkt vanuit QSPI met een framebuffer in SDRAM, en het knelpunt was precies de grootte van de framebuffer! Blijkbaar was een dubbele versnelling voldoende om de aanvankelijke "diavoorstelling" te overwinnen vanwege een banale verkleining van de grootte van de framebuffer. Maar het was niet mogelijk om een dergelijk resultaat te bereiken door alleen de Embox-code naar verschillende snelle geheugens over te brengen (de versnelling was niet 2, maar ongeveer 2 keer).
Hoe je het zelf kunt proberen
Als u een STM32F7-Discovery heeft, kunt u Qt zelf onder Embox uitvoeren. Hoe u dat doet, leest u op onze website
Conclusie
Als gevolg hiervan zijn we erin geslaagd Qt! De complexiteit van de taak is naar onze mening enigszins overdreven. Uiteraard moet u rekening houden met de specifieke kenmerken van microcontrollers en in het algemeen de architectuur van computersystemen begrijpen. De optimalisatieresultaten wijzen op het bekende feit dat het knelpunt in een computersysteem niet de processor is, maar het geheugen.
Dit jaar doen wij mee aan het festival
Bron: www.habr.com