God eftermiddag Vi er med i projektet
Qt er et rammeværk på tværs af platforme, der ikke kun omfatter grafiske komponenter, men også ting som QtNetwork, et sæt klasser til at arbejde med databaser, Qt for Automation (inklusive til IoT-implementering) og meget mere. Qt-teamet har været proaktivt med at bruge Qt i indlejrede systemer, så bibliotekerne er ret konfigurerbare. Indtil for nylig har de færreste dog tænkt på at overføre Qt til mikrocontrollere, sandsynligvis fordi en sådan opgave virker vanskelig - Qt er stor, MCU'er er små.
På den anden side er der i øjeblikket mikrocontrollere designet til at arbejde med multimedier og er bedre end de første Pentiums. For omkring et år siden dukkede Qt-bloggen op
Qt 4.8 er blevet overført til Embox i lang tid, så vi besluttede at prøve det på det. Vi valgte moveblocks-applikationen - et eksempel på fjedrende animation.
Qt moveblocks på QEMU
Til at begynde med konfigurerer vi Qt, hvis det er muligt, med det minimumssæt af komponenter, der kræves for at understøtte animation. Til dette er der muligheden "-qconfig minimal,small, medium...". Den forbinder en konfigurationsfil fra Qt med mange makroer - hvad skal aktiveres / hvad skal deaktiveres. Efter denne mulighed tilføjer vi andre flag til konfigurationen, hvis vi vil deaktivere noget andet. Her er et eksempel på vores
For at Qt kan fungere, skal du tilføje et OS-kompatibilitetslag. En måde er at implementere QPA (Qt Platform Abstraction). Vi tog udgangspunkt i det færdiglavede fb_base-plugin, der er inkluderet i Qt, og som QPA til Linux fungerer på grundlag af. Resultatet er et lille plugin kaldet emboxfb, som forsyner Qt med Embox's framebuffer, og så trækker det derhen uden hjælp udefra.
Sådan ser det ud at oprette et plugin
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();
}
Og sådan kommer gentegningen til at se ud
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;
}
Som et resultat, med compiler-optimeringen for hukommelsesstørrelse -Os aktiveret, viste biblioteksbilledet sig at være 3.5 MB, hvilket naturligvis ikke passer ind i hovedhukommelsen på STM32F746. Som vi allerede skrev i vores anden artikel om OpenCV, har dette board:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Da understøttelse af eksekvering af kode fra QSPI allerede er tilføjet til OpenCV, besluttede vi at starte med at indlæse hele Embox c Qt-billedet i QSPI. Og hurra, alt startede næsten med det samme fra QSPI! Men som i tilfældet med OpenCV viste det sig, at det virker for langsomt.
Derfor besluttede vi at gøre det på denne måde - først kopierer vi billedet til QSPI, indlæser det derefter i SDRAM og udfører derfra. Fra SDRAM blev det lidt hurtigere, men stadig langt fra QEMU.
Dernæst var der en idé om at inkludere et flydende komma - Qt laver trods alt nogle beregninger af kvadraters koordinater i animation. Vi forsøgte, men her fik vi ikke nogen synlig acceleration, selvom vi var i
Den mest effektive idé var at flytte framebufferen fra SDRAM til intern hukommelse. For at gøre dette lavede vi skærmdimensionerne ikke 480x272, men 272x272. Vi sænkede også farvedybden fra A8R8G8B8 til R5G6B5 og reducerede dermed størrelsen på en pixel fra 4 til 2 bytes. Den resulterende rammebufferstørrelse er 272 * 272 * 2 = 147968 bytes. Dette gav en betydelig acceleration, måske mest bemærkelsesværdigt, animationen blev næsten jævn.
Den seneste optimering var at køre Embox-kode fra RAM og Qt-kode fra SDRAM. For at gøre dette kobler vi først som sædvanligt Embox statisk sammen med Qt, men vi placerer tekst-, rodata-, data- og bss-segmenterne af biblioteket i QSPI for derefter at kopiere det til 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))
Ved at udføre Embox-koden fra ROM fik vi også en mærkbar acceleration. Som et resultat viste animationen sig ret glat:
Til allersidst, mens man forberedte artiklen og prøvede forskellige Embox-konfigurationer, viste det sig, at Qt moveblocks fungerer fantastisk fra QSPI med en framebuffer i SDRAM, og flaskehalsen var præcis på størrelse med framebufferen! Tilsyneladende var en 2-dobbelt acceleration nok for at overvinde det indledende "diasshow" på grund af en banal reduktion i størrelsen af rammebufferen. Men det var ikke muligt at opnå et sådant resultat ved kun at overføre Embox-koden til forskellige hurtige hukommelser (hastigheden var ikke 2, men omkring 1.5 gange).
Sådan prøver du det selv
Hvis du har en STM32F7-Discovery, kan du selv køre Qt under Embox. Du kan læse hvordan det foregår på vores
Konklusion
Som et resultat lykkedes det at lancere Qt! Opgavens kompleksitet er efter vores mening noget overdrevet. Naturligvis skal du tage højde for detaljerne ved mikrocontrollere og generelt forstå arkitekturen i computersystemer. Optimeringsresultaterne peger på det velkendte faktum, at flaskehalsen i et computersystem ikke er processoren, men hukommelsen.
I år deltager vi i festivalen
Kilde: www.habr.com