กำลังย้าย Qt ไปที่ STM32

กำลังย้าย Qt ไปที่ STM32สวัสดีตอนบ่าย เราอยู่ในโครงการ เอ็มบ็อกซ์ เปิดตัว Qt บน STM32F7-Discovery และต้องการพูดคุยเกี่ยวกับเรื่องนี้ ก่อนหน้านี้เราได้บอกแล้วว่าเราจะเปิดตัวได้อย่างไร OpenCV.

Qt เป็นเฟรมเวิร์กข้ามแพลตฟอร์มที่ไม่เพียงแต่ประกอบด้วยองค์ประกอบกราฟิกเท่านั้น แต่ยังรวมไปถึงสิ่งต่างๆ เช่น QtNetwork ชุดคลาสสำหรับการทำงานกับฐานข้อมูล Qt สำหรับระบบอัตโนมัติ (รวมถึงการใช้งาน IoT) และอื่นๆ อีกมากมาย ทีมงาน Qt มีความกระตือรือร้นในการใช้ Qt ในระบบฝังตัว ดังนั้นไลบรารีจึงสามารถกำหนดค่าได้ค่อนข้างมาก อย่างไรก็ตาม จนกระทั่งเมื่อไม่นานมานี้ มีเพียงไม่กี่คนที่คิดเกี่ยวกับการย้าย Qt ไปยังไมโครคอนโทรลเลอร์ อาจเป็นเพราะงานดังกล่าวดูยาก - Qt มีขนาดใหญ่ MCU มีขนาดเล็ก

ในทางกลับกัน ในขณะนี้ มีไมโครคอนโทรลเลอร์ที่ออกแบบมาเพื่อทำงานกับมัลติมีเดียและเหนือกว่า Pentium รุ่นแรก ประมาณหนึ่งปีที่ผ่านมา บล็อก Qt ปรากฏขึ้น เสา. นักพัฒนาได้สร้างพอร์ต Qt สำหรับ RTEMS OS และเปิดตัวตัวอย่างพร้อมวิดเจ็ตบนบอร์ดหลายตัวที่ทำงาน stm32f7 สิ่งนี้ทำให้เราสนใจ เห็นได้ชัดเจนและนักพัฒนาเองก็เขียนเกี่ยวกับเรื่องนี้ว่า Qt ทำงานช้าใน STM32F7-Discovery เราสงสัยว่าเราสามารถรัน Qt ภายใต้ Embbox ได้หรือไม่ ไม่ใช่แค่วาดวิดเจ็ต แต่ยังสามารถรันแอนิเมชั่นได้ด้วย

Qt 4.8 ได้รับการย้ายไปยัง Embox มาเป็นเวลานานแล้ว ดังนั้นเราจึงตัดสินใจลองใช้มัน เราเลือกแอปพลิเคชัน Moveblocks - ตัวอย่างของแอนิเมชั่นที่สปริงตัว

Qt ย้ายบล็อกบน QEMUกำลังย้าย Qt ไปที่ STM32

ขั้นแรก เรากำหนดค่า Qt หากเป็นไปได้ ด้วยชุดส่วนประกอบขั้นต่ำที่จำเป็นต่อการรองรับแอนิเมชัน สำหรับสิ่งนี้มีตัวเลือก “-qconfig น้อยที่สุด,เล็ก,ปานกลาง...” มันเชื่อมต่อไฟล์กำหนดค่าจาก Qt กับมาโครจำนวนมาก - อะไรที่จะเปิดใช้งาน / อะไรที่จะปิดการใช้งาน หลังจากตัวเลือกนี้ เราจะเพิ่มแฟล็กอื่นๆ ให้กับการกำหนดค่า หากเราต้องการปิดการใช้งานอย่างอื่น นี่คือตัวอย่างของเรา การกำหนดค่า.

เพื่อให้ Qt ทำงานได้ คุณต้องเพิ่มเลเยอร์ความเข้ากันได้ของระบบปฏิบัติการ วิธีหนึ่งคือการใช้ QPA (Qt Platform Abstraction) เราใช้พื้นฐานของปลั๊กอิน fb_base สำเร็จรูปที่รวมอยู่ใน Qt โดยพิจารณาจาก QPA สำหรับ Linux ที่ใช้งานได้ ผลลัพธ์ที่ได้คือปลั๊กอินขนาดเล็กที่เรียกว่า emboxfb ซึ่งจัดเตรียม Qt พร้อมด้วย framebuffer ของ 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;
}

ด้วยเหตุนี้ เมื่อเปิดใช้งานการเพิ่มประสิทธิภาพคอมไพเลอร์สำหรับขนาดหน่วยความจำ -Os อิมเมจของไลบรารีจึงมีขนาด 3.5 MB ซึ่งแน่นอนว่าไม่พอดีกับหน่วยความจำหลักของ STM32F746 ตามที่เราได้เขียนไปแล้วในบทความอื่นของเราเกี่ยวกับ OpenCV บอร์ดนี้มี:

  • รอม 1MB
  • แรม 320 กิโลไบต์
  • SDRAM ขนาด 8 เมกะไบต์
  • QSPI ขนาด 16 เมกะไบต์

เนื่องจากได้เพิ่มการรองรับการรันโค้ดจาก QSPI ลงใน OpenCV แล้ว เราจึงตัดสินใจเริ่มต้นด้วยการโหลดอิมเมจ Embox c Qt ทั้งหมดลงใน QSPI และไชโย ทุกอย่างเริ่มต้นเกือบจะในทันทีจาก QSPI! แต่ในกรณีของ OpenCV กลับกลายเป็นว่ามันทำงานช้าเกินไป

กำลังย้าย Qt ไปที่ STM32

ดังนั้นเราจึงตัดสินใจทำเช่นนี้ - อันดับแรกเราคัดลอกรูปภาพไปยัง QSPI จากนั้นโหลดลงใน SDRAM และดำเนินการจากที่นั่น จาก SDRAM มันเร็วขึ้นเล็กน้อย แต่ก็ยังห่างไกลจาก QEMU

กำลังย้าย Qt ไปที่ STM32

ต่อไป มีแนวคิดที่จะรวมจุดลอยตัวด้วย เพราะท้ายที่สุดแล้ว Qt จะทำการคำนวณพิกัดของกำลังสองในแอนิเมชั่น เราพยายามแล้ว แต่ที่นี่เราไม่เห็นความเร่งใดๆ เลย แม้ว่าจะเข้ามาก็ตาม статье นักพัฒนา Qt อ้างว่า FPU ให้ความเร็วเพิ่มขึ้นอย่างมากสำหรับ "การลากแอนิเมชั่น" บนหน้าจอสัมผัส การคำนวณจุดลอยตัวใน Moveblock อาจน้อยลงอย่างมาก และขึ้นอยู่กับตัวอย่างที่เฉพาะเจาะจง

แนวคิดที่มีประสิทธิภาพที่สุดคือการย้าย framebuffer จาก SDRAM ไปยังหน่วยความจำภายใน ในการดำเนินการนี้ เราได้กำหนดขนาดหน้าจอไม่ใช่ 480x272 แต่เป็น 272x272 นอกจากนี้เรายังลดความลึกของสีจาก A8R8G8B8 เป็น R5G6B5 ซึ่งช่วยลดขนาดหนึ่งพิกเซลจาก 4 เหลือ 2 ไบต์ ขนาด framebuffer ที่ได้คือ 272 * 272 * 2 = 147968 ไบต์ สิ่งนี้ทำให้มีการเร่งความเร็วอย่างมีนัยสำคัญ อาจเห็นได้ชัดเจนที่สุด ภาพเคลื่อนไหวเกือบจะราบรื่น

การเพิ่มประสิทธิภาพล่าสุดคือการเรียกใช้โค้ด Embbox จาก RAM และโค้ด Qt จาก SDRAM ในการดำเนินการนี้ ตามปกติแล้ว อันดับแรกเราจะเชื่อมโยง Embbox กับ 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 จาก ROM เรายังได้รับการเร่งความเร็วที่เห็นได้ชัดเจนอีกด้วย เป็นผลให้แอนิเมชั่นออกมาค่อนข้างราบรื่น:


ในตอนท้ายสุด ในขณะที่เตรียมบทความและลองใช้การกำหนดค่า Embox ต่างๆ ปรากฎว่า Qt moveblocks ทำงานได้ดีมากจาก QSPI พร้อมด้วย framebuffer ใน SDRAM และคอขวดนั้นมีขนาดเท่ากับ framebuffer อย่างแน่นอน! เห็นได้ชัดว่าเพื่อเอาชนะ "สไลด์โชว์" เริ่มต้นการเร่งความเร็ว 2 เท่าก็เพียงพอแล้วเนื่องจากการลดขนาดของบัฟเฟอร์เฟรมซ้ำซาก แต่ไม่สามารถบรรลุผลดังกล่าวได้โดยการโอนเฉพาะรหัส Embox ไปยังความทรงจำที่รวดเร็วต่างๆ (การเร่งความเร็วไม่ใช่ 2 แต่ประมาณ 1.5 เท่า)

วิธีลองทำด้วยตัวเอง

หากคุณมี STM32F7-Discovery คุณสามารถเรียกใช้ Qt ภายใต้ Embox ได้ด้วยตัวเอง คุณสามารถอ่านวิธีการดำเนินการนี้ได้ในของเรา วิกิพีเดีย.

ข้อสรุป

ด้วยเหตุนี้ เราจึงสามารถเปิดตัว Qt! ในความคิดของเรา ความซับซ้อนของงานนั้นค่อนข้างเกินความจริง โดยธรรมชาติแล้วคุณต้องคำนึงถึงลักษณะเฉพาะของไมโครคอนโทรลเลอร์และเข้าใจสถาปัตยกรรมของระบบคอมพิวเตอร์โดยทั่วไป ผลลัพธ์การปรับให้เหมาะสมชี้ให้เห็นข้อเท็จจริงที่ทราบกันดีว่าคอขวดในระบบคอมพิวเตอร์ไม่ใช่โปรเซสเซอร์ แต่เป็นหน่วยความจำ

ปีนี้เราจะเข้าร่วมในเทศกาล เทคเทรน. ที่นั่นเราจะบอกรายละเอียดเพิ่มเติมแก่คุณและแสดง Qt, OpenCV บนไมโครคอนโทรลเลอร์และความสำเร็จอื่นๆ ของเรา

ที่มา: will.com

เพิ่มความคิดเห็น