Dobar dan U projektu smo
Qt je međuplatformski okvir koji uključuje ne samo grafičke komponente, već i stvari kao što su QtNetwork, skup klasa za rad s bazama podataka, Qt za automatizaciju (uključujući implementaciju IoT-a) i još mnogo toga. Qt tim bio je proaktivan u korištenju Qt-a u ugrađenim sustavima, tako da su biblioteke prilično konfigurabilne. Međutim, donedavno je malo ljudi razmišljalo o prijenosu Qt-a na mikrokontrolere, vjerojatno zato što se takav zadatak čini teškim - Qt je velik, MCU-ovi su mali.
S druge strane, u ovom trenutku postoje mikrokontroleri dizajnirani za rad s multimedijom i superiorniji od prvih Pentiuma. Prije otprilike godinu dana pojavio se Qt blog
Qt 4.8 je već duže vrijeme portiran na Embox pa smo ga odlučili isprobati na njemu. Odabrali smo aplikaciju moveblocks - primjer elastične animacije.
Qt moveblocks na QEMU
Za početak, konfiguriramo Qt, ako je moguće, s minimalnim skupom komponenti potrebnih za podršku animaciji. Za to postoji opcija “-qconfig minimalno, malo, srednje...”. Povezuje konfiguracijsku datoteku iz Qt-a s mnogo makronaredbi - što omogućiti / što onemogućiti. Nakon ove opcije, dodajemo druge zastavice u konfiguraciju ako želimo onemogućiti nešto drugo. Evo primjera našeg
Kako bi Qt radio, trebate dodati sloj kompatibilnosti OS-a. Jedan od načina je implementacija QPA (Qt Platform Abstraction). Kao osnovu uzeli smo gotov fb_base dodatak uključen u Qt, na temelju kojeg radi QPA za Linux. Rezultat je mali dodatak nazvan emboxfb, koji daje Qt-u Emboxov okvirni međuspremnik, a zatim crta tamo bez ikakve vanjske pomoći.
Ovako izgleda stvaranje dodatka
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 ovako će izgledati precrtavanje
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;
}
Kao rezultat toga, s omogućenom optimizacijom kompajlera za veličinu memorije -Os, slika knjižnice se pokazala kao 3.5 MB, što naravno ne stane u glavnu memoriju STM32F746. Kao što smo već napisali u našem drugom članku o OpenCV-u, ova ploča ima:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Budući da je podrška za izvršavanje koda iz QSPI-ja već dodana u OpenCV, odlučili smo započeti učitavanjem cijele Embox c Qt slike u QSPI. I hura, sve je krenulo gotovo odmah od QSPI-ja! No, kao iu slučaju OpenCV-a pokazalo se da radi presporo.
Stoga smo odlučili to učiniti na ovaj način - prvo kopiramo sliku u QSPI, zatim je učitamo u SDRAM i izvršimo od tamo. Od SDRAM-a postao je malo brži, ali još uvijek daleko od QEMU-a.
Zatim, postojala je ideja da se uključi pokretni zarez - uostalom, Qt radi neke izračune koordinata kvadrata u animaciji. Pokušali smo, ali ovdje nismo dobili nikakvo vidljivo ubrzanje, iako u
Najučinkovitija ideja bila je premjestiti okvirni međuspremnik iz SDRAM-a u internu memoriju. Da bismo to učinili, napravili smo dimenzije zaslona ne 480x272, već 272x272. Također smo smanjili dubinu boje s A8R8G8B8 na R5G6B5, čime smo smanjili veličinu jednog piksela s 4 na 2 bajta. Rezultirajuća veličina međuspremnika okvira je 272 * 272 * 2 = 147968 bajtova. To je dalo značajno ubrzanje, možda najuočljivije, animacija je postala gotovo glatka.
Najnovija optimizacija bila je pokretanje Embox koda iz RAM-a i Qt koda iz SDRAM-a. Da bismo to učinili, prvo, kao i obično, statički povezujemo Embox zajedno s Qt-om, ali stavljamo tekst, rodata, podatke i bss segmente biblioteke u QSPI kako bismo ga zatim kopirali u 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))
Izvršavanjem Embox koda iz ROM-a također smo dobili osjetno ubrzanje. Kao rezultat toga, animacija je ispala prilično glatka:
Na samom kraju, tijekom pripreme članka i isprobavanja različitih Embox konfiguracija, pokazalo se da Qt moveblocks odlično radi iz QSPI-ja s framebufferom u SDRAM-u, a usko grlo je bila upravo veličina framebuffera! Očigledno, za prevladavanje početnog "slideshowa" bilo je dovoljno dvostruko ubrzanje zbog banalnog smanjenja veličine okvira međuspremnika. Ali nije bilo moguće postići takav rezultat prijenosom samo Embox koda u razne brze memorije (ubrzanje nije bilo 2, već oko 2 puta).
Kako to sami isprobati
Ako imate STM32F7-Discovery, možete sami pokrenuti Qt pod Emboxom. Kako se to radi možete pročitati na našem
Zaključak
Kao rezultat, uspjeli smo pokrenuti Qt! Složenost zadatka, po našem mišljenju, donekle je pretjerana. Naravno, morate uzeti u obzir specifičnosti mikrokontrolera i općenito razumjeti arhitekturu računalnih sustava. Rezultati optimizacije ukazuju na dobro poznatu činjenicu da usko grlo računalnog sustava nije procesor, već memorija.
Ove godine ćemo sudjelovati na festivalu
Izvor: www.habr.com