Qt perkėlimas į STM32

Qt perkėlimas į STM32Laba diena Mes dalyvaujame projekte Embox paleido Qt STM32F7-Discovery ir norėčiau apie tai pakalbėti. Anksčiau jau pasakojome, kaip mums pavyko paleisti OpenCV.

Qt yra kelių platformų sistema, apimanti ne tik grafinius komponentus, bet ir tokius dalykus kaip QtNetwork, klasių rinkinys darbui su duomenų bazėmis, Qt automatizavimui (įskaitant IoT diegimą) ir daug daugiau. Qt komanda aktyviai naudojo Qt įterptosiose sistemose, todėl bibliotekos yra gana konfigūruojamos. Tačiau dar visai neseniai mažai kas galvojo apie Qt perkėlimą į mikrovaldiklius, tikriausiai todėl, kad tokia užduotis atrodo sunki – Qt didelis, MCU maži.

Kita vertus, šiuo metu yra mikrovaldikliai, skirti dirbti su multimedija ir pranašesni už pirmuosius Pentium. Maždaug prieš metus pasirodė Qt tinklaraštis paštu. Kūrėjai sukūrė Qt prievadą RTEMS OS ir paleido pavyzdžius su valdikliais keliose plokštėse, kuriose veikia stm32f7. Tai mus sudomino. Buvo pastebėta ir patys kūrėjai apie tai rašo, kad STM32F7-Discovery Qt yra lėtas. Svarstėme, ar galėtume paleisti Qt naudodami Embox ir ne tik nupiešti valdiklį, bet ir paleisti animaciją.

Qt 4.8 ilgą laiką buvo perkeltas į Embox, todėl nusprendėme jį išbandyti. Pasirinkome „moveblocks“ aplikaciją – spyruokliškos animacijos pavyzdį.

Qt judėjimo blokai QEMUQt perkėlimas į STM32

Pirmiausia sukonfigūruojame Qt, jei įmanoma, su minimaliu komponentų rinkiniu, reikalingu animacijai palaikyti. Tam yra parinktis „-qconfig minimal,small,medium...“. Jis sujungia konfigūracijos failą iš Qt su daugybe makrokomandų – ką įjungti / ką išjungti. Po šios parinkties prie konfigūracijos pridedame kitų vėliavėlių, jei norime išjungti ką nors kita. Štai mūsų pavyzdys konfigūracija.

Kad Qt veiktų, turite pridėti OS suderinamumo sluoksnį. Vienas iš būdų yra įdiegti QPA (Qt Platform Abstraction). Remėmės paruoštu fb_base papildiniu, įtrauktu į Qt, kurio pagrindu veikia QPA for Linux. Rezultatas yra mažas įskiepis, vadinamas emboxfb, kuris suteikia Qt su Embox kadrų buferiu, o tada jis įtraukiamas ten be jokios pašalinės pagalbos.

Taip atrodo įskiepio kūrimas

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

Ir taip atrodys perpiešimas

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

Dėl to, įjungus kompiliatoriaus optimizavimą atminties dydžiui -Os, bibliotekos vaizdas pasirodė 3.5 MB, o tai, žinoma, netelpa į pagrindinę STM32F746 atmintį. Kaip jau rašėme kitame mūsų straipsnyje apie OpenCV, šioje lentoje yra:

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

Kadangi QSPI kodo vykdymo palaikymas jau buvo įtrauktas į OpenCV, nusprendėme pradėti įkeldami visą Embox c Qt vaizdą į QSPI. Ir hurra, viskas prasidėjo beveik iš karto nuo QSPI! Tačiau, kaip ir OpenCV atveju, paaiškėjo, kad jis veikia per lėtai.

Qt perkėlimas į STM32

Todėl nusprendėme tai padaryti taip – ​​pirmiausia nukopijuojame vaizdą į QSPI, tada įkeliame į SDRAM ir vykdome iš ten. Iš SDRAM jis tapo šiek tiek greitesnis, bet vis dar toli nuo QEMU.

Qt perkėlimas į STM32

Toliau kilo mintis įtraukti slankiojo kablelio – juk Qt animacijoje daro kažkokius kvadratų koordinačių skaičiavimus. Bandėme, bet čia jokio matomo pagreičio negavome, nors į straipsnis Qt kūrėjai teigė, kad FPU žymiai padidina „animacijos vilkimo“ jutikliniame ekrane greitį. Slankiojo kablelio skaičiavimų judėjimo blokuose gali būti žymiai mažiau, ir tai priklauso nuo konkretaus pavyzdžio.

Veiksmingiausia idėja buvo perkelti kadrų buferį iš SDRAM į vidinę atmintį. Norėdami tai padaryti, ekrano matmenis padarėme ne 480x272, o 272x272. Taip pat sumažinome spalvų gylį nuo A8R8G8B8 iki R5G6B5, taip sumažindami vieno pikselio dydį nuo 4 iki 2 baitų. Gautas kadrų buferio dydis yra 272 * 272 * 2 = 147968 baitai. Tai davė reikšmingą pagreitį, bene labiausiai pastebima, kad animacija tapo beveik sklandi.

Naujausias optimizavimas buvo paleisti Embox kodą iš RAM ir Qt kodą iš SDRAM. Norėdami tai padaryti, pirmiausia, kaip įprasta, statiškai susiejame Embox su Qt, tačiau bibliotekos tekstą, rodata, duomenis ir bss segmentus įdedame į QSPI, kad vėliau nukopijuotume jį į 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))

Vykdydami Embox kodą iš ROM, taip pat gavome pastebimą pagreitį. Dėl to animacija pasirodė gana sklandi:


Pačioje pabaigoje ruošiant straipsnį ir bandant įvairias Embox konfigūracijas, paaiškėjo, kad Qt moveblocks puikiai veikia nuo QSPI su kadrų buferiu SDRAM, o kliūtis buvo būtent kadrų buferio dydis! Matyt, norint įveikti pradinį „skaidrių demonstravimą“, pakako 2 kartų pagreičio dėl banalaus kadrų buferio dydžio sumažinimo. Bet tokio rezultato pasiekti perkeliant tik Embox kodą į įvairius greitus prisiminimus nepavyko (pagreitis buvo ne 2, o apie 1.5 karto).

Kaip pačiam išbandyti

Jei turite STM32F7-Discovery, galite patys paleisti Qt naudodami Embox. Kaip tai daroma, galite perskaityti mūsų svetainėje wiki.

išvada

Dėl to mums pavyko paleisti Qt! Užduoties sudėtingumas, mūsų nuomone, yra šiek tiek perdėtas. Natūralu, kad reikia atsižvelgti į mikrovaldiklių specifiką ir apskritai suprasti kompiuterinių sistemų architektūrą. Optimizavimo rezultatai rodo gerai žinomą faktą, kad kompiuterinės sistemos kliūtis yra ne procesorius, o atmintis.

Šiais metais dalyvausime festivalyje TechTrain. Ten mes jums papasakosime išsamiau ir parodysime Qt, OpenCV ant mikrovaldiklių ir kitus mūsų pasiekimus.

Šaltinis: www.habr.com

Добавить комментарий