將 Qt 移植到 STM32

將 Qt 移植到 STM32午安我們在專案中 恩博克斯 在STM32F7-Discovery上推出了Qt,並想談談它。 早些時候,我們已經講述了我們如何成功啟動 OpenCV的.

Qt 是一個跨平台框架,不僅包括圖形元件,還包括 QtNetwork、一組用於處理資料庫的類別、Qt for Automation(包括用於 IoT 實作)等。 Qt 團隊一直積極主動地在嵌入式系統中使用 Qt,因此這些函式庫是非常可設定的。 然而,直到最近,很少有人考慮將 Qt 移植到微控制器,可能是因為這樣的任務看起來很困難 - Qt 很大,MCU 很小。

另一方面,目前有一些微控制器設計用於多媒體工作,並且優於第一代奔騰。 大約一年前,Qt 部落格出現了 郵寄。 開發人員為 RTEMS 作業系統製作了 Qt 端口,並在運行 stm32f7 的幾塊板上啟動了帶有小部件的範例。 這讓我們很感興趣。 值得注意的是,Qt 在 STM32F7-Discovery 上速度很慢,開發人員自己也對此進行了描述。 我們想知道是否可以在 Embox 下運行 Qt,不僅可以繪製小部件,還可以運行動畫。

Qt 4.8 已經移植到 Embox 很長一段時間了,所以我們決定在上面嘗試一下。 我們選擇了 moveblocks 應用程式 - 彈性動畫的一個範例。

QEMU 上的 Qt moveblocks將 Qt 移植到 STM32

首先,如果可能的話,我們使用支援動畫所需的最少組件集來配置 Qt。 為此,有一個選項「-qconfig minus,small,medium...」。 它將 Qt 的設定檔與許多巨集連接起來-啟用什麼/停用什麼。 在此選項之後,如果我們想要停用其他功能,我們可以在配置中新增其他標誌。 這是我們的一個例子 配置.

為了讓 Qt 運作,您需要新增作業系統相容層。 一種方法是實作 QPA(Qt 平台抽象)。 我們以 Qt 中包含的現成 fb_base 外掛程式為基礎,QPA for 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;
}

結果,在啟用記憶體大小 -Os 的編譯器最佳化後,庫映像大小為 3.5 MB,這當然不適合 STM32F746 的主記憶體。 正如我們在另一篇有關 OpenCV 的文章中所寫的,該板具有:

  • 1MB 唯讀記憶體
  • 320KB 內存
  • 8MB內存
  • 16MB QSPI

由於 OpenCV 中已經添加了對從 QSPI 執行程式碼的支持,因此我們決定首先將整個 Embox c Qt 映像載入到 QSPI 中。 萬歲,一切幾乎都是從 QSPI 立即開始的! 但正如 OpenCV 的情況一樣,事實證明它的運行速度太慢了。

將 Qt 移植到 STM32

因此,我們決定這樣做 - 首先我們將映像複製到 QSPI,然後將其載入到 SDRAM 並從那裡執行。 與 SDRAM 相比,它變得更快了一點,但與 QEMU 仍然相差甚遠。

將 Qt 移植到 STM32

接下來,有一個想法是包含一個浮點 - 畢竟,Qt 對動畫中的正方形座標進行了一些計算。 我們嘗試過,但在這裡我們沒有得到任何明顯的加速,儘管在 文章 Qt 開發人員聲稱 FPU 顯著提高了觸控螢幕上「拖曳動畫」的速度。 moveblocks 中的浮點計算可能會顯著減少,這取決於具體的範例。

最有效的想法是將幀緩衝區從 SDRAM 移至內部記憶體。 為此,我們將螢幕尺寸設為 480x272,而不是 272x272。 我們還將顏色深度從 A8R8G8B8 降低到 R5G6B5,從而將一個像素的大小從 4 位元組減少到 2 位元組。 產生的幀緩衝區大小為 272 * 272 * 2 = 147968 位元組。 這提供了顯著的加速,也許最引人注目的是,動畫變得幾乎平滑。

最新的優化是從 RAM 運行 Embox 程式碼,從 SDRAM 運行 Qt 程式碼。 為此,我們首先像往常一樣將 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))

透過從 ROM 執行 Embox 程式碼,我們也獲得了明顯的加速。 結果,動畫變得相當流暢:


最後,在準備文章並嘗試不同的 Embox 配置時,結果發現 Qt moveblocks 在 SDRAM 中帶有幀緩衝區的 QSPI 中工作得很好,而瓶頸恰恰是幀緩衝區的大小! 顯然,為了克服最初的“幻燈片放映”,由於幀緩衝區大小的平庸減少,2 倍加速就足夠了。 但僅僅將 Embox 程式碼轉移到各種快速記憶體中是不可能達到這樣的結果的(加速不是 2 倍,而是大約 1.5 倍)。

如何自己嘗試一下

如果您有 STM32F7-Discovery,您可以自行在 Embox 下執行 Qt。 您可以在我們的網站上閱讀這是如何完成的 維基百科.

結論

結果,我們成功啟動了 Qt! 我們認為,這項任務的複雜性有些被誇大了。 當然,您需要考慮微控制器的具體情況並大致了解電腦系統的體系結構。 最佳化結果指出了一個眾所周知的事實:計算系統的瓶頸不是處理器,而是記憶體。

今年我們將參加這個節日 技術訓練。 在那裡我們將更詳細地告訴您並展示微控制器上的 Qt、OpenCV 以及我們的其他成就。

來源: www.habr.com

添加評論