Qt porten naar STM32

Qt porten naar STM32Goedemiddag Wij zitten in het project embox lanceerde Qt op STM32F7-Discovery en wil er graag over praten. Eerder vertelden we al hoe we het voor elkaar kregen om te lanceren OpenCV.

Qt is een platformonafhankelijk raamwerk dat niet alleen grafische componenten omvat, maar ook zaken als QtNetwork, een reeks klassen voor het werken met databases, Qt voor automatisering (inclusief voor IoT-implementatie) en nog veel meer. Het Qt-team is proactief geweest met het gebruik van Qt in ingebedde systemen, dus de bibliotheken zijn behoorlijk configureerbaar. Tot voor kort dachten echter weinig mensen aan het porten van Qt naar microcontrollers, waarschijnlijk omdat een dergelijke taak moeilijk lijkt: Qt is groot, MCU's zijn klein.

Aan de andere kant zijn er momenteel microcontrollers die zijn ontworpen om met multimedia te werken en superieur zijn aan de eerste Pentiums. Ongeveer een jaar geleden verscheen de Qt-blog post. De ontwikkelaars maakten een port van Qt voor het RTEMS OS en lanceerden voorbeelden met widgets op verschillende boards met stm32f7. Dit interesseerde ons. Het viel op, en de ontwikkelaars schrijven er zelf over, dat Qt traag is op de STM32F7-Discovery. We vroegen ons af of we Qt onder Embox konden uitvoeren, en niet alleen een widget konden tekenen, maar ook een animatie konden uitvoeren.

Qt 4.8 is al lange tijd overgezet naar Embox, dus we besloten het erop te proberen. We kozen voor de moveblocks-applicatie - een voorbeeld van verende animatie.

Qt verplaatst blokken op QEMUQt porten naar STM32

Om te beginnen configureren we Qt, indien mogelijk, met de minimale set componenten die nodig is om animatie te ondersteunen. Hiervoor is er een optie “-qconfig minimaal,klein,medium...”. Het verbindt een configuratiebestand van Qt met veel macro's - wat moet worden ingeschakeld/wat moet worden uitgeschakeld. Na deze optie voegen we andere vlaggen toe aan de configuratie als we iets anders willen uitschakelen. Hier is een voorbeeld van onze configuratie.

Om Qt te laten werken, moet u een OS-compatibiliteitslaag toevoegen. Eén manier is om QPA (Qt Platform Abstraction) te implementeren. Als basis hebben we de kant-en-klare plug-in fb_base genomen die in Qt zit, op basis waarvan QPA voor Linux werkt. Het resultaat is een kleine plug-in genaamd emboxfb, die Qt voorziet van de framebuffer van Embox, en vervolgens daarheen tekent zonder enige hulp van buitenaf.

Zo ziet het maken van een plug-in eruit

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();
}

En zo zal het hertekenen eruit zien

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;
}

Als gevolg hiervan bleek de bibliotheekimage, met de compileroptimalisatie voor geheugengrootte -Os ingeschakeld, 3.5 MB te zijn, wat uiteraard niet in het hoofdgeheugen van de STM32F746 past. Zoals we al schreven in ons andere artikel over OpenCV, heeft dit bestuur:

  • 1 MB-ROM
  • 320 KB RAM-geheugen
  • 8 MB SDRAM
  • 16 MB QSPI

Omdat ondersteuning voor het uitvoeren van code van QSPI al aan OpenCV is toegevoegd, hebben we besloten om te beginnen met het laden van de volledige Embox c Qt-image in QSPI. En hoera, alles begon vrijwel onmiddellijk vanuit QSPI! Maar net als bij OpenCV bleek dat het te langzaam werkt.

Qt porten naar STM32

Daarom hebben we besloten om het op deze manier te doen: eerst kopiëren we de afbeelding naar QSPI, laden deze vervolgens in SDRAM en voeren het vanaf daar uit. Vanaf SDRAM werd het iets sneller, maar nog steeds ver verwijderd van QEMU.

Qt porten naar STM32

Vervolgens was er een idee om een ​​drijvende komma op te nemen - Qt voert immers enkele berekeningen uit van de coördinaten van vierkanten in animatie. We hebben het geprobeerd, maar hier kregen we geen zichtbare versnelling, hoewel binnen статье Qt-ontwikkelaars beweerden dat FPU een aanzienlijke snelheidsverhoging geeft voor het “slepen van animaties” op het touchscreen. Er kunnen aanzienlijk minder drijvende-kommaberekeningen voorkomen in verplaatsblokken, en dit hangt af van het specifieke voorbeeld.

Het meest effectieve idee was om de framebuffer van SDRAM naar het interne geheugen te verplaatsen. Om dit te doen, hebben we de schermafmetingen niet 480x272, maar 272x272 gemaakt. We hebben ook de kleurdiepte verlaagd van A8R8G8B8 naar R5G6B5, waardoor de grootte van één pixel werd verkleind van 4 naar 2 bytes. De resulterende framebuffergrootte is 272 * 272 * 2 = 147968 bytes. Dit gaf een aanzienlijke versnelling, misschien wel het meest opvallend: de animatie werd bijna vloeiend.

De nieuwste optimalisatie was om Embox-code uit te voeren vanuit RAM en Qt-code vanuit SDRAM. Om dit te doen, koppelen we eerst, zoals gewoonlijk, Embox statisch aan Qt, maar plaatsen we de tekst-, rodata-, data- en bss-segmenten van de bibliotheek in QSPI om deze vervolgens naar SDRAM te kopiëren.

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))

Door de Embox-code uit ROM uit te voeren, kregen we ook een merkbare versnelling. Het resultaat was dat de animatie behoorlijk soepel verliep:


Helemaal aan het einde, tijdens het voorbereiden van het artikel en het uitproberen van verschillende Embox-configuraties, bleek dat Qt moveblocks prima werkt vanuit QSPI met een framebuffer in SDRAM, en het knelpunt was precies de grootte van de framebuffer! Blijkbaar was een dubbele versnelling voldoende om de aanvankelijke "diavoorstelling" te overwinnen vanwege een banale verkleining van de grootte van de framebuffer. Maar het was niet mogelijk om een ​​dergelijk resultaat te bereiken door alleen de Embox-code naar verschillende snelle geheugens over te brengen (de versnelling was niet 2, maar ongeveer 2 keer).

Hoe je het zelf kunt proberen

Als u een STM32F7-Discovery heeft, kunt u Qt zelf onder Embox uitvoeren. Hoe u dat doet, leest u op onze website wiki.

Conclusie

Als gevolg hiervan zijn we erin geslaagd Qt! De complexiteit van de taak is naar onze mening enigszins overdreven. Uiteraard moet u rekening houden met de specifieke kenmerken van microcontrollers en in het algemeen de architectuur van computersystemen begrijpen. De optimalisatieresultaten wijzen op het bekende feit dat het knelpunt in een computersysteem niet de processor is, maar het geheugen.

Dit jaar doen wij mee aan het festival TechTrain. Daar zullen we u meer in detail vertellen en Qt, OpenCV op microcontrollers en onze andere prestaties laten zien.

Bron: www.habr.com

Voeg een reactie