Qt の STM32 への移植

Qt の STM32 への移植こんにちは私たちはプロジェクトに参加しています エンボックス STM32F7-Discovery で Qt を起動したので、それについて話したいと思います。 先ほど、私たちがどのようにして立ち上げに成功したかをすでに説明しました OpenCV.

Qt は、グラフィカル コンポーネントだけでなく、データベースを操作するためのクラスのセットである QtNetwork、オートメーション (IoT 実装を含む) 用の Qt などを含むクロスプラットフォーム フレームワークです。 Qt チームは組み込みシステムでの Qt の使用に積極的に取り組んでいるため、ライブラリはかなり構成可能です。 しかし、最近まで、Qt をマイクロコントローラーに移植することを考える人はほとんどいませんでした。おそらく、そのような作業は難しいように思われるためです。Qt は大きく、MCU は小さいためです。

一方、現時点では、マルチメディアで動作するように設計され、最初の Pentium よりも優れたマイクロコントローラーが存在します。 約 XNUMX 年前、Qt ブログが登場しました 投稿する。 開発者は RTEMS OS 用の Qt のポートを作成し、stm32f7 を実行するいくつかのボード上でウィジェットを備えたサンプルを起動しました。 私たちはこれに興味を持ちました。 STM32F7-Discovery では Qt が遅いことが顕著であり、開発者自身もそれについて書いています。 Embox で Qt を実行して、ウィジェットを描画するだけでなくアニメーションも実行できないか考えていました。

Qt 4.8 は長い間 Embox に移植されてきたので、それを試してみることにしました。 私たちは、弾力のあるアニメーションの例である moveblocks アプリケーションを選択しました。

QEMU 上の Qt ムーブブロックQt の STM32 への移植

まず、可能であれば、アニメーションをサポートするために必要な最小限のコンポーネントのセットを使用して Qt を構成します。 このために、オプション「-qconfig minimum,small,medium...」があります。 Qt の設定ファイルと多くのマクロ (何を有効にするか、何を無効にするか) を接続します。 他の何かを無効にする場合は、このオプションの後に他のフラグを構成に追加します。 これは私たちの例です 構成.

Qt が動作するには、OS 互換性レイヤーを追加する必要があります。 XNUMX つの方法は、QPA (Qt Platform Abstraction) を実装することです。 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のROM
  • 320KBのRAM
  • 8MB SDRAM
  • 16MB 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 = XNUMX バイトになります。 これにより大幅な加速が得られ、おそらく最も顕著なのは、アニメーションがほぼスムーズになったことです。

最新の最適化は、EMbox コードを RAM から実行し、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))

ROM から Embox コードを実行すると、顕著な加速も得られました。 その結果、アニメーションは非常にスムーズになりました。


最後に、記事を準備してさまざまな Embox 構成を試しているときに、SDRAM 内のフレームバッファを使用した QSPI からの Qt ムーブブロックがうまく動作し、ボトルネックはまさに​​フレームバッファのサイズであることがわかりました。 どうやら、最初の「スライドショー」を克服するには、フレームバッファのサイズを平凡に削減したため、2 倍の高速化で十分でした。 しかし、Embox コードだけをさまざまな高速メモリに転送しただけでは、このような結果を達成することはできませんでした (加速は 2 倍ではなく、約 1.5 倍でした)。

自分で試す方法

STM32F7-Discovery をお持ちの場合は、自分で Embox で Qt を実行できます。 これがどのように行われるかについては、 вики.

まとめ

その結果、無事にQtを起動することができました! 私たちの意見では、このタスクの複雑さは多少誇張されています。 当然のことながら、マイクロコントローラーの詳細を考慮し、コンピューター システムのアーキテクチャを一般的に理解する必要があります。 最適化の結果は、コンピューティング システムのボトルネックはプロセッサではなくメモリであるという周知の事実を示しています。

今年もお祭りに参加します テックトレイン。 そこでは、Qt、マイクロコントローラー上の OpenCV、およびその他の成果について詳しく説明します。

出所: habr.com

コメントを追加します