Guten Tag! Wir arbeiten an einem Projekt und haben Qt auf dem STM32F7-Discovery gestartet und möchten darüber berichten. Zuvor haben wir bereits erzählt, wie es uns gelungen ist, .
Qt – ist ein plattformübergreifendes Framework, das nicht nur grafische Komponenten umfasst, sondern auch Dinge wie QtNetwork, eine Sammlung von Klassen zur Arbeit mit Datenbanken, Qt für Automatisierung (einschließlich für IoT-Implementierungen) und vieles mehr. Die Entwickler des Qt-Teams haben die Nutzung von Qt in eingebetteten Systemen bereits im Voraus berücksichtigt, daher sind die Bibliotheken gut konfigurierbar. Allerdings haben sich bis vor kurzem nur wenige Gedanken über die Portierung von Qt auf Mikrocontroller gemacht, wahrscheinlich weil diese Aufgabe komplex erscheint – Qt ist groß, das MCU ist klein.
Auf der anderen Seite gibt es derzeit Mikrocontroller, die für Multimedia-Anwendungen konzipiert sind und die ersten Pentiums übertreffen. Vor etwa einem Jahr erschien in dem Qt-Blog . Die Entwickler haben Qt für das RTEMS-Betriebssystem portiert und Beispiele mit Widgets auf mehreren Platinen, die von stm32f7 betrieben werden, gestartet. Das hat unser Interesse geweckt. Es war offensichtlich, und die Entwickler selbst erwähnen es, dass Qt auf dem STM32F7-Discovery träge läuft. Wir waren neugierig, ob wir Qt unter Embox starten können, und zwar nicht nur, um ein Widget zu zeichnen, sondern um eine Animation zu starten.
Qt 4.8 ist bereits lange in Embox portiert, deshalb haben wir beschlossen, es darauf auszuprobieren. Wir haben die Anwendung moveblocks gewählt – ein Beispiel für eine federnde Animation.
Qt moveblocks auf QEMU
Zunächst konfigurieren wir Qt mit möglichst minimalem Komponentenpaket, das zur Unterstützung der Animation erforderlich ist. Dazu gibt es die Option „-qconfig minimal,small,medium …“. Sie verbindet eine Konfigurationsdatei aus dem Qt-Paket mit vielen Makros – was ein- / was ausgeschaltet werden soll. Nach dieser Option fügen wir in die Konfiguration andere Flags hinzu, wenn wir noch etwas zusätzlich ausschalten möchten. Hier ist ein Beispiel unserer .
Um Qt zum Laufen zu bringen, muss eine Kompatibilitätsschicht mit dem Betriebssystem hinzugefügt werden. Eine Möglichkeit ist die Implementierung von QPA (Qt Platform Abstraction). Wir haben als Grundlage bereits ein vorhandenes Plugin fb_base aus dem Qt-Paket genommen, auf dem QPA für Linux basiert. Am Ende entstand ein kleines Plugin emboxfb, das Qt den Framebuffer von Embox zur Verfügung stellt, und dann wird dort ohne fremde Hilfe gezeichnet.
So sieht die Erstellung eines Plugins aus
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 (fbFd < 0) {
qFatal("QEmboxFbIntegration: Fehler beim Öffnen des Framebuffers %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
qFatal("QEmboxFbIntegration: Fehler ioctl beim Framebuffer %s", fbPath);
}
if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
qFatal("QEmboxFbIntegration: Fehler ioctl beim 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: Fehler mmap beim Framebuffer %s", fbPath);
}
if (!fbData || !fbSize) {
qFatal("QEmboxFbIntegration: Falscher Framebuffer: Basis = %p,"
"Größe=%d", fbData, fbSize);
}
mPrimaryScreen = new QEmboxFbScreen(fbData, fbWidth,
fbHeight, fbBytesPerLine,
emboxFbFormatToQImageFormat(fbFormat));
mPrimaryScreen->setPhysicalSize(QSize(fbWidth, fbHeight));
mScreens.append(mPrimaryScreen);
this->printFbInfo();
}
So würde die Neuzeichnung aussehen.
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;
}
Mit aktivierter Compileroptimierung für die Speichermenge -Os ergab das Bibliotheksabbild 3,5 MB, was natürlich nicht in den Hauptspeicher des STM32F746 passt. Wie wir bereits in unserem anderen Artikel über OpenCV geschrieben haben, hat dieses Board:
- 1 MB ROM
- 320 KB RAM
- 8 MB SDRAM
- 16 MB QSPI
Da für OpenCV bereits die Unterstützung für die Ausführung von Code aus QSPI hinzugefügt wurde, haben wir beschlossen, zu beginnen, indem wir das Bild von Embox mit Qt vollständig in QSPI geladen haben. Und hurra, alles startete fast sofort aus QSPI! Aber wie im Fall von OpenCV stellte sich heraus, dass es zu langsam läuft.

Deshalb haben wir entschieden, es so zu machen – zuerst das Bild in QSPI zu kopieren, dann es in SDRAM zu laden und von dort aus auszuführen. Von SDRAM aus wurde es etwas schneller, aber immer noch weit entfernt von QEMU.

Weiterhin wurde die Idee gebracht, die Gleitkommazahl zu aktivieren – schließlich führt Qt einige Berechnungen der Koordinaten von Quadraten in der Animation durch. Wir haben es ausprobiert, aber hier erhielten wir keine sichtbare Beschleunigung, obwohl in die Entwickler von Qt behaupteten, dass die FPU einen erheblichen Geschwindigkeitsgewinn für die „Dragging-Animation“ auf dem Touchscreen bietet. Möglicherweise gibt es bei moveblocks erheblich weniger Berechnungen mit Gleitkommazahlen, und das hängt vom spezifischen Beispiel ab.
Die effektivste Idee war, das Framebuffer von SDRAM in den internen Speicher zu übertragen. Dazu haben wir die Bildschirmgröße nicht auf 480×272, sondern auf 272×272 festgelegt. Außerdem haben wir die Farbtiefe von A8R8G8B8 auf R5G6B5 verringert, wodurch die Größe eines Pixels von 4 auf 2 Bytes reduziert wurde. Wir erhielten eine Framebuffer-Größe von 272 * 272 * 2 = 147968 Bytes. Dies führte zu einer signifikanten Beschleunigung, wahrscheinlich der auffälligsten, die Animation wurde fast flüssig.
Die letzte Optimierung war die Ausführung des Embox-Codes aus dem RAM, während Qt aus SDRAM geladen wird. Dazu verlinken wir zunächst wie gewohnt statisch Embox zusammen mit Qt, platzieren jedoch die Segmente text, rodata, data und bss der Bibliothek im QSPI, um sie später in SDRAM zu kopieren.
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))
Durch die Ausführung des Embox-Codes aus dem ROM erhielten wir ebenfalls einen spürbaren Geschwindigkeitsvorteil. Letztlich war die Animation ausreichend flüssig:

Bereits am Ende, als wir den Artikel vorbereiteten und verschiedene Konfigurationen von Embox ausprobierten, stellte sich heraus, dass Qt moveblocks auch hervorragend von QSPI mit dem Framebuffer in SDRAM funktioniert, und der Engpass war tatsächlich die Größe des Framebuffers! Offenbar reichte eine Verdopplung der Geschwindigkeit durch die banale Reduzierung der Framebuffer-Größe aus, um die anfängliche „Diashow“ zu überwinden. Mit dem bloßen Transfer des Embox-Codes in verschiedene schnelle Speicher ließ sich dieses Ergebnis nicht erzielen (die Beschleunigung betrug nicht 2, sondern etwa 1,5 Mal).
Wie man es selbst ausprobieren kann
Wenn Sie ein STM32F7-Discovery haben, können Sie Qt unter Embox selbst starten. Wie das geht, können Sie in unserem .
Fazit
Schließlich ist es uns gelungen, Qt zu starten! Die Schwierigkeit dieser Aufgabe ist unserer Meinung nach etwas übertrieben. Natürlich müssen die Besonderheiten der Mikrocontroller berücksichtigt werden und man sollte die Architektur von Rechensystemen verstehen. Die Optimierungsergebnisse weisen auf die bekannte Tatsache hin, dass der größte Engpass im Rechensystem nicht die CPU, sondern der Speicher ist.
In diesem Jahr werden wir am Festival teilnehmen. Dort werden wir ausführlich über Qt, OpenCV auf Mikrocontrollern und andere unsere Errungenschaften berichten und zeigen.
Quelle: habr.com
