ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Qt for MCUs 2.11 LTS 与 Qt 5.15.19 发布:ESP32-S3、RA8D1 适配与地图渲染实战

Qt for MCUs 2.11 LTS 与 Qt 5.15.19 发布:ESP32-S3、RA8D1 适配与地图渲染实战 1. 从一次选型争论说起MCU 上跑 Qt 到底是不是伪命题前阵子群里有人抛出一个问题手头一个带屏的工业面板项目主控用的是 ESP32-S3界面想做得像样点到底该不该上 Qt。底下立刻分成两派一派说 MCU 那点内存和主频跑 Qt 纯属自找麻烦另一派直接甩出 Qt for MCUs 的链接说时代变了。这个争论其实每隔一段时间就会重演一次而 2025 年 Qt for MCUs 2.11 LTS 和 Qt 5.15.19 的发布恰好给这场争论提供了新的注脚。先把结论摆在前面Qt for MCUs 和桌面版 Qt 是两条完全不同的技术路线前者不是把后者裁剪一下塞进单片机而是基于 QML 子集重新设计的一套轻量运行时。这次 2.11 LTS 版本明确把 ESP32-S3、RA8D1 这类带图形加速能力的 MCU 列为重点支持对象还专门提到了 MCU 地图渲染能力说明官方在往低端硬件也能做出像样 HMI这个方向持续投入。与此同时Qt 5.15.19 作为 Qt 5 系列的最终版本发布意味着这条老分支正式进入维护尾声还在用 Qt 5 做嵌入式 Linux 项目的团队需要认真考虑迁移节奏了。这篇文章适合三类人看一是正在做 MCU 带屏项目、纠结 GUI 方案选型的嵌入式工程师二是用惯了 Qt Widgets、想搞清楚 Qt for MCUs 到底能不能复用手上技能的开发者三是负责技术决策、需要判断 Qt 5 到 Qt 6 迁移窗口期的项目负责人。我会把版本更新的实际含义、ESP32-S3 和 RA8D1 这类芯片的适配要点、MCU 地图渲染的实现思路以及 Qt 5 收尾带来的连锁反应按我自己的理解拆开讲一遍。2. Qt for MCUs 2.11 LTS 到底更新了什么值得关注的东西2.1 LTS 这个标签对嵌入式项目意味着什么很多人看到版本号里的 LTS 没什么感觉觉得无非是官方给个长期支持承诺。但在嵌入式行业LTS 的实际价值远比想象中大。一个工业面板或者医疗设备的生命周期动辄五到八年产品一旦量产固件和 GUI 框架的版本基本就冻结了后续只做小修小补。如果用的框架半年就停止维护遇到一个渲染 bug 或者安全补丁整个团队就得被迫做一次大版本升级这个成本在量产阶段是灾难性的。Qt for MCUs 的 LTS 版本通常提供三年左右的标准支持期加上延长的商业支持可以拉得更长。2.11 作为 LTS意味着从 2025 年开始的这三年里官方会持续为这个版本提供补丁和关键修复不会强制你跟着季度版本跑。对于已经进入量产或者即将量产的团队锁定 LTS 版本是降低长期维护风险的常规操作。我个人的习惯是只要项目进入 DVT 阶段就立刻把框架版本钉死在最近的 LTS 上非必要不升级。2.2 ESP32-S3 被重点支持背后的硬件逻辑ESP32-S3 出现在支持列表里其实挺有意思。这颗芯片严格来说不算传统意义上的低端 MCU它双核 Xtensa LX7、主频能到 240MHz、带 512KB SRAM 和可选的 PSRAM还内置了 LCD 控制器和 2D 图形加速单元。乐鑫把它定位成带 AI 加速的物联网 SoC但社区里大量人拿它做带屏的 HMI 项目因为它便宜、生态好、资料多。Qt for MCUs 支持 ESP32-S3关键在于它那颗 2D 加速单元和足够的 PSRAM。纯靠 CPU 软件渲染跑 QML在 240MHz 的核上做全屏刷新会非常吃力帧率可能掉到个位数。但有了硬件 2D 加速矩形填充、alpha 混合、图像缩放这些操作可以卸载出去CPU 只负责逻辑和布局计算帧率就能拉到可接受的范围。这里有个实操细节ESP32-S3 的 PSRAM 带宽是瓶颈如果帧缓冲放在 PSRAM 里高分辨率下刷新率会明显受限能放内部 SRAM 的尽量放内部放不下的部分再考虑 PSRAM并且要优先保证帧缓冲的访问优先级。2.3 RA8D1 代表的另一条路线Cortex-M85 与 HeliumRA8D1 是瑞萨基于 Arm Cortex-M85 内核的 MCU主频 480MHz带 Helium 向量扩展和 2D 图形加速。它和 ESP32-S3 代表了两条不同的硬件路线ESP32-S3 是够用就好、成本优先RA8D1 是性能拉满、面向高端 HMI。Cortex-M85 的 Helium 指令集对图形和信号处理类负载有明显加速作用配合瑞萨自己的图形加速外设跑 Qt for MCUs 的复杂界面会从容很多。选型的时候要算一笔账如果你的界面只是几个按钮、几个数值显示、偶尔刷新一下曲线ESP32-S3 完全够用成本能压到很低。但如果界面涉及多层叠加、实时动画、地图渲染这类重负载RA8D1 这类带向量扩展和强图形外设的芯片才是合理选择。我见过不少项目为了省几块钱选了低端芯片结果界面卡顿到用户投诉最后返工换芯片损失远超当初省下的成本。2.4 MCU 地图渲染这次更新里最值得琢磨的能力地图渲染被单独拎出来说说明这是个有实际需求但实现起来有难度的场景。在 MCU 上渲染地图难点不在画线而在于地图数据量大、需要平移缩放、要处理图层叠加、还要保证帧率。桌面端可以用 OpenGL 或者成熟的 GIS 库MCU 上这些都没有得从零设计一套适合小内存的渲染管线。Qt for MCUs 的地图渲染思路我理解核心是分块加载加矢量绘制。把地图切成瓦片只加载当前视口和预取范围内的瓦片其余的不占内存。绘制时用矢量路径而不是位图这样缩放不会糊但矢量绘制的计算量更大需要硬件加速来兜底。平移和缩放操作要能触发瓦片的动态加载和卸载这中间的内存管理是重点稍不注意就会碎片化或者 OOM。实际做的时候瓦片缓存策略、预取范围、缩放级别切换的时机都需要根据具体硬件反复调参没有一套放之四海皆准的配置。3. 在 ESP32-S3 上把 Qt for MCUs 跑起来的完整路径3.1 环境搭建里最容易踩的几个坑先说工具链。ESP32-S3 的开发环境主流是 ESP-IDFQt for MCUs 对 ESP32-S3 的支持是通过它自己的构建系统对接 ESP-IDF 的。安装顺序很重要先装 ESP-IDF 并确保idf.py能正常工作再装 Qt for MCUs 的 SDK最后配置两者的路径关联。我见过有人反过来装结果 Qt 的构建脚本找不到 IDF 的组件报一堆莫名其妙的错。版本匹配是另一个大坑。ESP-IDF 的版本迭代很快Qt for MCUs 2.11 对 ESP-IDF 的版本是有明确要求的用太新或太旧的 IDF 都可能编译失败。建议严格按官方文档里标注的 IDF 版本走不要图新鲜用最新版。另外 Python 环境也容易出问题ESP-IDF 和 Qt 的构建脚本都依赖 Python如果系统里有多个 Python 版本务必确认构建时用的是同一个否则会出现模块找不到的情况。3.2 显示驱动与帧缓冲的对接细节Qt for MCUs 在 MCU 上跑最终要落到一块屏幕上中间隔着显示驱动和帧缓冲。ESP32-S3 常见的屏幕接口是 SPI 和 RGBSPI 屏便宜但带宽低RGB 屏带宽高但占引脚多。如果做 Qt 界面强烈建议用 RGB 接口的屏SPI 的刷新率很难支撑流畅的 QML 动画。帧缓冲的分配策略直接影响性能。ESP32-S3 内部 SRAM 只有 512KB一块 480x272 的 16 位色帧缓冲就要 260KB 左右双缓冲直接翻倍内部 SRAM 根本放不下。这时候要么用 PSRAM 做帧缓冲要么用单缓冲加局部刷新。用 PSRAM 的话前面提过带宽是瓶颈实测下来 480x272 分辨率下能跑到 30 帧左右再高就吃力了。局部刷新适合界面变化区域小的场景只重绘脏矩形能省不少带宽但实现复杂度高需要 Qt 的渲染后端支持脏矩形追踪。3.3 QML 子集的边界哪些写法在 MCU 上不能用Qt for MCUs 用的是 QML 的一个子集不是完整 QML。很多在桌面端习以为常的写法在 MCU 上要么不支持要么性能极差。比如 JavaScript 的复杂表达式、动态创建对象、大量的绑定链这些在 MCU 上都是性能杀手。核心原则是能在 C 侧算好的就不要放到 QML 里算。具体来说列表类界面不要用Repeater一次性创建所有项要用ListView配合委托复用只创建可见区域内的项。动画尽量用属性动画而不是 JavaScript 驱动的逐帧计算。图片资源要预先处理成合适的尺寸和格式不要指望运行时缩放。我踩过的一个坑是用了带阴影效果的矩形桌面端很流畅MCU 上直接掉到十几帧后来换成预渲染的九宫格图片才解决。阴影、模糊、渐变这些视觉效果在 MCU 上都要谨慎使用能用静态资源替代的就替代。3.4 实测性能数据与调优方向拿 ESP32-S3 加 480x272 RGB 屏做基准一个中等复杂度的界面顶部状态栏、中部列表、底部按钮栏实测帧率在 25 到 35 帧之间波动。列表滚动时帧率会掉因为滚动触发了大量重绘。优化方向有几个一是减少每帧重绘的面积把静态部分和动态部分分层二是降低颜色深度16 位色比 32 位色省一半带宽三是把频繁变化的数值显示用专门的图层处理避免整屏刷新。内存占用方面一个典型界面加上框架本身RAM 占用在 300KB 到 400KB 之间如果用了 PSRAM 做帧缓冲内部 SRAM 的压力会小很多。Flash 占用取决于界面复杂度简单界面 1MB 以内复杂界面可能到 2MB 以上选芯片的时候要把 Flash 容量算够。这些数据不是绝对的具体项目差异很大但可以作为量级参考。4. RA8D1 与高端 MCU 路线性能富余时该怎么用4.1 Cortex-M85 的 Helium 对 GUI 的实际增益RA8D1 用的 Cortex-M85 带 Helium 向量扩展这对 GUI 渲染的帮助主要体现在批量像素操作上。比如图像缩放、颜色空间转换、alpha 混合这些操作用 Helium 指令可以一次处理多个像素比纯标量运算快好几倍。Qt for MCUs 的渲染后端如果针对 Helium 做了优化在 RA8D1 上的帧率会比同主频的普通 Cortex-M 高出一截。但要注意Helium 的增益不是自动的需要编译器生成向量指令还需要渲染算法本身适合向量化。如果渲染后端还是标量实现Helium 就白白浪费了。选 RA8D1 这类芯片的时候要确认 Qt for MCUs 的对应后端是否已经针对 Helium 优化过否则性能优势体现不出来。这一点在选型阶段就要问清楚不要等板子打回来才发现。4.2 高端 MCU 上可以尝试的复杂界面形态性能富余的时候界面设计可以放开一些。多层叠加、半透明效果、实时曲线、地图渲染这些在 ESP32-S3 上要精打细算的东西在 RA8D1 上可以更从容地实现。比如工业 HMI 里常见的实时趋势图低端芯片上只能画折线高端芯片上可以做平滑曲线加渐变填充加动态游标。地图渲染在 RA8D1 上也能做得更完整。矢量地图的平移缩放可以做到接近实时瓦片预取范围可以开大一些缩放级别切换可以做得更平滑。如果项目需要显示厂区平面图、设备分布图这类带交互的地图界面RA8D1 这类芯片是更合适的选择。当然硬件性能上去了软件架构也要跟上否则瓶颈会转移到代码效率上。4.3 成本与性能的平衡点怎么找选型本质上是在成本和性能之间找平衡。我的经验是先明确界面的性能底线最低可接受帧率是多少、最复杂的界面场景是什么、未来有没有功能扩展的可能。然后拿几颗候选芯片做实际测试不要只看参数表。参数表上的主频和加速单元和实际跑 Qt 界面的表现中间差着驱动质量、框架优化程度、内存带宽等一堆因素。一个实用的方法是做最小可行原型拿候选芯片的开发板跑一个接近真实复杂度的界面测帧率、测内存、测启动时间。这个投入通常几天就能完成但能避免选型失误带来的巨大返工成本。我见过太多项目在参数表上做决策结果样机阶段发现性能不够那时候改硬件已经来不及了。5. Qt 5.15.19 作为 Qt 5 最终版本带来的连锁反应5.1 Qt 5 正式收尾意味着什么Qt 5.15.19 是 Qt 5 系列的最后一个版本这个信号很明确Qt 5 不再有新功能只会有选择性的安全修复而且这个修复窗口也不会太长。对于还在用 Qt 5 做嵌入式 Linux 项目的团队这意味着技术栈正式进入只出不进的状态新项目不应该再选 Qt 5老项目要开始规划迁移。迁移的紧迫性取决于项目阶段。如果项目已经量产且稳定短期内不迁移问题不大但要做好技术债记录等下一个大版本迭代时一并处理。如果项目还在开发中现在就是迁移的最佳时机越往后拖代码量越大迁移成本越高。如果项目刚立项没有任何理由选 Qt 5直接上 Qt 6。5.2 Qt 5 到 Qt 6 迁移中最容易出问题的模块Qt 5 到 Qt 6 的迁移不是简单的版本号替换中间有不少破坏性变更。图形栈从 Qt 5 的 QPainter 为主转向 Qt 6 的 RHI渲染硬件接口抽象底层渲染路径变了自定义绘制的代码可能需要重写。QML 方面Qt 6 对 QML 的类型系统和绑定机制做了调整一些在 Qt 5 里能跑的写法在 Qt 6 里会报错或者行为不一致。模块拆分也是个大问题。Qt 6 把很多原本在核心模块里的功能拆到了独立模块比如 Qt Quick Controls 的样式、Qt Charts、Qt Data Visualization 等。迁移时经常遇到这个类怎么找不到了一查发现挪到别的模块去了需要在项目文件里补上对应的依赖。建议迁移前先跑一遍官方的迁移检查工具把明显的 API 变更先列出来心里有个数。5.3 嵌入式 Linux 项目迁移的实操节奏嵌入式 Linux 项目迁移 Qt 6节奏上建议分三步走。第一步是环境准备把交叉编译工具链、Qt 6 的嵌入式构建、目标板的系统库都升级到位这一步最容易卡在依赖库版本冲突上要有耐心。第二步是代码迁移先解决编译错误再解决运行时行为差异最后处理性能回归。第三步是回归测试嵌入式项目的测试往往不充分迁移后要重点测图形渲染、输入事件、多语言这些容易出问题的部分。迁移过程中构建系统从 qmake 转向 CMake 是个绕不开的坎。Qt 6 官方主推 CMakeqmake 虽然还能用但支持在弱化。如果项目原来用 qmake迁移时顺便把构建系统也换了虽然短期工作量增加但长期看是值得的。CMake 的跨平台能力和生态支持都比 qmake 好早换早省心。6. 地图渲染在 MCU 上的实现思路与踩坑记录6.1 瓦片化小内存渲染大地图的核心手段MCU 的内存装不下整张地图瓦片化是必然选择。把地图按固定尺寸切成瓦片运行时只加载视口内和预取范围内的瓦片。瓦片尺寸的选择有讲究太小则瓦片数量多管理开销大太大则单块内存占用高加载粒度粗。常见的选择是 256x256 像素一块这个尺寸在内存占用和管理效率之间比较平衡。瓦片缓存策略决定了平移缩放时的流畅度。缓存太小稍微一移动就要重新加载会卡顿缓存太大内存扛不住。我的做法是缓存视口周围一圈的瓦片移动时优先命中缓存缓存未命中再异步加载。异步加载要注意不能阻塞渲染线程否则加载期间界面会冻结。Qt for MCUs 在这块提供了相应的机制但具体参数要根据硬件调。6.2 矢量绘制与位图绘制的取舍地图渲染有矢量路线和位图路线两条。矢量路线缩放不糊、文件小但每帧都要重新计算路径CPU 压力大。位图路线渲染快但缩放会糊、多套缩放级别要存多份数据Flash 占用大。MCU 上通常的做法是混合低缩放级别用矢量高缩放级别用位图或者根据硬件能力选择。如果硬件有 2D 加速矢量绘制的路径填充和描边可以部分卸载性能会好很多。但矢量路径的三角化、裁剪这些操作还是 CPU 在做复杂路径依然吃力。实际项目里地图的复杂度要控制不要指望在 MCU 上渲染城市级详细地图厂区平面图、简单路网这类场景才是合理的目标。6.3 交互响应平移缩放的流畅度怎么保证地图交互最怕的就是拖拽时卡顿。保证流畅度的核心是渲染和加载解耦拖拽时先用已有的瓦片渲染哪怕边缘有空白也不要等新瓦片加载完再刷新。新瓦片加载完成后再平滑地补上。这样用户感觉是流畅的虽然中间可能有短暂的空白区域。缩放比平移更复杂因为缩放会改变瓦片的显示尺寸需要重新采样。如果缩放级别变化跨越了瓦片级别还要切换瓦片数据源。我的经验是缩放动画要做短快速过渡到目标级别不要在中间级别停留太久减少重采样和切换的次数。另外缩放的中心点要跟随手指或鼠标位置这个细节做不好用户体验会很别扭。7. 几个实际项目里总结出来的经验7.1 内存规划要留足余量MCU 项目最容易出问题的就是内存。Qt for MCUs 本身有基础开销界面资源有开销运行时还有动态分配。规划的时候不要按理论值算要留至少 30% 的余量。我见过项目在开发阶段内存刚好够用加了一个功能就 OOM最后只能砍功能或者换芯片。内存这东西宁可芯片选大一号也不要卡在临界点上。7.2 界面复杂度要和硬件能力匹配做界面设计的时候要和硬件工程师对齐性能预算。设计师画的效果图很漂亮但每一层半透明、每一个阴影、每一段动画在 MCU 上都是有代价的。我的做法是让设计师先看硬件能跑起来的 demo在这个基础上做设计而不是先设计再砍效果。这样返工少双方预期也一致。7.3 版本锁定与升级策略嵌入式项目的框架版本要锁定不要跟着最新版跑。锁定在 LTS 版本上只在有明确需求或者安全修复时才升级。升级前要在独立分支上做完整回归测试确认没有性能回归和功能异常再合并。Qt 5 到 Qt 6 这种大版本迁移更要单独规划不要和功能开发混在一起做。7.4 工具链版本一致性团队协作时工具链版本不一致是常见的坑。A 用 IDF 4.4B 用 IDF 5.0编译出来的固件行为可能不一样。解决办法是把工具链版本写进项目文档用脚本自动检查版本或者干脆用容器把开发环境固化下来。这个投入在团队规模超过三个人之后就非常值得。8. 关于这次版本更新我自己的判断Qt for MCUs 2.11 LTS 把 ESP32-S3 和 RA8D1 列为重点支持加上地图渲染能力说明官方在认真对待MCU 上做像样 HMI这个需求。ESP32-S3 这条线走的是性价比路线适合量大面广的消费类和工业类带屏产品RA8D1 这条线走的是性能路线适合对界面要求高的高端 HMI。两条线覆盖了大部分 MCU 带屏场景选型时按性能和成本需求对号入座就行。Qt 5.15.19 作为 Qt 5 的终点提醒还在用 Qt 5 的团队该做迁移规划了。迁移不是一蹴而就的事尤其是嵌入式项目牵扯到工具链、系统库、构建系统、代码本身需要提前排期。我的建议是如果项目还在活跃开发把 Qt 6 迁移列入下一个大版本的计划如果项目已经冻结做好技术债记录等有实际需求时再动。最后说个我自己的习惯每次框架大版本更新我都会拿一个真实项目里最复杂的界面在新版本上跑一遍看帧率、内存、启动时间的变化。这个动作花不了多少时间但能让我对版本更新的实际影响有第一手的判断而不是只看发布说明。发布说明告诉你有什么新功能实测告诉你这些功能在你的场景里到底值不值得用。
返回列表