Qt portimine STM32-sse

Qt portimine STM32-sseTere päevast Oleme projektis Embox käivitas Qt saidil STM32F7-Discovery ja tahaksin sellest rääkida. Varem rääkisime juba, kuidas meil käivitamine õnnestus OpenCV.

Qt on platvormideülene raamistik, mis sisaldab mitte ainult graafilisi komponente, vaid ka selliseid asju nagu QtNetwork, klasside komplekt andmebaasidega töötamiseks, Qt automatiseerimiseks (sh IoT juurutamiseks) ja palju muud. Qt meeskond on Qt manussüsteemides ennetavalt kasutanud, nii et teegid on üsna konfigureeritavad. Kuid kuni viimase ajani mõtlesid vähesed inimesed Qt portimisele mikrokontrolleritesse, ilmselt seetõttu, et selline ülesanne tundub keeruline - Qt on suur, MCU-d väikesed.

Teisest küljest on praegu olemas mikrokontrollerid, mis on loodud töötama multimeediumiga ja paremad kui esimesed Pentiumid. Umbes aasta tagasi ilmus Qt ajaveeb postitus. Arendajad tegid RTEMS OS-i jaoks Qt pordi ja käivitasid vidinate näited mitmel tahvlil, millel töötab stm32f7. See huvitas meid. Oli märgata ja ka arendajad ise kirjutavad sellest, et Qt on STM32F7-Discovery peal aeglane. Mõtlesime, kas saaksime Emboxi all Qt käivitada ja mitte lihtsalt vidinat joonistada, vaid käivitada animatsiooni.

Qt 4.8 on Emboxi porditud juba pikka aega, nii et otsustasime seda sellega proovida. Valisime rakenduse moveblocks – vetruva animatsiooni näide.

Qt liigub QEMU-sQt portimine STM32-sse

Alustuseks seadistame Qt võimaluse korral minimaalse komponentide komplektiga, mis on vajalik animatsiooni toetamiseks. Selleks on valik “-qconfig minimaalne, väike, keskmine...”. See ühendab Qt konfiguratsioonifaili paljude makrodega – mida lubada/mida keelata. Pärast seda valikut lisame konfiguratsioonile muud lipud, kui tahame midagi muud keelata. Siin on näide meie seadistamine.

Selleks, et Qt töötaks, peate lisama OS-i ühilduvuskihi. Üks võimalus on rakendada QPA (Qt Platform Abstraction). Võtsime aluseks Qt-s sisalduva valmis fb_base plugina, mille alusel töötab QPA for Linux. Tulemuseks on väike plugin nimega emboxfb, mis varustab Qt-ga Emboxi kaadripuhvriga ja seejärel tõmbab sinna ilma kõrvalise abita.

Nii näeb välja pistikprogrammi loomine

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

Ja selline näeb ümber joonistus välja

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

Selle tulemusel, kui kompilaatori optimeerimine mälumahu -Os jaoks oli lubatud, osutus teegi kujutiseks 3.5 MB, mis loomulikult ei mahu STM32F746 põhimällu. Nagu me juba oma teises artiklis OpenCV kohta kirjutasime, on sellel tahvlil:

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

Kuna OpenCV-le on juba lisatud QSPI koodi täitmise tugi, otsustasime alustuseks laadida kogu Embox c Qt pildi QSPI-sse. Ja hurraa, kõik algas peaaegu kohe QSPI-st! Kuid nagu OpenCV puhul, selgus, et see töötab liiga aeglaselt.

Qt portimine STM32-sse

Seetõttu otsustasime seda teha nii - esmalt kopeerime pildi QSPI-sse, seejärel laadime selle SDRAM-i ja käivitame sealt. SDRAM-ist muutus see pisut kiiremaks, kuid QEMU-st siiski kaugel.

Qt portimine STM32-sse

Järgmiseks tekkis mõte lisada ujukoma – Qt teeb ju animatsioonis mingeid ruutude koordinaatide arvutusi. Proovisime, kuid siin ei saanud me nähtavat kiirendust, kuigi sisse siit Qt arendajad väitsid, et FPU suurendab oluliselt puuteekraanil animatsiooni lohistamise kiirust. Liikumisplokkides võib ujukomaarvutusi olla oluliselt vähem ja see oleneb konkreetsest näitest.

Kõige tõhusam idee oli viia kaadripuhver SDRAM-ist sisemällu. Selleks tegime ekraani mõõtmeteks mitte 480x272, vaid 272x272. Samuti alandasime värvisügavust A8R8G8B8-lt R5G6B5-le, vähendades nii ühe piksli suurust 4-lt 2-le baidile. Saadud kaadripuhvri suurus on 272 * 272 * 2 = 147968 baiti. See andis märkimisväärse kiirenduse, võib-olla kõige märgatavamalt muutus animatsioon peaaegu sujuvaks.

Viimane optimeerimine oli Emboxi koodi käivitamine RAM-ist ja Qt-kood SDRAM-ist. Selleks seame esmalt, nagu tavaliselt, staatiliselt Emboxi Qt-ga, kuid teegi teksti, rodata, andmete ja bss-segmendid paigutame QSPI-sse, et seejärel kopeerida see SDRAM-i.

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

ROM-ilt Emboxi koodi käivitades saime ka märgatava kiirenduse. Selle tulemusel osutus animatsioon üsna sujuvaks:


Päris lõpus artiklit ette valmistades ja erinevaid Emboxi seadistusi proovides selgus, et Qt moveblocks töötab QSPI-st suurepäraselt SDRAM-is oleva kaadripuhvriga ning kitsaskohaks oli just kaadripuhvri suurus! Ilmselt piisas esialgsest "slaidiseansist" ülesaamiseks 2-kordsest kiirendusest kaadripuhvri suuruse banaalse vähendamise tõttu. Kuid ainult Emboxi koodi erinevatele kiiretele mäludele ülekandmisega sellist tulemust saavutada ei õnnestunud (kiirendus ei olnud 2, vaid umbes 1.5-kordne).

Kuidas seda ise proovida

Kui teil on STM32F7-Discovery, saate ise Emboxi all Qt käivitada. Kuidas seda tehakse, saate lugeda meie lehelt wiki.

Järeldus

Selle tulemusena õnnestus meil käivitada Qt! Ülesande keerukus on meie arvates mõnevõrra liialdatud. Loomulikult peate arvestama mikrokontrollerite eripäraga ja üldiselt mõistma arvutisüsteemide arhitektuuri. Optimeerimise tulemused viitavad üldtuntud tõsiasjale, et arvutussüsteemi kitsaskohaks ei ole protsessor, vaid mälu.

Sel aastal osaleme festivalil TechTrain. Seal räägime teile täpsemalt ja näitame Qt, OpenCV mikrokontrolleritel ja muid meie saavutusi.

Allikas: www.habr.com

Lisa kommentaar