Memindahkan Qt ke STM32

Memindahkan Qt ke STM32Selamat siang Kami berada dalam proyek ini kotak masuk meluncurkan Qt di STM32F7-Discovery dan ingin membicarakannya. Sebelumnya, kami telah memberi tahu bagaimana kami berhasil meluncurkannya OpenCV.

Qt adalah kerangka kerja lintas platform yang tidak hanya mencakup komponen grafis, tetapi juga hal-hal seperti QtNetwork, sekumpulan kelas untuk bekerja dengan database, Qt untuk Otomatisasi (termasuk untuk implementasi IoT) dan banyak lagi. Tim Qt telah proaktif dalam menggunakan Qt dalam sistem tertanam, sehingga perpustakaannya cukup dapat dikonfigurasi. Namun, hingga saat ini, hanya sedikit orang yang berpikir untuk mem-porting Qt ke mikrokontroler, mungkin karena tugas seperti itu tampaknya sulit - Qt besar, MCU kecil.

Di sisi lain, saat ini terdapat mikrokontroler yang dirancang untuk bekerja dengan multimedia dan lebih unggul dari Pentium pertama. Sekitar setahun yang lalu, blog Qt muncul pos. Pengembang membuat port Qt untuk OS RTEMS, dan meluncurkan contoh dengan widget di beberapa papan yang menjalankan stm32f7. Ini membuat kami tertarik. Terlihat jelas, dan pengembang sendiri menulis tentang hal itu, bahwa Qt lambat di STM32F7-Discovery. Kami bertanya-tanya apakah kami dapat menjalankan Qt di bawah Embox, dan tidak hanya menggambar widget, tetapi juga menjalankan animasi.

Qt 4.8 telah lama di-porting ke Embox, jadi kami memutuskan untuk mencobanya. Kami memilih aplikasi moveblocks - contoh animasi kenyal.

Qt memindahkan blok di QEMUMemindahkan Qt ke STM32

Untuk memulainya, kami mengonfigurasi Qt, jika memungkinkan, dengan kumpulan komponen minimum yang diperlukan untuk mendukung animasi. Untuk ini ada opsi β€œ-qconfig minimal,small,medium…”. Ini menghubungkan file konfigurasi dari Qt dengan banyak makro - apa yang diaktifkan / apa yang dinonaktifkan. Setelah opsi ini, kami menambahkan tanda lain ke konfigurasi jika kami ingin menonaktifkan yang lain. Ini adalah contoh kami konfigurasi.

Agar Qt berfungsi, Anda perlu menambahkan lapisan kompatibilitas OS. Salah satu caranya adalah dengan menerapkan QPA (Qt Platform Abstraksi). Kami mengambil sebagai dasar plugin fb_base siap pakai yang disertakan dalam Qt, yang menjadi dasar kerja QPA untuk Linux. Hasilnya adalah sebuah plugin kecil bernama emboxfb, yang menyediakan Qt dengan framebuffer Embox, dan kemudian menariknya ke sana tanpa bantuan dari luar.

Seperti inilah tampilan pembuatan plugin

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

Dan seperti inilah gambaran ulangnya

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

Hasilnya, ketika optimasi kompiler untuk ukuran memori -Os diaktifkan, gambar perpustakaan menjadi 3.5 MB, yang tentu saja tidak sesuai dengan memori utama STM32F746. Seperti yang sudah kami tulis di artikel kami yang lain tentang OpenCV, board ini memiliki:

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

Karena dukungan untuk mengeksekusi kode dari QSPI telah ditambahkan ke OpenCV, kami memutuskan untuk memulai dengan memuat seluruh gambar Embox c Qt ke QSPI. Dan hore, semuanya dimulai segera dari QSPI! Namun seperti halnya OpenCV, ternyata kerjanya terlalu lambat.

Memindahkan Qt ke STM32

Oleh karena itu, kami memutuskan untuk melakukannya dengan cara ini - pertama kami menyalin gambar ke QSPI, lalu memuatnya ke SDRAM dan menjalankannya dari sana. Dari SDRAM menjadi sedikit lebih cepat, namun masih jauh dari QEMU.

Memindahkan Qt ke STM32

Selanjutnya, ada ide untuk memasukkan floating point - lagipula, Qt melakukan beberapa perhitungan koordinat kotak dalam animasi. Kami mencobanya, tetapi di sini kami tidak mendapatkan akselerasi yang terlihat, meskipun masuk Artikel Pengembang Qt mengklaim bahwa FPU memberikan peningkatan kecepatan yang signifikan untuk β€œmenyeret animasi” pada layar sentuh. Mungkin terdapat lebih sedikit penghitungan floating point di moveblock, dan ini bergantung pada contoh spesifiknya.

Ide paling efektif adalah memindahkan framebuffer dari SDRAM ke memori internal. Untuk melakukan ini, kami membuat dimensi layar bukan 480x272, tetapi 272x272. Kami juga menurunkan kedalaman warna dari A8R8G8B8 ke R5G6B5, sehingga mengurangi ukuran satu piksel dari 4 menjadi 2 byte. Ukuran framebuffer yang dihasilkan adalah 272*272*2 = 147968 bytes. Hal ini memberikan akselerasi yang signifikan, mungkin yang paling terasa, animasinya menjadi hampir mulus.

Optimasi terbaru adalah menjalankan kode Embox dari RAM dan kode Qt dari SDRAM. Untuk melakukan ini, pertama-tama kita, seperti biasa, menghubungkan Embox secara statis dengan Qt, tetapi kita menempatkan segmen teks, rodata, data dan bss dari perpustakaan di QSPI untuk kemudian menyalinnya ke 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))

Dengan menjalankan kode Embox dari ROM, kami juga menerima akselerasi yang nyata. Hasilnya, animasinya menjadi cukup mulus:


Pada akhirnya, saat menyiapkan artikel dan mencoba konfigurasi Embox yang berbeda, ternyata moveblock Qt berfungsi dengan baik dari QSPI dengan framebuffer di SDRAM, dan hambatannya justru pada ukuran framebuffer! Rupanya, untuk mengatasi "slideshow" awal, akselerasi 2 kali lipat sudah cukup karena pengurangan ukuran framebuffer. Namun hasil seperti itu tidak dapat dicapai hanya dengan mentransfer kode Embox ke berbagai memori cepat (percepatannya bukan 2, tetapi sekitar 1.5 kali).

Cara mencobanya sendiri

Jika Anda memiliki STM32F7-Discovery, Anda dapat menjalankan sendiri Qt di bawah Embox. Anda dapat membaca bagaimana hal ini dilakukan di kami wiki.

Kesimpulan

Hasilnya, kami berhasil meluncurkan Qt! Kompleksitas tugas ini, menurut kami, agak dilebih-lebihkan. Tentu saja, Anda perlu mempertimbangkan spesifikasi mikrokontroler dan secara umum memahami arsitektur sistem komputer. Hasil optimasi menunjukkan fakta yang diketahui bahwa hambatan dalam sistem komputasi bukanlah prosesor, tetapi memori.

Tahun ini kami akan berpartisipasi dalam festival tersebut Kereta Teknologi. Disana kami akan memberi tahu Anda lebih detail dan menunjukkan Qt, OpenCV pada mikrokontroler dan pencapaian kami lainnya.

Sumber: www.habr.com

Tambah komentar