Buon pomeriggio Siamo nel progetto
Qt è un framework multipiattaforma che include non solo componenti grafici, ma anche cose come QtNetwork, un insieme di classi per lavorare con i database, Qt for Automation (inclusa l'implementazione IoT) e molto altro. Il team Qt è stato proattivo nell'usare Qt nei sistemi embedded, quindi le librerie sono abbastanza configurabili. Tuttavia, fino a poco tempo fa, poche persone pensavano di portare Qt sui microcontrollori, probabilmente perché un compito del genere sembrava difficile: Qt è grande, gli MCU sono piccoli.
D'altra parte, al momento esistono microcontrollori progettati per funzionare con la multimedialità e superiori ai primi Pentium. Circa un anno fa è apparso il blog Qt
Qt 4.8 è stato portato su Embox per molto tempo, quindi abbiamo deciso di provarlo. Abbiamo scelto l'applicazione moveblocks, un esempio di animazione elastica.
Sposta i blocchi Qt su QEMU
Per cominciare, configuriamo Qt, se possibile, con il set minimo di componenti richiesti per supportare l'animazione. Per questo esiste l'opzione “-qconfig minimal,small,medium...”. Collega un file di configurazione da Qt con molte macro: cosa abilitare/cosa disabilitare. Dopo questa opzione, aggiungiamo altri flag alla configurazione se vogliamo disabilitare qualcos'altro. Ecco un esempio del nostro
Affinché Qt funzioni, è necessario aggiungere un livello di compatibilità del sistema operativo. Un modo è implementare QPA (Qt Platform Abstraction). Abbiamo preso come base il plugin fb_base già pronto incluso in Qt, sulla base del quale funziona QPA per Linux. Il risultato è un piccolo plugin chiamato emboxfb, che fornisce a Qt il framebuffer di Embox, e poi si disegna lì senza alcun aiuto esterno.
Ecco come appare la creazione di un 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();
}
E questo è come apparirà il ridisegno
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;
}
Di conseguenza, con l'ottimizzazione del compilatore per la dimensione della memoria -Os abilitata, l'immagine della libreria risulta essere di 3.5 MB, che ovviamente non rientra nella memoria principale dell'STM32F746. Come abbiamo già scritto nel nostro altro articolo su OpenCV, questa scheda ha:
- 1 MB di ROM
- 320KB di RAM
- SD-RAM da 8 MB
- QSPI da 16 MB
Poiché il supporto per l'esecuzione del codice da QSPI è già stato aggiunto a OpenCV, abbiamo deciso di iniziare caricando l'intera immagine Embox c Qt in QSPI. E evviva, tutto è partito quasi subito da QSPI! Ma come nel caso di OpenCV, si è scoperto che funziona troppo lentamente.
Pertanto, abbiamo deciso di farlo in questo modo: prima copiamo l'immagine su QSPI, quindi la carichiamo nella SDRAM ed eseguiamo da lì. Da SDRAM è diventato un po' più veloce, ma ancora lontano da QEMU.
Successivamente, è nata l'idea di includere un punto mobile: dopo tutto, Qt esegue alcuni calcoli sulle coordinate dei quadrati nell'animazione. Ci abbiamo provato, ma qui non abbiamo ottenuto alcuna accelerazione visibile, anche se dentro
L'idea più efficace è stata spostare il framebuffer dalla SDRAM alla memoria interna. Per fare ciò, abbiamo reso le dimensioni dello schermo non 480x272, ma 272x272. Abbiamo anche abbassato la profondità del colore da A8R8G8B8 a R5G6B5, riducendo così la dimensione di un pixel da 4 a 2 byte. La dimensione del framebuffer risultante è 272 * 272 * 2 = 147968 byte. Ciò ha dato un'accelerazione significativa, forse la più evidente, l'animazione è diventata quasi fluida.
L'ultima ottimizzazione è stata l'esecuzione del codice Embox dalla RAM e del codice Qt dalla SDRAM. Per fare questo, prima colleghiamo staticamente Embox insieme a Qt, come al solito, ma posizioniamo i segmenti text, rodata, data e bss della libreria in QSPI per poi copiarli su 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))
Eseguendo il codice Embox dalla ROM, abbiamo anche ricevuto una notevole accelerazione. Di conseguenza, l'animazione è risultata abbastanza fluida:
Alla fine, mentre preparavo l'articolo e provavo diverse configurazioni di Embox, si è scoperto che i moveblock Qt funzionano benissimo da QSPI con un framebuffer in SDRAM, e il collo di bottiglia era proprio la dimensione del framebuffer! A quanto pare, per superare lo “slideshow” iniziale, è stata sufficiente un'accelerazione di 2 volte dovuta ad una banale riduzione delle dimensioni del framebuffer. Ma non è stato possibile ottenere un risultato del genere trasferendo solo il codice Embox su varie memorie veloci (l'accelerazione non era 2, ma circa 1.5 volte).
Come provarlo tu stesso
Se disponi di un STM32F7-Discovery, puoi eseguire tu stesso Qt sotto Embox. Puoi leggere come viene fatto sul nostro
conclusione
Di conseguenza, siamo riusciti a lanciare Qt! La complessità del compito, a nostro avviso, è alquanto esagerata. Naturalmente, è necessario tenere conto delle specificità dei microcontrollori e in generale comprendere l'architettura dei sistemi informatici. I risultati dell'ottimizzazione evidenziano il fatto ben noto che il collo di bottiglia in un sistema informatico non è il processore, ma la memoria.
Quest'anno parteciperemo al festival
Fonte: habr.com