Porting Qt al STM32

Porting Qt al STM32Bonan posttagmezon Ni estas en la projekto Embox lanĉis Qt sur STM32F7-Discovery kaj ŝatus paroli pri ĝi. Antaŭe, ni jam rakontis kiel ni sukcesis lanĉi OpenCV.

Qt estas transplatforma kadro, kiu inkluzivas ne nur grafikajn komponentojn, sed ankaŭ tiajn aferojn kiel QtNetwork, aron da klasoj por labori kun datumbazoj, Qt por Aŭtomatigo (inkluzive por IoT-efektivigo) kaj multe pli. La Qt-teamo estis iniciatema pri uzado de Qt en enigitaj sistemoj, do la bibliotekoj estas sufiĉe agordeblaj. Tamen, ĝis antaŭ nelonge, malmultaj homoj pensis pri porti Qt al mikroregiloj, verŝajne ĉar tia tasko ŝajnas malfacila - Qt estas granda, MCUoj estas malgrandaj.

Aliflanke, nuntempe ekzistas mikrokontroliloj destinitaj por labori kun plurmediaj kaj superaj ol la unuaj Pentiums. Antaŭ ĉirkaŭ unu jaro aperis la blogo Qt afiŝo. La programistoj faris havenon de Qt por la RTEMS OS, kaj lanĉis ekzemplojn kun fenestraĵoj sur pluraj tabuloj kurantaj stm32f7. Ĉi tio interesis nin. Estis rimarkeble, kaj la programistoj mem skribas pri ĝi, ke Qt malrapidas ĉe la STM32F7-Discovery. Ni scivolis ĉu ni povus ruli Qt sub Embox, kaj ne nur desegni fenestraĵon, sed ruli animacion.

Qt 4.8 estis portita al Embox dum longa tempo, do ni decidis provi ĝin sur ĝi. Ni elektis la aplikaĵon moveblocks - ekzemplo de printempa animacio.

Qt moveblocks sur QEMUPorting Qt al STM32

Komence, ni agordas Qt, se eble, kun la minimuma aro de komponantoj necesaj por subteni animacion. Por tio ekzistas opcio "-qconfig minimuma, malgranda, meza...". Ĝi ligas agordan dosieron de Qt kun multaj makrooj - kion ebligi / kion malŝalti. Post ĉi tiu opcio, ni aldonas aliajn flagojn al la agordo se ni volas malŝalti ion alian. Jen ekzemplo de nia agordo.

Por ke Qt funkciu, vi devas aldoni OS-kongruan tavolon. Unu maniero estas efektivigi QPA (Qt Platform Abstraction). Ni prenis kiel bazon la pretan fb_base kromaĵon inkluzivita en Qt, surbaze de kiu QPA por Linukso funkcias. La rezulto estas malgranda kromaĵo nomata emboxfb, kiu provizas Qt per la framebuffer de Embox, kaj poste ĝi desegnas tie sen ia ekstera helpo.

Jen kiel aspektas krei kromprogramon

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

Kaj jen kiel aspektos la redesegnaĵo

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

Kiel rezulto, kun la kompililo optimumigo por memorgrandeco -Os ebligita, la biblioteko bildo montriĝis esti 3.5 MB, kiu kompreneble ne konvenas en la ĉefa memoro de la STM32F746. Kiel ni jam skribis en nia alia artikolo pri OpenCV, ĉi tiu tabulo havas:

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

Ĉar subteno por ekzekuti kodon de QSPI jam estis aldonita al OpenCV, ni decidis komenci ŝarĝante la tutan bildon de Embox c Qt en QSPI. Kaj hure, ĉio komenciĝis preskaŭ tuj de QSPI! Sed kiel en la kazo de OpenCV, montriĝis, ke ĝi funkcias tro malrapide.

Porting Qt al STM32

Tial ni decidis fari ĝin tiel - unue ni kopias la bildon al QSPI, poste ŝarĝas ĝin en SDRAM kaj ekzekutas de tie. De SDRAM ĝi fariĝis iom pli rapida, sed ankoraŭ malproksime de QEMU.

Porting Qt al STM32

Poste, estis ideo inkluzivi glitkomon - finfine, Qt faras kelkajn kalkulojn de la koordinatoj de kvadratoj en animacio. Ni provis, sed ĉi tie ni ne ricevis ajnan videblan akcelon, kvankam en artikolo Qt-programistoj asertis, ke FPU donas signifan pliiĝon en rapideco por "trenado de animacio" sur tuŝekrano. Povas ekzisti signife malpli da glitkomaj kalkuloj en movblokoj, kaj tio dependas de la specifa ekzemplo.

La plej efika ideo estis movi la framebuffer de SDRAM al interna memoro. Por fari tion, ni faris la ekranajn dimensiojn ne 480x272, sed 272x272. Ni ankaŭ malaltigis la kolorprofundon de A8R8G8B8 al R5G6B5, tiel reduktante la grandecon de unu pikselo de 4 ĝis 2 bajtoj. La rezulta frambuffer grandeco estas 272 * 272 * 2 = 147968 bajtoj. Ĉi tio donis gravan akcelon, eble plej rimarkinde, la animacio fariĝis preskaŭ glata.

La plej nova optimumigo estis ruli Embox-kodon de RAM kaj Qt-kodon de SDRAM. Por fari tion, ni unue, kiel kutime, statike ligas Embox kune kun Qt, sed ni metas la tekstojn, rodatajn, datumojn kaj bss-segmentojn de la biblioteko en QSPI por tiam kopii ĝin al 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))

Ekzekutante la Embox-kodon el ROM, ni ankaŭ ricevis rimarkindan akcelon. Kiel rezulto, la animacio rezultis sufiĉe glata:


Ĉe la fino, dum preparante la artikolon kaj provante malsamajn Embox-agordojn, montriĝis, ke Qt moveblocks funkcias bonege de QSPI kun framebuffer en SDRAM, kaj la botelkolo estis ĝuste la grandeco de la framebuffer! Ŝajne, por venki la komencan "diagramon", 2-obla akcelo sufiĉis pro banala redukto de la grandeco de la kadrobufro. Sed ne eblis atingi tian rezulton transdonante nur la Embox-kodon al diversaj rapidaj memoroj (la akcelo ne estis 2, sed ĉirkaŭ 1.5 fojojn).

Kiel provi ĝin mem

Se vi havas STM32F7-Discovery, vi mem povas ruli Qt sub Embox. Vi povas legi kiel ĉi tio estas farita sur nia vikio.

konkludo

Kiel rezulto, ni sukcesis lanĉi Qt! La komplekseco de la tasko, laŭ nia opinio, estas iom troigita. Kompreneble, vi devas konsideri la specifaĵojn de mikroregiloj kaj ĝenerale kompreni la arkitekturon de komputilaj sistemoj. La optimumigo-rezultoj montras al la konata fakto, ke la botelkolo en komputika sistemo ne estas la procesoro, sed la memoro.

Ĉi-jare ni partoprenos en la festivalo TechTrain. Tie ni rakontos al vi pli detale kaj montros Qt, OpenCV sur mikroregiloj kaj niajn aliajn atingojn.

fonto: www.habr.com

Aldoni komenton