نقل كيو تي إلى STM32

نقل كيو تي إلى STM32مساء الخير نحن في المشروع امبوكس أطلقت Qt على STM32F7-Discovery وأود التحدث عنها. في وقت سابق ، أخبرنا بالفعل كيف تمكنا من الإطلاق مكتبة برمجية مفتوحة للرؤية الحاسوبية.

Qt عبارة عن إطار عمل عبر الأنظمة الأساسية لا يتضمن مكونات رسومية فحسب ، بل يتضمن أيضًا أشياء مثل QtNetwork ، ومجموعة من الفئات للعمل مع قواعد البيانات ، و Qt for Automation (بما في ذلك تنفيذ IoT) وغير ذلك الكثير. توقع مطورو فريق Qt استخدام Qt في الأنظمة المدمجة ، لذا فإن المكتبات قابلة للتكوين بشكل جيد. ومع ذلك ، حتى وقت قريب ، كان عدد قليل من الناس يفكرون في تحويل Qt إلى ميكروكنترولر ، ربما لأن مثل هذه المهمة تبدو صعبة - Qt كبير ، MCUs صغيرة.

من ناحية أخرى ، توجد في الوقت الحالي وحدات تحكم دقيقة مصممة للعمل مع الوسائط المتعددة وتجاوز وحدات بنتيوم الأولى. ظهرت على مدونة كيو تي منذ حوالي عام بعد. قام المطورون بإنشاء منفذ Qt ضمن نظام التشغيل RTEMS ، وقاموا بتشغيل أمثلة مع عناصر واجهة مستخدم على العديد من اللوحات التي تعمل بنظام stm32f7. نحن مهتمون بهذا. كان من الملاحظ ، والمطورين أنفسهم يكتبون عن ذلك ، أن Qt يبطئ في STM32F7-Discovery. تساءلنا عما إذا كان بإمكاننا تشغيل Qt ضمن Embox ، وليس فقط رسم عنصر واجهة مستخدم ، ولكن تشغيل الرسوم المتحركة.

تم نقل Qt 4.8 إلى Embox لفترة طويلة ، لذلك قررنا تجربته. اخترنا تطبيق moveblocks - مثال على الرسوم المتحركة الربيعية.

Qt moveblocks على QEMUنقل كيو تي إلى STM32

بادئ ذي بدء ، قمنا بتكوين Qt مع الحد الأدنى من مجموعة المكونات المطلوبة لدعم الرسوم المتحركة ، إن أمكن. هناك خيار "-qconfig أدنى ، صغير ، متوسط ​​..." لهذا الغرض. يتضمن ملف تكوين من Qt مع الكثير من وحدات الماكرو - ما الذي يجب تمكينه / ما الذي يجب تعطيله. بعد هذا الخيار ، نضيف علامات أخرى إلى التكوين إذا أردنا تعطيل شيء آخر بالإضافة إلى ذلك. هنا مثال لنا إعدادات.

لكي تعمل Qt ، تحتاج إلى إضافة طبقة توافق نظام التشغيل. إحدى الطرق هي تنفيذ QPA (Qt Platform Abstraction). تم أخذ المكون الإضافي fb_base الجاهز كجزء من Qt كأساس ، والذي على أساسه يعمل QPA لنظام Linux. والنتيجة هي مكون إضافي emboxfb صغير يوفر Qt مع إطار Embox ، ثم يرسم هناك دون مساعدة خارجية.

هذا ما يبدو عليه البرنامج المساعد

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

وهذه هي الطريقة التي ستبدو بها إعادة الرسم

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

نتيجة لذلك ، مع تحسين المحول البرمجي لأحجام الذاكرة الممكّنة ، تحولت صورة المكتبة إلى 3.5 ميغابايت ، وهو بالطبع لا يتناسب مع الذاكرة الرئيسية لـ STM32F746. كما كتبنا في مقالتنا الأخرى حول OpenCV ، فإن هذا المنتدى يحتوي على:

  • 1 ميجا روم
  • 320 كيلو بايت رام
  • 8 ميجا بايت SDRAM
  • 16 ميجا بايت QSPI

نظرًا لأنه تمت إضافة دعم تنفيذ التعليمات البرمجية من QSPI بالفعل إلى OpenCV ، فقد قررنا البدء بتحميل صورة Embox بالكامل مع Qt في QSPI. رائع ، بدأ كل شيء على الفور تقريبًا من QSPI! ولكن كما في حالة OpenCV ، اتضح أنه بطيء جدًا.

نقل كيو تي إلى STM32

لذلك ، قررنا القيام بذلك - أولاً نقوم بنسخ الصورة إلى QSPI ، ثم نقوم بتحميلها في SDRAM وتنفيذها من هناك. من SDRAM أصبح أسرع قليلاً ، لكنه لا يزال بعيدًا عن QEMU.

نقل كيو تي إلى STM32

ثم كانت هناك فكرة لتضمين نقطة عائمة - بعد كل شيء ، يقوم Qt ببعض الحسابات لإحداثيات المربعات في الرسوم المتحركة. لقد حاولنا ، لكننا هنا لم نحصل على تسارع مرئي ، على الرغم من أنه في مقالة ادعى مطورو Qt أن FPU يوفر زيادة كبيرة في سرعة "سحب الرسوم المتحركة" على الشاشة التي تعمل باللمس. قد يكون هناك عدد أقل بكثير من حسابات الفاصلة العائمة في الكتل المتحركة ، ويعتمد ذلك على المثال المحدد.

تبين أن فكرة نقل إطار التخزين المؤقت من ذاكرة SDRAM إلى الذاكرة الداخلية هي الأكثر فعالية. للقيام بذلك ، جعلنا حجم الشاشة ليس 480 × 272 ، ولكن 272 × 272. قمنا أيضًا بتخفيض عمق اللون من A8R8G8B8 إلى R5G6B5 ، وبالتالي قللنا حجم بكسل واحد من 4 إلى 2 بايت. حصلنا على حجم الإطار المؤقت 272 * 272 * 2 = 147968 بايت. أعطى هذا تسريعًا كبيرًا ، ربما يكون أكثر ما يمكن ملاحظته ، أصبحت الرسوم المتحركة سلسة تقريبًا.

كان التحسين الأخير هو تنفيذ كود Embox من ذاكرة الوصول العشوائي ، و Qt من SDRAM. للقيام بذلك ، نقوم أولاً ، كالعادة ، بربط Embox مع Qt بشكل ثابت ، لكننا نضع مقاطع النص ، و rodata ، و data و bss للمكتبة في QSPI لنسخها إلى 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))

من خلال تنفيذ كود Embox من ROM ، حصلنا أيضًا على تسريع ملحوظ. نتيجة لذلك ، اتضح أن الرسوم المتحركة كانت سلسة للغاية:


بالفعل في النهاية ، أثناء تحضير المقال وتجربة تكوينات مختلفة لـ Embox ، اتضح أن Qt moveblocks يعمل بشكل رائع من QSPI مع إطار مؤقت في SDRAM ، وكان عنق الزجاجة هو بالضبط حجم الإطار الاحتياطي! على ما يبدو ، للتغلب على "عرض الشرائح" الأولي ، كان التسارع بمقدار الضعفين كافيًا بسبب انخفاض عادي في حجم الإطار الاحتياطي. لكن لم يكن من الممكن تحقيق مثل هذه النتيجة عن طريق نقل رمز Embox فقط إلى العديد من الذكريات السريعة (لم يكن التسارع 2 ، ولكن حوالي 2 مرة).

كيف تجربها بنفسك

إذا كان لديك STM32F7-Discovery ، فيمكنك تشغيل Qt ضمن Embox بنفسك. يمكنك قراءة كيف يتم ذلك على موقعنا вики.

اختتام

نتيجة لذلك ، تمكنا من بدء Qt! إن تعقيد المهمة ، في رأينا ، مبالغ فيه إلى حد ما. بطبيعة الحال ، يجب أن تأخذ بعين الاعتبار خصوصيات المتحكمات الدقيقة وأن تفهم بشكل عام بنية أنظمة الحوسبة. تشير نتائج التحسين إلى الحقيقة المعروفة ، وهي أن العقبة في نظام الحوسبة ليست المعالج ، بل الذاكرة.

هذا العام سوف نشارك في المهرجان قطار التكنولوجيا. هناك سنخبرنا بمزيد من التفاصيل ونعرض Qt و OpenCV على ميكروكنترولر وإنجازاتنا الأخرى.

المصدر: www.habr.com

إضافة تعليق