こんにちは私たちはプロジェクトに参加しています
Qt は、グラフィカル コンポーネントだけでなく、データベースを操作するためのクラスのセットである QtNetwork、オートメーション (IoT 実装を含む) 用の Qt などを含むクロスプラットフォーム フレームワークです。 Qt チームは組み込みシステムでの Qt の使用に積極的に取り組んでいるため、ライブラリはかなり構成可能です。 しかし、最近まで、Qt をマイクロコントローラーに移植することを考える人はほとんどいませんでした。おそらく、そのような作業は難しいように思われるためです。Qt は大きく、MCU は小さいためです。
一方、現時点では、マルチメディアで動作するように設計され、最初の Pentium よりも優れたマイクロコントローラーが存在します。 約 XNUMX 年前、Qt ブログが登場しました
Qt 4.8 は長い間 Embox に移植されてきたので、それを試してみることにしました。 私たちは、弾力のあるアニメーションの例である moveblocks アプリケーションを選択しました。
QEMU 上の Qt ムーブブロック
まず、可能であれば、アニメーションをサポートするために必要な最小限のコンポーネントのセットを使用して 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 の場合と同様、動作が遅すぎることが判明しました。
したがって、この方法で実行することにしました。まずイメージを QSPI にコピーし、次にそれを SDRAM にロードして、そこから実行します。 SDRAM からは少し速くなりましたが、それでも QEMU には程遠いです。
次に、浮動小数点を含めるというアイデアがありました。結局のところ、Qt はアニメーション内の正方形の座標の計算を行います。 試してみましたが、ここでは目に見える加速は得られませんでした。
最も効果的なアイデアは、フレームバッファを 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を起動することができました! 私たちの意見では、このタスクの複雑さは多少誇張されています。 当然のことながら、マイクロコントローラーの詳細を考慮し、コンピューター システムのアーキテクチャを一般的に理解する必要があります。 最適化の結果は、コンピューティング システムのボトルネックはプロセッサではなくメモリであるという周知の事実を示しています。
今年もお祭りに参加します
出所: habr.com