4. TouchGFX架构与GPU集成

TouchGFX 能在 STM32 上实现流畅的类手机 UI,关键不在于“画得快”,而在于它把渲染任务拆成了清晰的层次:上层是 TouchGFX 引擎负责界面逻辑与绘制指令,中间是硬件抽象层(HAL)屏蔽芯片差异,下层是 GPU 驱动接口与 DMA2D/Chrom-ART 加速器完成像素搬运、混合与填充。理解这条链路,才能判断一个界面卡顿到底卡在引擎、HAL 还是加速器配置上。

一、核心原理:四层协作的渲染链路

TouchGFX 的架构可以概括为“引擎—抽象—驱动—硬件”四层。引擎层包含 Widget、Screen、Presenter、Model 等对象,它不直接操作寄存器,而是把绘制请求交给 HAL。HAL 层提供 TouchGFXHAL、OSWrappers、TouchGFXGeneratedHAL 等类,负责帧缓冲管理、触摸事件、节拍与 GPU 调用入口。GPU 驱动接口层则把 DMA2D、Chrom-ART、LTDC 等外设封装成统一函数,例如 drawFilledRect、blitCopy、blitAlpha。最底层才是 STM32 的 DMA2D 与 Chrom-ART 硬件。

其中 DMA2D(Direct Memory Access 2D)是 STM32 的 2D 图形加速器,Chrom-ART 是 ST 对其图形加速能力的品牌称呼。它支持三种典型模式:寄存器到存储器填充、存储器到存储器复制、带 Alpha 混合的复制。TouchGFX 通过 HAL 把这些模式映射为矩形填充、图像拷贝、透明度混合等操作,从而把 CPU 从逐像素循环中解放出来。

TouchGFX 渲染链路:引擎 → HAL → GPU 驱动 → DMA2D/Chrom-ART TouchGFX 引擎层 Widget / Screen / Presenter / Model / Painter 产生绘制指令:填充矩形、拷贝位图、Alpha 混合、文本渲染 硬件抽象层 HAL TouchGFXHAL / TouchGFXGeneratedHAL / OSWrappers 帧缓冲管理、触摸事件、节拍、GPU 调用入口、DMA2D 初始化 GPU 驱动接口层 drawFilledRect / blitCopy / blitAlpha / blendImage 把引擎指令翻译为 DMA2D 寄存器配置与 LTDC 图层操作 STM32 硬件层 DMA2D / Chrom-ART / LTDC / SDRAM / 内部 SRAM 执行像素填充、拷贝、混合,输出到帧缓冲并显示 性能瓶颈点 HAL 配置 / 缓存一致性 数据流: 引擎指令 → HAL 封装 → DMA2D 寄存器 → 帧缓冲 → LTDC 扫描输出 关键:DMA2D 只搬运像素,不参与界面逻辑;逻辑仍由 CPU 执行

二、方法流程:从绘制请求到屏幕像素

当界面需要刷新时,TouchGFX 引擎会调用 HAL::drawFilledRect 或 HAL::blitCopy 等方法。以填充矩形为例,HAL 会先判断是否启用 DMA2D:若启用,则配置 DMA2D 的 CR、OPFCCR、OCOLR、NLR、OMAR 等寄存器,启动传输;若未启用,则退化为 CPU 逐像素填充。图像拷贝则配置前景层地址、偏移、颜色格式,并选择是否开启 Alpha 混合。

典型配置流程如下:

// 1. 使能 DMA2D 时钟
__HAL_RCC_DMA2D_CLK_ENABLE();

// 2. 初始化 DMA2D 句柄
hdma2d.Instance = DMA2D;
hdma2d.Init.Mode         = DMA2D_M2M_BLEND;   // 存储器到存储器带混合
hdma2d.Init.ColorMode    = DMA2D_OUTPUT_ARGB8888;
hdma2d.Init.OutputOffset = 0;
HAL_DMA2D_Init(&hdma2d);

// 3. 配置前景层与背景层
HAL_DMA2D_ConfigLayer(&hdma2d, 0);  // 前景
HAL_DMA2D_ConfigLayer(&hdma2d, 1);  // 背景

// 4. 启动混合传输
HAL_DMA2D_BlendingStart(&hdma2d,
                        (uint32_t)fg_addr,
                        (uint32_t)bg_addr,
                        (uint32_t)dst_addr,
                        width, height);
HAL_DMA2D_PollForTransfer(&hdma2d, 100);

在 TouchGFX 工程中,这些底层调用通常由 TouchGFXGeneratedHAL 自动完成,开发者只需在 TouchGFXHAL::initialize() 中确认 DMA2D 已初始化,并在 touchgfx_init() 前完成 LTDC 与 SDRAM 配置。若使用 CubeMX,勾选 DMA2D 后生成的代码会包含上述初始化,但 TouchGFX 的 HAL 仍需正确指向这些句柄。

三、案例/场景:按钮滑动与半透明弹窗

假设界面上有一个半透明弹窗覆盖在背景图上。引擎会先绘制背景图,再绘制弹窗。弹窗的 Alpha 混合由 DMA2D 的 DMA2D_M2M_BLEND 模式完成:前景层是弹窗位图,背景层是当前帧缓冲,输出到同一帧缓冲。若 DMA2D 未启用,CPU 需要逐像素执行 dst = src * alpha + dst * (1 - alpha),在 480×272 屏幕上可能耗时数毫秒;启用 DMA2D 后可降至微秒级。

另一个常见场景是列表滑动。TouchGFX 会频繁调用 blitCopy 搬运列表项位图。如果位图存放在外部 SDRAM,而 DMA2D 访问 SDRAM 时未正确配置 MPU 或 Cache,可能出现花屏或数据不一致。此时需要将帧缓冲区域配置为 Write-Through 或 Non-Cacheable,或在 DMA2D 传输前后执行 SCB_CleanDCache_by_Addr。

四、误区与复盘:DMA2D 不是万能加速器

误区一:启用 DMA2D 就一定流畅。 DMA2D 只加速像素搬运与混合,不加速界面逻辑、文本排版、控件树遍历。若 CPU 在 handleTickEvent 中执行大量计算,帧率仍会下降。

误区二:忽略颜色格式匹配。 DMA2D 输入输出格式必须与 LTDC 图层格式一致。若帧缓冲为 RGB565,而位图为 ARGB8888,混合结果会偏色或错位。

误区三:忘记 Cache 一致性。 Cortex-M7 带 D-Cache,DMA2D 直接访问内存时可能读到旧数据。必须在 HAL 层做好 clean/invalidate 操作。

复盘时可按以下清单逐项检查:

检查项 正确做法 常见错误
DMA2D 时钟 __HAL_RCC_DMA2D_CLK_ENABLE() 未使能时钟,传输无响应
颜色格式 与 LTDC 图层一致,如 RGB565/ARGB8888 前景背景格式混用
Cache 一致性 帧缓冲配置为 Non-Cacheable 或传输前后 clean DMA2D 读到旧帧数据
HAL 初始化顺序 先 LTDC/SDRAM,再 DMA2D,最后 touchgfx_init 顺序颠倒导致花屏
传输完成判断 使用 HAL_DMA2D_PollForTransfer 或中断 未等待完成就改写缓冲

理解 TouchGFX 架构的关键,是把“界面逻辑”和“像素搬运”分开看:引擎负责前者,DMA2D/Chrom-ART 负责后者,HAL 是两者之间的翻译官。调优时先确认 HAL 是否把绘制请求正确转成了 DMA2D 操作,再检查 Cache 与颜色格式,最后才考虑降低界面复杂度。