انتقال Qt به STM32

انتقال Qt به STM32عصر بخیر ما در پروژه هستیم صندوق پستی Qt را در STM32F7-Discovery راه اندازی کرد و می خواهم در مورد آن صحبت کنم. قبلاً ما قبلاً گفته بودیم که چگونه توانستیم راه اندازی کنیم OpenCV.

Qt یک چارچوب بین پلتفرمی است که نه تنها شامل اجزای گرافیکی، بلکه مواردی مانند QtNetwork، مجموعه‌ای از کلاس‌ها برای کار با پایگاه‌های داده، Qt برای اتوماسیون (از جمله برای پیاده‌سازی اینترنت اشیا) و موارد دیگر است. تیم Qt در مورد استفاده از Qt در سیستم‌های جاسازی شده فعال بوده است، بنابراین کتابخانه‌ها کاملاً قابل تنظیم هستند. با این حال، تا همین اواخر، افراد کمی در مورد انتقال Qt به میکروکنترلرها فکر می کردند، احتمالاً به این دلیل که چنین کاری دشوار به نظر می رسد - Qt بزرگ است، MCU ها کوچک هستند.

از سوی دیگر، در حال حاضر میکروکنترلرهایی برای کار با چند رسانه ای و برتر از پنتیوم های اول طراحی شده اند. حدود یک سال پیش، وبلاگ Qt ظاهر شد ارسال. توسعه دهندگان یک پورت Qt برای RTEMS OS ساختند و نمونه هایی را با ویجت ها بر روی چندین برد که stm32f7 دارند راه اندازی کردند. این به ما علاقه مند شد. قابل توجه بود و خود توسعه دهندگان در مورد آن می نویسند که Qt در STM32F7-Discovery کند است. ما فکر می‌کردیم که آیا می‌توانیم Qt را در Embox اجرا کنیم و نه فقط یک ویجت بکشیم، بلکه یک انیمیشن را اجرا کنیم.

Qt 4.8 برای مدت طولانی به Embox پورت شده است، بنابراین تصمیم گرفتیم آن را روی آن امتحان کنیم. ما برنامه moveblocks را انتخاب کردیم - نمونه ای از انیمیشن فنری.

بلوک های حرکتی Qt در QEMUانتقال Qt به STM32

برای شروع، در صورت امکان، Qt را با حداقل مجموعه ای از اجزای مورد نیاز برای پشتیبانی از انیمیشن پیکربندی می کنیم. برای این گزینه "-qconfig حداقل، کوچک، متوسط..." وجود دارد. این یک فایل پیکربندی از Qt را با ماکروهای زیادی متصل می کند - چه چیزی را فعال کنید / چه چیزی را غیرفعال کنید. بعد از این گزینه، اگر بخواهیم چیز دیگری را غیرفعال کنیم، پرچم های دیگری را به پیکربندی اضافه می کنیم. در اینجا یک نمونه از ما است پیکربندی.

برای اینکه Qt کار کند، باید یک لایه سازگاری سیستم عامل اضافه کنید. یکی از راه ها پیاده سازی QPA (Qt Platform Abstraction) است. ما پلاگین آماده fb_base موجود در Qt را به عنوان پایه در نظر گرفتیم که بر اساس آن QPA برای لینوکس کار می کند. نتیجه یک پلاگین کوچک به نام emboxfb است که فریم بافر Embox را به Qt ارائه می کند و سپس بدون هیچ کمک خارجی به آنجا رسم می کند.

این چیزی است که ایجاد یک افزونه به نظر می رسد

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

در نتیجه، با فعال بودن بهینه سازی کامپایلر برای اندازه حافظه -Os، تصویر کتابخانه 3.5 مگابایت است که البته در حافظه اصلی STM32F746 جای نمی گیرد. همانطور که قبلاً در مقاله دیگر خود درباره OpenCV نوشتیم، این برد دارای موارد زیر است:

  • رام 1 مگابایتی
  • رم 320 کیلوبایت
  • 8 مگابایت SDRAM
  • 16 مگابایت QSPI

از آنجایی که پشتیبانی از اجرای کد از QSPI قبلاً به OpenCV اضافه شده است، تصمیم گرفتیم با بارگیری کل تصویر Embox c Qt در QSPI شروع کنیم. و هورای، همه چیز تقریباً بلافاصله از QSPI شروع شد! اما همانطور که در مورد OpenCV، معلوم شد که خیلی کند کار می کند.

انتقال Qt به STM32

بنابراین، تصمیم گرفتیم این کار را به این صورت انجام دهیم - ابتدا تصویر را در QSPI کپی می کنیم، سپس آن را در SDRAM بارگذاری می کنیم و از آنجا اجرا می کنیم. از SDRAM کمی سریعتر شد، اما هنوز با QEMU فاصله دارد.

انتقال Qt به STM32

بعد، ایده ای برای گنجاندن یک نقطه شناور وجود داشت - بالاخره Qt محاسبات مختصات مربع ها را در انیمیشن انجام می دهد. ما تلاش کردیم، اما در اینجا هیچ شتاب قابل مشاهده ای دریافت نکردیم، هرچند در مقاله توسعه دهندگان Qt ادعا کردند که FPU سرعت "کشیدن انیمیشن" روی صفحه لمسی را افزایش می دهد. ممکن است محاسبات ممیز شناور به میزان قابل توجهی در بلوک های متحرک کمتر باشد و این به مثال خاص بستگی دارد.

موثرترین ایده انتقال فریم بافر از SDRAM به حافظه داخلی بود. برای این کار، ابعاد صفحه را نه 480x272، بلکه 272x272 ساختیم. همچنین عمق رنگ را از A8R8G8B8 به R5G6B5 کاهش دادیم، بنابراین اندازه یک پیکسل را از 4 به 2 بایت کاهش دادیم. اندازه فریم بافر حاصل 272 * 272 * 2 = 147968 بایت است. این شتاب قابل توجهی به همراه داشت، شاید از همه مهمتر این بود که انیمیشن تقریبا صاف شد.

آخرین بهینه سازی اجرای کد Embox از رم و کد Qt از SDRAM بود. برای انجام این کار، ابتدا، طبق معمول، Embox را به صورت ایستا با Qt پیوند می دهیم، اما بخش های متن، rodata، داده و 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 از رام شتاب محسوسی نیز دریافت کردیم. در نتیجه، انیمیشن کاملاً روان شد:


در انتها، در حین آماده سازی مقاله و آزمایش پیکربندی های مختلف Embox، مشخص شد که بلوک های حرکتی Qt از QSPI با یک فریم بافر در SDRAM عالی کار می کنند و گلوگاه دقیقاً به اندازه فریم بافر بود! ظاهراً برای غلبه بر "نمایش اسلاید" اولیه، یک شتاب 2 برابری به دلیل کاهش پیش پا افتاده اندازه فریم بافر کافی بود. اما دستیابی به چنین نتیجه ای با انتقال تنها کد Embox به حافظه های سریع مختلف ممکن نبود (شتاب 2، بلکه حدود 1.5 برابر بود).

چگونه خودتان آن را امتحان کنید

اگر STM32F7-Discovery دارید، می‌توانید Qt را خودتان در Embox اجرا کنید. می توانید نحوه انجام این کار را در ما بخوانید ویکی.

نتیجه

در نتیجه موفق شدیم Qt را راه اندازی کنیم! پیچیدگی کار، به نظر ما، تا حدودی اغراق آمیز است. به طور طبیعی، شما باید ویژگی های میکروکنترلرها را در نظر بگیرید و به طور کلی معماری سیستم های کامپیوتری را درک کنید. نتایج بهینه سازی به این واقعیت معروف اشاره می کند که گلوگاه در یک سیستم محاسباتی پردازنده نیست، بلکه حافظه است.

امسال در جشنواره شرکت خواهیم کرد TechTrain. در آنجا با جزئیات بیشتری به شما می گوییم و Qt، OpenCV را روی میکروکنترلرها و دیگر دستاوردهایمان نشان می دهیم.

منبع: www.habr.com

اضافه کردن نظر