Boas tardes Estamos no proxecto
Qt é un marco multiplataforma que inclúe non só compoñentes gráficos, senón tamén cousas como QtNetwork, un conxunto de clases para traballar con bases de datos, Qt for Automation (incluída a implementación de IoT) e moito máis. O equipo de Qt foi proactivo sobre o uso de Qt en sistemas integrados, polo que as bibliotecas son bastante configurables. Non obstante, ata hai pouco, poucas persoas pensaban en portar Qt a microcontroladores, probablemente porque tal tarefa parece difícil: Qt é grande, os MCU son pequenos.
Por outra banda, neste momento existen microcontroladores pensados para funcionar con multimedia e superiores aos primeiros Pentium. Hai aproximadamente un ano apareceu o blog Qt
Qt 4.8 foi portado a Embox durante moito tempo, polo que decidimos probalo. Escollemos a aplicación moveblocks, un exemplo de animación elástica.
Qt moveblocks en QEMU
Para comezar, configuramos Qt, se é posible, co conxunto mínimo de compoñentes necesarios para soportar a animación. Para iso hai unha opción “-qconfig minimal,small,medium...”. Conecta un ficheiro de configuración de Qt con moitas macros: que activar / que desactivar. Despois desta opción, engadimos outras bandeiras á configuración se queremos desactivar outra cousa. Velaquí un exemplo do noso
Para que Qt funcione, cómpre engadir unha capa de compatibilidade do sistema operativo. Unha forma é implementar QPA (Qt Platform Abstracción). Tomamos como base o complemento fb_base preparado incluído en Qt, sobre a base do cal funciona QPA para Linux. O resultado é un pequeno complemento chamado emboxfb, que proporciona a Qt o framebuffer de Embox, e despois debuxa alí sen axuda externa.
Isto é o que parece crear un complemento
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 así será o rediseño
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;
}
Como resultado, coa optimización do compilador para o tamaño da memoria -Os activada, a imaxe da biblioteca resultou ser de 3.5 MB, que por suposto non encaixa na memoria principal do STM32F746. Como xa escribimos no noso outro artigo sobre OpenCV, este taboleiro ten:
- 1 MB de ROM
- 320 KB de RAM
- 8 MB SDRAM
- 16 MB QSPI
Dado que xa se engadiu o soporte para executar código desde QSPI a OpenCV, decidimos comezar cargando toda a imaxe de Embox c Qt en QSPI. E vaga, todo comezou case de inmediato desde QSPI! Pero como no caso de OpenCV, resultou que funciona moi lentamente.
Polo tanto, decidimos facelo deste xeito: primeiro copiamos a imaxe en QSPI, despois cargamos na SDRAM e executamos desde alí. Desde SDRAM fíxose un pouco máis rápido, pero aínda lonxe de QEMU.
A continuación, houbo unha idea de incluír un punto flotante; despois de todo, Qt fai algúns cálculos das coordenadas dos cadrados na animación. Intentamos, pero aquí non obtivemos ningunha aceleración visible, aínda que dentro
A idea máis efectiva foi mover o framebuffer da SDRAM á memoria interna. Para iso, fixemos que as dimensións da pantalla non fosen 480x272, senón 272x272. Tamén reducimos a profundidade da cor de A8R8G8B8 a R5G6B5, reducindo así o tamaño dun píxel de 4 a 2 bytes. O tamaño do framebuffer resultante é 272 * 272 * 2 = 147968 bytes. Isto deu unha aceleración significativa, quizais o máis notable, a animación tornouse case suave.
A última optimización foi executar código Embox desde RAM e código Qt desde SDRAM. Para iso, primeiro, como é habitual, enlazamos embox de forma estática con Qt, pero colocamos os segmentos de texto, rodata, datos e bss da biblioteca en QSPI para despois copialo na 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))
Ao executar o código Embox desde a ROM, tamén recibimos unha aceleración notable. Como resultado, a animación resultou bastante suave:
Ao final, mentres preparaba o artigo e probaba diferentes configuracións de Embox, descubriuse que Qt moveblocks funciona moi ben desde QSPI cun framebuffer en SDRAM, e o pescozo de botella era precisamente do tamaño do framebuffer. Ao parecer, para superar a "presentación de diapositivas" inicial, unha aceleración de 2 veces foi suficiente debido a unha redución banal do tamaño do framebuffer. Pero non foi posible conseguir tal resultado transferindo só o código Embox a varias memorias rápidas (a aceleración non foi de 2, senón de 1.5 veces).
Como probalo vostede mesmo
Se tes un STM32F7-Discovery, podes executar Qt en Embbox ti mesmo. Podes ler como se fai isto na nosa web
Conclusión
Como resultado, conseguimos lanzar Qt! A complexidade da tarefa, na nosa opinión, é algo esaxerada. Por suposto, cómpre ter en conta as características específicas dos microcontroladores e comprender xeralmente a arquitectura dos sistemas informáticos. Os resultados da optimización apuntan ao feito ben coñecido de que o pescozo de botella nun sistema informático non é o procesador, senón a memoria.
Este ano imos participar no festival
Fonte: www.habr.com