1. TouchGFX 概述与显示架构
各位做嵌入式 UI 的朋友,大家好。我是老周,在嵌入式图形领域摸爬滚打了十多年。今天咱们开始聊 TouchGFX,这个框架我用了好几年,从最早的 4.x 版本一直跟到现在。说实话,它是我见过的在资源受限 MCU 上跑得最流畅的 GUI 方案之一。
这一章咱们先打基础。我会把 TouchGFX 的发展脉络、核心架构、MVP 模式以及帧缓冲区机制讲清楚。这些东西看似理论,但我在项目中踩过的坑,十有八九都跟这些基础概念有关。
1.1 TouchGFX 发展历程
TouchGFX 最早是瑞典一家叫 Draupner Graphics 的公司搞出来的。2018 年被 ST 收购后,发展速度明显加快了。我印象最深的是 4.13 版本,那时候刚支持 FreeRTOS,我还在一个项目里硬生生把裸机代码改成了多线程架构。
几个关键节点:
- 2014 年:TouchGFX 1.0 发布,主打低资源消耗
- 2018 年:被 ST 收购,开始深度绑定 STM32 生态
- 2020 年:4.18 版本引入 MVP 模式,架构大改
- 2022 年:4.21 版本支持多缓冲区 + DMA2D 硬件加速
- 2024 年:4.24 版本优化了 Partial Buffer 机制
核心观点:TouchGFX 的演进始终围绕一个目标——在有限资源下实现流畅的图形交互。每次版本更新,要么是降低内存占用,要么是提升渲染效率。
1.2 核心架构:分层设计
TouchGFX 的架构其实不复杂。我习惯把它分成三层来看:
| 层级 | 组件 | 职责 |
|---|---|---|
| 应用层 | Screen、View、Presenter | 业务逻辑、界面交互 |
| 框架层 | Model、MessageBus、Timer | 数据管理、事件分发 |
| 硬件抽象层 | HAL、FrameBuffer、DMA2D | 显示驱动、内存管理 |
为什么要分层?说白了就是为了解耦。我在一个医疗设备项目里吃过亏——当初把显示逻辑和业务逻辑写在一起,后来换屏幕驱动,改了整整两周。如果当时用 TouchGFX 的分层架构,换个 HAL 实现就行了。
这里我画了一张架构图,方便大家理解:
1.3 MVP 模式:Model-View-Presenter
MVP 模式是 TouchGFX 4.18 之后引入的核心设计思想。说实话,刚接触的时候我也觉得有点绕,但用顺手了就会发现,它把界面和逻辑拆得干干净净。
三个角色的职责:
- Model:数据层,负责业务数据和状态管理。我一般把传感器数据、通信协议解析都放这里。
- View:视图层,只负责界面绘制和用户输入捕获。它不关心数据从哪来。
- Presenter:协调层,连接 Model 和 View。用户点了按钮,Presenter 决定该做什么。
我的经验:刚开始用 MVP 时,我总想把业务逻辑塞进 View 里,觉得省事。结果后来要加一个夜间模式,改得我头皮发麻。记住一条原则——View 里只放界面代码,其他都交给 Presenter。
举个实际例子。假设有个温度显示界面:
// Model 层:获取温度数据
class TemperatureModel : public Model {
public:
int getTemperature() { return sensor.read(); }
};
// View 层:显示温度
class TemperatureView : public View {
public:
void updateTemperature(int temp) {
textArea.setValue(temp);
}
};
// Presenter 层:协调
class TemperaturePresenter : public Presenter {
public:
void onButtonClicked() {
int temp = model->getTemperature();
view->updateTemperature(temp);
}
};
你看,Model 只管读数据,View 只管显示,Presenter 负责调度。这样每个类都很轻,测试也好测。
1.4 帧缓冲区机制
帧缓冲区是 TouchGFX 性能的关键。说白了,它就是一块内存区域,用来存放一帧画面的像素数据。MCU 的显示控制器会不断从这块内存读取数据,刷新到屏幕上。
TouchGFX 支持三种缓冲区模式:
| 模式 | 内存占用 | 刷新方式 | 适用场景 |
|---|---|---|---|
| 单缓冲区 | 1 × 帧大小 | 直接写入 | 低端 MCU,内存紧张 |
| 双缓冲区 | 2 × 帧大小 | 后台绘制 + 前台显示 | 主流方案,防撕裂 |
| 局部缓冲区 | 1/4 ~ 1/2 帧大小 | 分块刷新 | 大分辨率屏幕 |
避坑指南:我曾经在一个 800×480 的屏幕上用单缓冲区,结果画面撕裂严重。后来换成双缓冲区,配合 DMA2D 传输,效果立竿见影。但要注意,双缓冲区内存翻倍,如果你的 MCU 只有 64KB RAM,可能撑不住。
帧缓冲区的配置通常在 TouchGFXConfiguration.cpp 里:
// 双缓冲区配置示例
static uint16_t frameBuffer0[FRAME_BUFFER_WIDTH * FRAME_BUFFER_HEIGHT];
static uint16_t frameBuffer1[FRAME_BUFFER_WIDTH * FRAME_BUFFER_HEIGHT];
void touchgfx_init() {
HAL& hal = touchgfx_generic_init<MyHAL>(
frameBuffer0,
frameBuffer1,
FRAME_BUFFER_WIDTH,
FRAME_BUFFER_HEIGHT,
0 // 不使用局部缓冲区
);
}
这里有个细节——帧缓冲区的对齐。我建议至少 4 字节对齐,如果支持 DMA2D,最好 32 字节对齐。不然后续做硬件加速时会出奇怪的问题。
1.5 本章小结
这一章我们聊了 TouchGFX 的来龙去脉、三层架构、MVP 模式以及帧缓冲区机制。这些东西是后续所有优化的基础。你想想看,如果不理解帧缓冲区是怎么工作的,后面讲 DMA2D 加速、Partial Buffer 优化,你根本不知道为什么要那么做。
嗯,基础打牢了,后面咱们才能聊真正的优化技巧。