将 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! 我们认为,这项任务的复杂性有些被夸大了。 当然,您需要考虑微控制器的具体情况并大致了解计算机系统的体系结构。 优化结果指出了一个众所周知的事实:计算系统的瓶颈不是处理器,而是内存。

今年我们将参加这个节日 TechTrain。 在那里我们将更详细地告诉您并展示微控制器上的 Qt、OpenCV 以及我们的其他成就。

来源: habr.com

添加评论