Qt pārneŔana uz STM32

Qt pārneÅ”ana uz STM32Labdien Mēs esam projektā Embox uzsāka Qt vietnē STM32F7-Discovery un vēlētos par to runāt. IepriekÅ” mēs jau stāstÄ«jām, kā mums izdevās palaist OpenCV.

Qt ir starpplatformu sistēma, kas ietver ne tikai grafiskos komponentus, bet arÄ« tādas lietas kā QtNetwork, klaÅ”u kopu darbam ar datu bāzēm, Qt automatizācijai (tostarp IoT ievieÅ”anai) un daudz ko citu. Qt komanda ir aktÄ«vi izmantojusi Qt iegultās sistēmās, tāpēc bibliotēkas ir diezgan konfigurējamas. Tomēr vēl nesen retais domāja par Qt pārneÅ”anu uz mikrokontrolleriem, iespējams, tāpēc, ka Ŕāds uzdevums Ŕķiet grÅ«ts - Qt ir liels, MCU ir mazi.

No otras puses, Å”obrÄ«d ir mikrokontrolleri, kas paredzēti darbam ar multimediju un ir labāki par pirmajiem Pentiums. Apmēram pirms gada parādÄ«jās Qt emuārs post. Izstrādātāji izveidoja Qt portu operētājsistēmai RTEMS un palaida piemērus ar logrÄ«kiem vairākās platēs, kurās darbojas stm32f7. Tas mÅ«s ieinteresēja. Bija manāms, un paÅ”i izstrādātāji par to raksta, ka Qt ir lēns STM32F7-Discovery. Mēs domājām, vai mēs varētu palaist Qt zem Embox un ne tikai uzzÄ«mēt logrÄ«ku, bet arÄ« palaist animāciju.

Qt 4.8 jau ilgu laiku ir pārnests uz Embox, tāpēc mēs nolēmām to izmēģināt. Izvēlējāmies aplikāciju moveblocks ā€“ atsperÄ«gas animācijas piemēru.

Qt pārvietoŔanas bloki QEMUQt pārneŔana uz STM32

Sākumā mēs konfigurējam Qt, ja iespējams, ar minimālo komponentu komplektu, kas nepiecieÅ”ams animācijas atbalstam. Å im nolÅ«kam ir opcija ā€œ-qconfig minimāls, mazs, vidējs...ā€. Tas savieno Qt konfigurācijas failu ar daudziem makro - ko iespējot / ko atspējot. Pēc Ŕīs opcijas mēs konfigurācijai pievienojam citus karogus, ja vēlamies atspējot kaut ko citu. Å eit ir mÅ«su piemērs konfigurācija.

Lai Qt darbotos, jāpievieno OS saderÄ«bas slānis. Viens no veidiem ir ieviest QPA (Qt Platform Abstraction). Par pamatu ņēmām Qt iekļauto gatavo fb_base spraudni, uz kura pamata darbojas QPA for Linux. Rezultāts ir neliels spraudnis ar nosaukumu emboxfb, kas nodroÅ”ina Qt ar Embox kadru buferi, un pēc tam tas tiek zÄ«mēts bez jebkādas ārējas palÄ«dzÄ«bas.

Šādi izskatās spraudņa izveide

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

Un Ŕādi izskatÄ«sies pārzÄ«mējums

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

Rezultātā, ja ir iespējota kompilatora optimizācija atmiņas izmēram -Os, bibliotēkas attēls izrādÄ«jās 3.5 MB, kas, protams, neietilpst STM32F746 galvenajā atmiņā. Kā mēs jau rakstÄ«jām citā mÅ«su rakstā par OpenCV, Å”ajā panelÄ« ir:

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

Tā kā OpenCV jau ir pievienots QSPI koda izpildes atbalsts, mēs nolēmām sākt, ielādējot visu Embox c Qt attēlu QSPI. Un urrā, viss sākās gandrīz uzreiz no QSPI! Bet, tāpat kā OpenCV gadījumā, izrādījās, ka tas darbojas pārāk lēni.

Qt pārneŔana uz STM32

Tāpēc mēs nolēmām to darÄ«t Ŕādi - vispirms nokopējam attēlu uz QSPI, pēc tam ielādējam to SDRAM un izpildām no turienes. No SDRAM tas kļuva nedaudz ātrāks, taču joprojām ir tālu no QEMU.

Qt pārneŔana uz STM32

Tālāk radās doma iekļaut peldoÅ”o komatu - galu galā Qt veic dažus kvadrātu koordinātu aprēķinus animācijā. Mēģinājām, bet Å”eit nekādu redzamu paātrinājumu nesaņēmām, kaut gan iekŔā raksts Qt izstrādātāji apgalvoja, ka FPU nodroÅ”ina ievērojamu ātruma palielinājumu ā€œanimācijas vilkÅ”anaiā€ skārienekrānā. Moveblocks var bÅ«t ievērojami mazāk peldoŔā komata aprēķinu, un tas ir atkarÄ«gs no konkrētā piemēra.

VisefektÄ«vākā ideja bija pārvietot kadru buferi no SDRAM uz iekŔējo atmiņu. Lai to izdarÄ«tu, mēs izveidojām ekrāna izmērus nevis 480x272, bet gan 272x272. Mēs arÄ« samazinājām krāsu dziļumu no A8R8G8B8 uz R5G6B5, tādējādi samazinot viena pikseļa izmēru no 4 lÄ«dz 2 baitiem. IegÅ«tais kadru bufera lielums ir 272 * 272 * 2 = 147968 baiti. Tas deva ievērojamu paātrinājumu, iespējams, visievērojamāk, animācija kļuva gandrÄ«z vienmērÄ«ga.

Pēdējā optimizācija bija palaist Embox kodu no RAM un Qt kodu no SDRAM. Lai to izdarītu, mēs vispirms, kā parasti, statiski saistām Embox kopā ar Qt, bet bibliotēkas tekstu, rodata, datu un bss segmentus ievietojam QSPI, lai pēc tam kopētu to uz 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))

Izpildot Embox kodu no ROM, mēs arī saņēmām ievērojamu paātrinājumu. Rezultātā animācija izrādījās diezgan gluda:


PaŔās beigās, gatavojot rakstu un izmēģinot dažādas Embox konfigurācijas, atklājās, ka Qt moveblocks lieliski strādā no QSPI ar kadru buferi SDRAM, un pudeles kakls bija tieÅ”i kadru bufera izmērs! AcÄ«mredzot, lai pārvarētu sākotnējo ā€œslaidrādiā€, pietika ar 2-kārtÄ«gu paātrinājumu, jo tika banāls kadru bufera lieluma samazinājums. Bet Ŕādu rezultātu nebija iespējams sasniegt, pārsÅ«tot tikai Embox kodu uz dažādām ātrajām atmiņām (paātrinājums bija nevis 2, bet apmēram 1.5 reizes).

Kā paÅ”am izmēģināt

Ja jums ir STM32F7-Discovery, varat pats palaist Qt sadaļā Embox. Kā tas tiek darīts, varat lasīt mūsu vietnē wiki.

Secinājums

Rezultātā mums izdevās palaist Qt! Uzdevuma sarežģītÄ«ba, mÅ«suprāt, ir nedaudz pārspÄ«lēta. Protams, jums ir jāņem vērā mikrokontrolleru specifika un vispārēji jāsaprot datorsistēmu arhitektÅ«ra. Optimizācijas rezultāti norāda uz labi zināmo faktu, ka skaitļoÅ”anas sistēmas saÅ”aurinājums nav procesors, bet gan atmiņa.

Šogad piedalīsimies festivālā TechTrain. Tur pastāstīsim sīkāk un parādīsim Qt, OpenCV uz mikrokontrolleriem un citus mūsu sasniegumus.

Avots: www.habr.com

Pievieno komentāru