Qt-ı STM32-ə köçürmək

Qt-ı STM32-ə köçürməkGünortanız Xeyir Biz layihədəyik Emboks STM32F7-Discovery-də Qt-ni işə saldı və bu barədə danışmaq istərdim. Daha əvvəl necə işə salmağı bacardığımızı artıq söylədik OpenCV.

Qt, təkcə qrafik komponentləri deyil, həm də QtNetwork, verilənlər bazası ilə işləmək üçün siniflər dəsti, Avtomatlaşdırma üçün Qt (o cümlədən IoT tətbiqi üçün) və daha çox şeyləri əhatə edən çarpaz platforma çərçivəsidir. Qt komandası daxili sistemlərdə Qt-dan istifadə etməkdə fəal olmuşdur, buna görə də kitabxanalar kifayət qədər konfiqurasiya edilə bilər. Bununla belə, son vaxtlara qədər az adam Qt-ni mikrokontrollerlərə köçürmək barədə düşünürdü, yəqin ki, belə bir iş çətin göründüyü üçün - Qt böyükdür, MCU-lar kiçikdir.

Digər tərəfdən, hazırda multimedia ilə işləmək üçün nəzərdə tutulmuş və ilk Pentium-lardan üstün olan mikrokontrollerlər mövcuddur. Təxminən bir il əvvəl Qt bloqu peyda oldu yazı. Tərtibatçılar RTEMS ƏS üçün Qt portu yaratdılar və stm32f7 ilə işləyən bir neçə lövhədə vidjetlərlə nümunələri işə saldılar. Bu bizi maraqlandırdı. Bu diqqətəlayiq idi və tərtibatçıların özləri bu barədə yazırlar ki, Qt STM32F7-Discovery-də yavaşdır. Biz maraqlanırdıq ki, biz Qt-ı Embox altında işlədə bilərikmi və sadəcə bir vidcet çəkməklə yanaşı, animasiya da işlədə bilərik.

Qt 4.8 uzun müddətdir Embox-a köçürülüb, ona görə də biz onu sınamaq qərarına gəldik. Moveblocks tətbiqini seçdik - yaylı animasiya nümunəsi.

QEMU-da Qt hərəkət bloklarıQt-ı STM32-ə köçürmək

Başlamaq üçün, Qt-ni, mümkünsə, animasiyanı dəstəkləmək üçün tələb olunan minimum komponentlər dəsti ilə konfiqurasiya edirik. Bunun üçün “-qconfig minimal, kiçik, orta...” seçimi var. Qt-dan konfiqurasiya faylını bir çox makro ilə birləşdirir - nəyi aktivləşdirmək / nəyi söndürmək. Bu seçimdən sonra başqa bir şeyi aradan qaldırmaq istəsək, konfiqurasiyaya başqa bayraqlar əlavə edirik. Budur bizim nümunəmiz konfiqurasiya.

Qt-nin işləməsi üçün OS uyğunluq qatını əlavə etməlisiniz. Bir yol QPA (Qt Platform Abstraction) tətbiq etməkdir. Qt-a daxil olan hazır fb_base plaginini əsas götürdük, bunun əsasında Linux üçün QPA işləyir. Nəticə Qt-ni Embox-un çərçivə buferi ilə təmin edən emboxfb adlı kiçik bir plagindir və sonra heç bir kənar yardım olmadan orada çəkir.

Plugin yaratmaq belə görünür

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

Və yenidən çəkiliş belə görünəcək

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

Nəticədə, yaddaş ölçüsü üçün kompilyatorun optimallaşdırılması -Os aktivləşdirildikdə, kitabxana şəkli 3.5 MB oldu, bu, əlbəttə ki, STM32F746-nın əsas yaddaşına uyğun gəlmir. OpenCV haqqında digər məqaləmizdə artıq yazdığımız kimi, bu lövhədə:

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

QSPI-dən kodun icrası üçün dəstək artıq OpenCV-ə əlavə olunduğundan, biz bütün Embox c Qt şəklini QSPI-yə yükləməklə başlamaq qərarına gəldik. Və hurray, hər şey demək olar ki, dərhal QSPI-dən başladı! Ancaq OpenCV-də olduğu kimi, onun çox yavaş işlədiyi ortaya çıxdı.

Qt-ı STM32-ə köçürmək

Buna görə də biz bunu belə etmək qərarına gəldik - əvvəlcə şəkli QSPI-yə köçürür, sonra SDRAM-a yükləyirik və oradan icra edirik. SDRAM-dan bir az daha sürətli oldu, lakin hələ də QEMU-dan uzaqlaşdı.

Qt-ı STM32-ə köçürmək

Sonra, üzən nöqtəni daxil etmək fikri var idi - axı Qt animasiyada kvadratların koordinatlarının bəzi hesablamalarını edir. Çalışdıq, amma burada olsa da, görünən bir sürətlənmə əldə etmədik məqalə Qt tərtibatçıları iddia etdilər ki, FPU toxunma ekranında "animasiyanı sürükləmək" üçün sürətdə əhəmiyyətli bir artım verir. Hərəkət bloklarında üzən nöqtə hesablamaları əhəmiyyətli dərəcədə az ola bilər və bu, konkret nümunədən asılıdır.

Ən təsirli ideya çərçivə buferini SDRAM-dan daxili yaddaşa köçürmək idi. Bunun üçün ekran ölçülərini 480x272 deyil, 272x272 etdik. Rəng dərinliyini A8R8G8B8-dən R5G6B5-ə endirdik, beləliklə, bir pikselin ölçüsünü 4 baytdan 2 bayta endirdik. Nəticədə çərçivə buferinin ölçüsü 272 * 272 * 2 = 147968 baytdır. Bu, əhəmiyyətli bir sürətlənmə verdi, bəlkə də ən nəzərəçarpacaq dərəcədə animasiya demək olar ki, hamar oldu.

Ən son optimallaşdırma RAM-dan Embox kodunu və SDRAM-dan Qt kodunu işə salmaq idi. Bunu etmək üçün, biz ilk növbədə, həmişə olduğu kimi, Embox-u Qt ilə statik olaraq əlaqələndiririk, lakin sonra onu SDRAM-a köçürmək üçün kitabxananın mətnini, rodata, data və bss seqmentlərini QSPI-də yerləşdiririk.

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))

ROM-dan Embox kodunu yerinə yetirməklə biz də nəzərəçarpacaq sürətlənmə əldə etdik. Nəticədə, animasiya olduqca hamar oldu:


Ən sonunda məqaləni hazırlayarkən və müxtəlif Embox konfiqurasiyalarını sınayarkən məlum oldu ki, Qt hərəkət blokları QSPI-dən SDRAM-da çərçivə buferi ilə əla işləyir və darboğaz tam olaraq çərçivə buferinin ölçüsündə idi! Göründüyü kimi, ilkin "slayd şousunu" aradan qaldırmaq üçün çərçivə buferinin ölçüsünün banal azalması səbəbindən 2 qat sürətlənmə kifayət idi. Ancaq yalnız Embox kodunu müxtəlif sürətli yaddaşlara köçürməklə belə bir nəticə əldə etmək mümkün olmadı (sürətlənmə 2 yox, təxminən 1.5 dəfə idi).

Bunu özünüz necə sınamaq olar

Əgər sizdə STM32F7-Discovery varsa, Qt-ı Embox altında özünüz işlədə bilərsiniz. Bunun necə edildiyini bizim səhifəmizdə oxuya bilərsiniz wiki.

Nəticə

Nəticədə biz Qt-ni işə sala bildik! Tapşırığın mürəkkəbliyi, fikrimizcə, bir qədər şişirdilmişdir. Təbii ki, mikrokontrollerlərin xüsusiyyətlərini nəzərə almalı və ümumiyyətlə kompüter sistemlərinin arxitekturasını başa düşməlisiniz. Optimallaşdırma nəticələri məlum faktı göstərir ki, hesablama sistemindəki darboğaz prosessor deyil, yaddaşdır.

Bu il festivalda iştirak edəcəyik Texniki qatar. Orada sizə daha ətraflı məlumat verəcəyik və mikrokontrollerlərdə Qt, OpenCV və digər nailiyyətlərimizi göstərəcəyik.

Mənbə: www.habr.com

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