2、硬件平台选型:MCU与MPU的选择策略、显示控制器(TFT/OLED)接口规范、帧缓冲与显存设计原则、DMA2D与GPU加速
做嵌入式GUI,第一步就是选硬件。这一步要是走偏了,后面再怎么优化也救不回来。我见过太多项目,芯片选得太弱,界面卡成PPT;选得太强,成本又压不住。说白了,这就是个平衡的艺术。
2.1 MCU与MPU:你到底需要谁?
很多人问我:「MCU和MPU到底怎么分?」其实没那么玄乎。我的判断标准很简单——看你的UI复杂度。
MCU(微控制器),适合做轻量级界面。比如家电面板、仪表盘、小尺寸彩屏。这类场景下,RTOS + 轻量级GUI库(像LVGL、uGFX)就够用了。我做过一个温控器项目,STM32F429 + 480×272的TFT,跑LVGL,帧率稳稳的。
MPU(微处理器),适合跑复杂界面。比如带动画、视频播放、多窗口交互的场合。这时候你需要Linux + Qt或Flutter。我有个朋友做医疗监护仪,界面要同时显示波形、参数、报警动画,MCU根本扛不住,最后换了i.MX6ULL才搞定。
我的选型口诀:
- 界面简单、实时性高 → MCU + RTOS
- 界面复杂、需要生态 → MPU + Linux
- 两者之间?看看有没有硬件加速(DMA2D、GPU)
嗯,这里要注意一个坑:别以为MCU就做不了好UI。现在很多MCU内置了TFT控制器和DMA2D,跑个60帧的动画完全没问题。关键看你会不会用。
2.2 显示控制器接口规范
选好芯片,接下来就是连屏幕。接口这块,我踩过的坑比走过的路还多。
TFT接口:MCU接口 vs RGB接口
| 接口类型 | 引脚数 | 速度 | 适用场景 |
|---|---|---|---|
| MCU 8080/6800 | 8/16/18 | 较慢 | 小尺寸(< 5寸),低分辨率 |
| RGB并行 | 16/18/24 | 快 | 大尺寸,高分辨率 |
| SPI | 4-6 | 最慢 | 小屏,低刷新率 |
| MIPI DSI | 2-4对差分 | 极快 | 手机屏,高清大屏 |
我个人习惯,3.5寸以下用MCU接口,省引脚、布线简单。4.3寸以上用RGB接口,不然刷新率上不去。我曾经在一个7寸屏项目上用了MCU接口,结果刷一帧要50ms,动画根本没法看。后来改成RGB接口,配合DMA2D,直接降到8ms。
OLED接口:I2C vs SPI
OLED屏通常分辨率不高(128×64、128×32之类),接口也简单。我建议:
- I2C:引脚少(2根),适合小数据量、低刷新率。比如显示静态文字、图标。
- SPI:速度快,适合需要局部刷新的场合。比如做动态波形显示。
避坑指南:OLED屏的驱动芯片(如SSD1306)内部自带GRAM,你只需要往里面写数据就行。但要注意,它的刷新率有限,别指望用它做60fps的动画。我曾经试过用SPI刷OLED做小游戏,结果画面撕裂严重——后来才明白,OLED的帧率瓶颈在驱动芯片本身,不是接口速度。
2.3 帧缓冲与显存设计原则
帧缓冲,说白了就是一块内存区域,存着屏幕上每个像素的颜色值。显存设计得好不好,直接决定你的UI能不能跑起来。
原则一:显存大小 = 分辨率 × 色深
举个例子:480×272分辨率,16位色(RGB565),显存 = 480 × 272 × 2 = 261KB。嗯,看起来不大?但如果你用双缓冲,就要翻倍到522KB。很多MCU内部SRAM才256KB,根本放不下。
注意:别以为外部SDRAM就能随便用。SDRAM的访问延迟比内部SRAM高很多,频繁刷屏会导致CPU被拖死。我建议:
- 内部SRAM放帧缓冲 → 用于当前显示帧
- 外部SDRAM放显存 → 用于离屏渲染、资源存储
- 如果MCU有DMA2D,让它直接操作外部SDRAM
原则二:双缓冲 vs 单缓冲
单缓冲简单,但会有撕裂。双缓冲能解决撕裂,但内存翻倍。我的经验是:
- 静态界面(菜单、设置页)→ 单缓冲就够了
- 动态界面(动画、视频、滑动)→ 必须双缓冲
- 如果内存实在不够,可以用局部刷新 + 行缓冲
原则三:显存对齐
这个很多人会忽略。DMA2D和GPU通常要求显存地址按32字节对齐。不对齐的话,性能直接腰斩。我习惯在分配显存时,用 __attribute__((aligned(32))) 或者手动做地址对齐。
// 显存对齐示例(C语言)
#define FRAME_BUFFER_SIZE (480 * 272 * 2) // RGB565
static uint8_t fb[FRAME_BUFFER_SIZE] __attribute__((aligned(32)));
// 或者手动对齐
static uint8_t fb_raw[FRAME_BUFFER_SIZE + 32];
static uint8_t *fb = (uint8_t *)(((uint32_t)fb_raw + 31) & ~31);
2.4 DMA2D与GPU加速
说到加速,DMA2D是MCU界的「神兵利器」。它本质上是个2D图形DMA,能独立完成图像拷贝、颜色填充、像素格式转换、Alpha混合等操作。CPU只需要发个指令,剩下的DMA2D自己搞定。
DMA2D能干的事:
- 快速清屏(比CPU memset快5-10倍)
- 图像叠加(比如把图标合成到背景上)
- 颜色格式转换(ARGB8888 → RGB565)
- 矩形区域填充
我做过一个对比测试:用CPU逐像素画一个480×272的矩形,耗时约12ms;用DMA2D,只要1.2ms。差距就是这么明显。
DMA2D使用要点:
- 初始化时配置好时钟,DMA2D需要独立的时钟源
- 操作前检查DMA2D是否忙(读寄存器状态位)
- 用中断或轮询等待传输完成
- 注意源地址和目标地址不能重叠(除非做内存拷贝)
GPU加速:什么时候需要?
如果你用的是MPU(比如i.MX系列、全志、瑞芯微),通常内置了GPU。GPU能处理更复杂的图形操作,比如:
- 3D变换(旋转、缩放)
- 贝塞尔曲线渲染
- 多图层合成
- 视频解码叠加
但GPU也有代价:驱动复杂、功耗高、调试困难。我建议:
- 如果你的UI只是2D平面,DMA2D完全够用
- 如果需要3D效果或复杂动画,再考虑GPU
- 别为了「炫技」而用GPU,简单才是王道
我的经验:在STM32F769上做智能家居面板,我用DMA2D实现了60fps的滑动动画,效果跟手机差不多。但同样的代码移植到没有DMA2D的芯片上,帧率直接掉到15fps。所以选型时,DMA2D比CPU主频更重要。
最后说一句:硬件选型没有银弹。你得多问自己几个问题:屏幕多大?刷新率要求多少?动画复杂吗?成本预算多少?把这些想清楚了,选型自然就清晰了。