Porting Qt à STM32

Porting Qt à STM32Bonghjornu Semu in u prugettu Embox lanciatu Qt nantu à STM32F7-Discovery è vulete parlà. Nanzu, avemu digià dettu cumu avemu riisciutu à lancià OpenCV.

Qt hè un quadru multiplataforma chì include micca solu cumpunenti gràfiche, ma ancu cose cum'è QtNetwork, un inseme di classi per travaglià cù basa di dati, Qt for Automation (cumpresu per l'implementazione IoT) è assai più. A squadra di Qt hè stata proattiva per l'usu di Qt in sistemi incrustati, cusì e librerie sò abbastanza configurabili. Tuttavia, finu à pocu tempu, pochi pirsuni pensavanu à portà Qt à i microcontrollers, probabilmente perchè un tali compitu pare difficiule - Qt hè grande, MCU sò chjuchi.

Per d 'altra banda, in u mumentu ci sò microcontrollers pensati per travaglià cù multimedia è superiore à i primi Pentiums. Circa un annu fà, u blog Qt apparsu post. I sviluppatori anu fattu un portu di Qt per u RTEMS OS, è hà lanciatu esempi cù widgets nantu à parechje schede chì currenu stm32f7. Questu ci hà interessatu. Era notu, è i sviluppatori stessi scrivenu nantu à questu, chì Qt hè lentu nantu à u STM32F7-Discovery. Ci dumandavamu se pudemu eseguisce Qt sottu Embox, è micca solu disegnà un widget, ma eseguisce una animazione.

Qt 4.8 hè stata portata à Embox per un bellu pezzu, cusì avemu decisu di pruvà. Avemu sceltu l'applicazione moveblocks - un esempiu di animazione primavera.

Qt moveblocks nantu à QEMUPorting Qt à STM32

Per principià, cunfiguremu Qt, se pussibule, cù u settore minimu di cumpunenti necessarii per sustene l'animazione. Per questu ci hè una opzione "-qconfig minimal, small, medium...". Cunnette un schedariu di cunfigurazione da Qt cù parechje macros - ciò chì attivà / ciò chì disattivà. Dopu sta opzione, aghjustemu altre bandiere à a cunfigurazione se vulemu disattivà qualcosa altru. Eccu un esempiu di u nostru cunfigurazione.

Per u travagliu di Qt, avete bisognu di aghjunghje una capa di cumpatibilità OS. Un modu hè di implementà QPA (Qt Platform Abstraction). Avemu pigliatu com'è basa u plugin ready-made fb_base inclusu in Qt, nantu à a basa di quale QPA per Linux travaglia. U risultatu hè un picculu plugin chjamatu emboxfb, chì furnisce Qt cù u framebuffer d'Embox, è poi disegna quì senza aiutu esternu.

Questu hè ciò chì crea un plugin pare

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

È questu hè ciò chì u redisegnu parerà

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

In u risultatu, cù l'ottimisazione di u compilatore per a dimensione di memoria -Os attivata, l'imaghjina di a biblioteca hè stata 3.5 MB, chì di sicuru ùn si mette in a memoria principale di u STM32F746. Cum'è avemu digià scrittu in u nostru altru articulu nantu à OpenCV, sta scheda hà:

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

Siccomu u supportu per eseguisce u codice da QSPI hè digià aghjuntu à OpenCV, avemu decisu di principià per carricà tutta l'imaghjini di Embbox c Qt in QSPI. E hurrah, tuttu hà cuminciatu quasi subitu da QSPI! Ma cum'è in u casu di l'OpenCV, hè statu chì travaglia troppu pianu.

Porting Qt à STM32

Dunque, avemu decisu di fà questu modu - prima copiamu l'imaghjini à QSPI, poi caricate in SDRAM è eseguite da quì. Da SDRAM hè diventatu un pocu più veloce, ma sempre luntanu da QEMU.

Porting Qt à STM32

In seguitu, ci era una idea di include un puntu flottante - dopu à tuttu, Qt faci qualchì calculu di e coordenate di i quadrati in animazione. Avemu pruvatu, ma quì ùn avemu micca avutu alcuna accelerazione visibile, anche se in articulu I sviluppatori di Qt anu dichjaratu chì FPU dà un aumentu significativu di a velocità per "trascinà l'animazione" nantu à u touchscreen. Ci pò esse significativamente menu calculi in virgule flottante in moveblocks, è questu dipende da l'esempiu specificu.

L'idea più efficace era di trasfurmà u framebuffer da SDRAM à a memoria interna. Per fà questu, avemu fattu a dimensione di u screnu micca 480x272, ma 272x272. Avemu ancu calatu a prufundità di culore da A8R8G8B8 à R5G6B5, riducendu cusì a dimensione di un pixel da 4 à 2 bytes. A dimensione di framebuffer risultatu hè 272 * 272 * 2 = 147968 bytes. Questu hà datu una accelerazione significativa, forse più notevolmente, l'animazione hè diventata quasi liscia.

L'ultima ottimisazione era di eseguisce u codice Embox da RAM è u codice Qt da SDRAM. Per fà questu, prima, cum'è di solitu, ligame staticamente Embo cù Qt, ma pusemu u testu, rodata, dati è segmenti bss di a biblioteca in QSPI per poi copià in 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))

Eseguendu u codice Embox da ROM, avemu ancu ricevutu una accelerazione notevuli. In u risultatu, l'animazione hè stata abbastanza liscia:


À a fine, mentre preparava l'articulu è provava diverse cunfigurazioni di l'Embox, hè risultatu chì Qt moveblocks funziona bè da QSPI cù un framebuffer in SDRAM, è u bottleneck era precisamente a dimensione di u framebuffer! Apparentemente, per superà u "slideshow" iniziale, una accelerazione di 2 volte era abbastanza per una riduzione banale di a dimensione di u framebuffer. Ma ùn era micca pussibule di ottene un tali risultatu trasfirendu solu u codice Embox à diversi ricordi veloci (l'accelerazione ùn era micca 2, ma circa 1.5 volte).

Cumu pruvà sè stessu

Sì avete un STM32F7-Discovery, pudete eseguisce Qt sottu Embbox stessu. Pudete leghje cumu questu hè fattu nantu à u nostru wiki.

cunchiusioni

In u risultatu, avemu riesciutu à lancià Qt! A cumplessità di u travagliu, in u nostru parè, hè un pocu esageratu. Naturalmente, avete bisognu di piglià in contu e specificità di i microcontrollers è in generale capisce l'architettura di i sistemi informatici. I risultati di l'ottimisazione indicanu u fattu cunnisciutu chì u collu di buttiglia in un sistema di computing ùn hè micca u processatore, ma a memoria.

Quist'annu avemu da participà à a festa TechTrain. Quì vi diciaremu in più dettagliu è mustrà Qt, OpenCV nantu à i microcontrollers è i nostri altri rializazioni.

Source: www.habr.com

Add a comment