Transferimi i Qt në STM32

Transferimi i Qt në STM32Mirembrema Jemi në projekt Embox lançoi Qt në STM32F7-Discovery dhe do të doja të flisja për të. Më parë, ne kemi thënë tashmë se si arritëm të nisnim OpenCV.

Qt është një kornizë ndër-platformë që përfshin jo vetëm komponentë grafikë, por edhe gjëra të tilla si QtNetwork, një grup klasash për të punuar me bazat e të dhënave, Qt për Automatizim (përfshirë për zbatimin e IoT) dhe shumë më tepër. Ekipi Qt ka qenë proaktiv në lidhje me përdorimin e Qt në sistemet e integruara, kështu që bibliotekat janë mjaft të konfigurueshme. Sidoqoftë, deri vonë, pak njerëz menduan të transferonin Qt te mikrokontrolluesit, ndoshta sepse një detyrë e tillë duket e vështirë - Qt është i madh, MCU-të janë të vogla.

Nga ana tjetër, për momentin ka mikrokontrollues të projektuar për të punuar me multimedia dhe superiorë se Pentium-ët e parë. Rreth një vit më parë, u shfaq blogu Qt post. Zhvilluesit krijuan një port të Qt për RTEMS OS dhe lëshuan shembuj me miniaplikacione në disa tabela që funksionojnë stm32f7. Kjo na interesoi. Ishte e dukshme, dhe vetë zhvilluesit shkruajnë për këtë, se Qt është i ngadalshëm në STM32F7-Discovery. Po pyesnim nëse mund të ekzekutonim Qt nën Embox, dhe jo vetëm të vizatonim një widget, por të ekzekutonim një animacion.

Qt 4.8 është transferuar në Embox për një kohë të gjatë, kështu që vendosëm ta provonim në të. Ne zgjodhëm aplikacionin Moveblocks - një shembull i animacionit tërheqës.

Qt bllokon lëvizjen në QEMUTransferimi i Qt në STM32

Për të filluar, ne konfigurojmë Qt, nëse është e mundur, me grupin minimal të komponentëve të kërkuar për të mbështetur animacionin. Për këtë ekziston një opsion "-qconfig minimal, i vogël, i mesëm...". Ai lidh një skedar konfigurimi nga Qt me shumë makro - çfarë të aktivizoni / çfarë të çaktivizoni. Pas këtij opsioni, ne shtojmë flamuj të tjerë në konfigurim nëse duam të çaktivizojmë diçka tjetër. Këtu është një shembull i yni konfigurimi.

Në mënyrë që Qt të funksionojë, duhet të shtoni një shtresë të përputhshmërisë së OS. Një mënyrë është zbatimi i QPA (Qt Platform Abstraction). Ne morëm si bazë shtojcën e gatshme fb_base të përfshirë në Qt, në bazë të së cilës funksionon QPA për Linux. Rezultati është një shtojcë e vogël e quajtur emboxfb, e cila i siguron Qt-së kornizën e embox-it, dhe më pas e tërheq atje pa ndonjë ndihmë nga jashtë.

Kështu duket krijimi i një shtojce

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

Dhe kështu do të duket rivizatimi

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

Si rezultat, me aktivizimin e optimizimit të përpiluesit për madhësinë e kujtesës -Os, imazhi i bibliotekës doli të ishte 3.5 MB, i cili natyrisht nuk përshtatet në memorien kryesore të STM32F746. Siç kemi shkruar tashmë në artikullin tonë tjetër rreth OpenCV, ky bord ka:

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

Meqenëse mbështetja për ekzekutimin e kodit nga QSPI është shtuar tashmë në OpenCV, vendosëm të fillojmë duke ngarkuar të gjithë imazhin Embox c Qt në QSPI. Dhe urray, gjithçka filloi pothuajse menjëherë nga QSPI! Por si në rastin e OpenCV, doli se funksionon shumë ngadalë.

Transferimi i Qt në STM32

Prandaj, vendosëm ta bëjmë në këtë mënyrë - fillimisht kopjojmë imazhin në QSPI, më pas e ngarkojmë në SDRAM dhe e ekzekutojmë prej andej. Nga SDRAM u bë pak më i shpejtë, por ende larg QEMU.

Transferimi i Qt në STM32

Më pas, ishte një ide për të përfshirë një pikë lundruese - në fund të fundit, Qt bën disa llogaritje të koordinatave të katrorëve në animacion. Ne u përpoqëm, por këtu nuk patëm ndonjë përshpejtim të dukshëm, megjithëse brenda artikull Zhvilluesit e Qt pohuan se FPU jep një rritje të konsiderueshme të shpejtësisë për "zvarritjen e animacionit" në ekranin me prekje. Mund të ketë shumë më pak përllogaritje me pikë lundruese në blloqe lëvizëse, dhe kjo varet nga shembulli specifik.

Ideja më efektive ishte zhvendosja e framebuffer-it nga SDRAM në memorien e brendshme. Për ta bërë këtë, ne bëmë dimensionet e ekranit jo 480x272, por 272x272. Ne gjithashtu ulëm thellësinë e ngjyrës nga A8R8G8B8 në R5G6B5, duke zvogëluar kështu madhësinë e një piksel nga 4 në 2 bajt. Madhësia e kornizës që rezulton është 272 * 272 * 2 = 147968 bajt. Kjo dha një përshpejtim të konsiderueshëm, ndoshta më e dukshme, animacioni u bë pothuajse i qetë.

Optimizimi i fundit ishte ekzekutimi i kodit Embox nga RAM dhe kodi Qt nga SDRAM. Për ta bërë këtë, ne fillimisht, si zakonisht, lidhim statikisht Embox së bashku me Qt, por vendosim tekstin, rodata, të dhënat dhe segmentet bss të bibliotekës në QSPI për ta kopjuar atë në 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))

Duke ekzekutuar kodin Embox nga ROM-i, kemi marrë gjithashtu një përshpejtim të dukshëm. Si rezultat, animacioni doli mjaft i qetë:


Në fund, gjatë përgatitjes së artikullit dhe testimit të konfigurimeve të ndryshme të Embox, rezultoi se Qt moveblocks funksionon shkëlqyeshëm nga QSPI me një framebuffer në SDRAM, dhe pengesa ishte pikërisht madhësia e framebuffer-it! Me sa duket, për të kapërcyer "slideshow" fillestar, një përshpejtim 2-fish ishte i mjaftueshëm për shkak të një zvogëlimi banal të madhësisë së kornizës. Por nuk ishte e mundur të arrihej një rezultat i tillë duke transferuar vetëm kodin Embox në memorie të ndryshme të shpejta (përshpejtimi nuk ishte 2, por rreth 1.5 herë).

Si ta provoni vetë

Nëse keni një STM32F7-Discovery, mund ta ekzekutoni vetë Qt nën Embox. Ju mund të lexoni se si bëhet kjo në faqen tonë wiki.

Përfundim

Si rezultat, ne arritëm të lëshonim Qt! Kompleksiteti i detyrës, për mendimin tonë, është disi i ekzagjeruar. Natyrisht, ju duhet të merrni parasysh specifikat e mikrokontrolluesve dhe në përgjithësi të kuptoni arkitekturën e sistemeve kompjuterike. Rezultatet e optimizimit tregojnë për faktin e mirënjohur se pengesa në një sistem kompjuterik nuk është procesori, por memoria.

Këtë vit do të marrim pjesë në festival TechTrain. Aty do t'ju tregojmë më në detaje dhe do t'ju tregojmë Qt, OpenCV në mikrokontrolluesit dhe arritjet tona të tjera.

Burimi: www.habr.com

Shto një koment