2. 嵌入式GUI与TouchGFX概述

嵌入式GUI并不是“把手机界面缩小塞进单片机”这么简单。它要在有限的CPU主频、SRAM、Flash、总线带宽和功耗预算下,完成图形绘制、文字排版、触摸响应和动画刷新。理解嵌入式GUI的发展脉络,以及TouchGFX在这条脉络中的位置,是后续做GPU加速开发的前提。

一、嵌入式GUI的发展:从点阵到GPU加速

早期嵌入式设备大多使用段码LCD或字符型LCD,界面由固定图标和数字组成,刷新逻辑接近“改寄存器”。随后出现点阵图形LCD,开发者开始用画点、画线、填充矩形等底层函数手工搭建界面,典型做法是直接操作显存缓冲区。

当界面复杂度上升,出现了第一代嵌入式图形库,例如emWin、μC/GUI、LVGL等。它们提供控件、字体、图层和事件机制,把“画什么”和“怎么画”分离。但这一阶段的渲染仍以CPU软件绘制为主:每个像素的混合、抗锯齿、透明度计算都由CPU完成。界面越炫,CPU占用越高,刷新率越难保证。

第三阶段是“GPU加速+框架化”。芯片厂商在MCU或MPU中集成2D GPU(如Chrom-ART、DMA2D、PXP、VG Lite等),把填充、拷贝、混合、缩放、旋转等操作从CPU卸载到专用硬件。TouchGFX正是这一阶段的代表性框架:它由ST推动,深度适配STM32系列,同时支持无GPU的纯软件渲染和有GPU的硬件加速渲染。

嵌入式GUI演进与TouchGFX定位 段码/字符LCD 固定图标 + 数字 直接写寄存器 无图形缓冲 点阵图形库 画点/画线/填充 手工搭建界面 CPU逐像素绘制 控件化框架 emWin / LVGL / μC/GUI 控件 + 事件 + 字体 仍以软件渲染为主 GPU加速框架 TouchGFX DMA2D / Chrom-ART 硬件混合与搬运 TouchGFX 渲染路径(有GPU时) UI逻辑 Presenter / View 绘制指令 Canvas / Widget 2D GPU 填充/混合/拷贝 帧缓冲 LTDC 输出 CPU 只负责逻辑与指令组织,像素级操作交给 GPU,刷新率与功耗同时受益

二、TouchGFX的核心特点

TouchGFX不是单纯的绘图库,而是一套“设计—生成—运行”的完整工具链。它的特点可以归纳为四点。

  • 与STM32深度绑定:官方支持STM32F4/F7/H7/U5等系列,能自动识别DMA2D、LTDC、DSI等外设,生成对应的驱动配置。
  • Designer + 代码生成:在TouchGFX Designer中拖拽控件、设置交互,生成C++骨架代码,开发者只需在View和Presenter中补充业务逻辑。
  • MVP架构:Model负责数据,View负责显示,Presenter负责协调。界面与业务解耦,便于多人协作和后期维护。
  • 硬件加速可配置:同一套UI代码,可以在有GPU的板子上走DMA2D,在无GPU的板子上回退到软件渲染,移植成本低。
TouchGFX的“加速”不是自动发生的。如果配置中未启用DMA2D,或者使用了GPU不支持的混合模式,渲染仍会回落到CPU,性能差异可能达到数倍。

三、GPU加速的意义:为什么值得专门学

在嵌入式GUI中,CPU通常还要处理通信、控制、算法等任务。如果UI渲染占用大量CPU时间,系统响应就会变慢,甚至出现触摸卡顿、动画掉帧。GPU加速的意义体现在三个层面。

维度纯CPU软件渲染GPU硬件加速
像素填充CPU逐字节写入,占用大量周期DMA2D批量搬运,CPU几乎不参与
透明度混合每像素做乘加运算硬件混合器并行完成
图层叠加多次拷贝到同一缓冲LTDC多图层直接合成
CPU占用高,影响实时任务低,CPU可处理业务逻辑
刷新率受限于CPU算力可达60fps甚至更高

以一个480×272的RGB565屏幕为例,全屏刷新一次需要约261KB的数据搬运。若用CPU逐像素填充,按100MHz主频估算,仅搬运就可能消耗数毫秒到数十毫秒;而DMA2D可以在后台完成同样工作,CPU同时去处理触摸事件或串口数据。这就是“加速”带来的直接收益。

四、典型场景与常见误区

典型场景包括:智能家电的触摸面板、工业HMI、医疗设备显示、可穿戴设备等。这些场景的共同点是界面有动画、有透明度、有多个图层,同时CPU还要跑控制逻辑。

常见误区有三个。第一,认为“用了TouchGFX就一定快”。实际上,如果UI中存在大量自定义绘制、频繁创建销毁控件、或者每帧都重绘全屏,GPU也救不了。第二,忽略帧缓冲带宽。GPU加速依赖内存带宽,如果SDRAM配置不当,DMA2D搬运反而会成为瓶颈。第三,把GPU当成“万能画布”。DMA2D擅长填充、拷贝、混合和格式转换,但不擅长复杂路径、曲线和任意旋转,这些仍需CPU或特定硬件完成。

排障时先确认三件事:DMA2D是否使能、帧缓冲是否放在可被GPU访问的内存区域、当前绘制操作是否落在GPU支持的功能范围内。很多“加速无效”的问题,根源都在配置而非代码。