3、MCU与驱动方案:主流MCU平台与显示控制器的实战选择

做嵌入式显示系统,选MCU平台这一步,其实就决定了你后面能走多远。我这些年经手过不少项目,从简单的温湿度显示到复杂的HMI人机界面,MCU选型这块踩过的坑还真不少。今天咱们就聊聊STM32、ESP32、i.MX RT这三个主流平台,以及它们背后的显示控制器和显存方案。

3.1 主流MCU平台:三足鼎立,各有所长

先说STM32。这玩意儿在嵌入式圈子里太常见了,生态成熟得不能再成熟。我个人习惯用STM32F4或H7系列做中小尺寸的显示项目,比如3.5寸到5寸的TFT屏。为什么?因为它的LTDC(LCD-TFT显示控制器)和DMA2D(2D图形加速器)配合得相当默契。

我在项目中遇到过用STM32F429驱动7寸屏的情况。当时客户要求刷新率至少30fps,还要带简单的动画效果。说实话,一开始我有点担心性能不够。但实际调下来,LTDC负责时序生成,DMA2D负责图层混合和颜色格式转换,CPU几乎不用管显示的事。嗯,这里要注意,STM32的LTDC最高支持XGA分辨率(1024x768),但实际跑起来,800x480左右是最舒服的。

我的经验: 如果你做的是电池供电的设备,STM32的灵活休眠模式是个加分项。显示不更新时,可以把LTDC时钟关了,功耗能降一大截。

再说ESP32。这芯片带Wi-Fi和蓝牙,天生就是为物联网显示终端准备的。它的显示方案比较特别——没有硬件LTDC,全靠SPI或并行8080接口刷屏。说白了,就是用CPU硬刷。我刚开始做ESP32显示项目时也觉得这太原始了,但后来发现,对于320x240这种小屏,配合ESP32的双核架构和DMA,效果其实还行。

我曾经用ESP32做过一个远程温湿度监测器,屏幕是2.8寸的ILI9341。刷屏用的是ESP-IDF的SPI驱动加DMA传输,帧率大概能到25fps。如果你要做更复杂的UI,比如带触摸和动画的,我建议用ESP32-S3,它带一个可编程的LCD接口,性能比老款ESP32强不少。

避坑指南: 我曾经在ESP32上直接跑LVGL,结果发现刷屏时Wi-Fi吞吐量掉得厉害。后来查了才知道,SPI和Wi-Fi共用同一个DMA控制器。解决办法是把刷屏任务优先级调低,或者用双核分工——一个核跑Wi-Fi,一个核刷屏。

最后说i.MX RT。这是NXP的跨界处理器,性能介于MCU和MPU之间。它内置了eLCDIF(增强型LCD接口)和PXP(像素处理管道),说白了就是专门为显示优化的。我做过一个10.1寸的工业HMI项目,用的就是i.MX RT1050。1024x600的分辨率,跑起来毫无压力。

i.MX RT的显示方案有个特点——它支持RGB接口和LVDS接口,可以直接驱动大屏。而且它的PXP硬件加速器可以做图像缩放、颜色空间转换、旋转等操作,这些在STM32上得靠DMA2D慢慢算。你想想看,如果要做视频播放或复杂的UI过渡效果,i.MX RT明显更合适。

平台 显示接口 最大分辨率 硬件加速 适用场景
STM32F4/H7 LTDC + DMA2D 1024x768 图层混合、颜色转换 中小尺寸HMI、仪表盘
ESP32/ESP32-S3 SPI/8080 + DMA 480x320(推荐) 无硬件加速 物联网显示、小屏终端
i.MX RT eLCDIF + PXP 1366x768 缩放、旋转、颜色空间转换 工业HMI、大屏显示

3.2 显示控制器:LTDC与DMA2D的配合艺术

LTDC是什么?说白了就是专门负责生成LCD时序的硬件模块。它不需要CPU干预,自己就能产生VSYNC、HSYNC、DE这些信号。你只需要配置好时序参数,然后把帧缓冲区的地址告诉它,它就会自动把数据送到LCD接口上。

我刚开始用STM32的LTDC时,最头疼的就是时序配置。每个LCD屏的时序参数都不一样,比如HBP(水平后肩)、HFP(水平前肩)、VBP(垂直后肩)这些。配置错了,屏幕要么不亮,要么显示错位。后来我总结了一个方法——直接看LCD数据手册里的时序图,把参数一个个填进去,然后用逻辑分析仪抓波形验证。嗯,这招屡试不爽。

// STM32 LTDC时序配置示例
LTDC_HandleTypeDef hltdc;
hltdc.Init.HorizontalSync = 40;      // HSYNC脉冲宽度
hltdc.Init.VerticalSync = 9;         // VSYNC脉冲宽度
hltdc.Init.AccumulatedHBP = 40 + 20; // HBP + HSYNC
hltdc.Init.AccumulatedVBP = 9 + 2;   // VBP + VSYNC
hltdc.Init.AccumulatedActiveW = 800; // 有效宽度
hltdc.Init.AccumulatedActiveH = 480; // 有效高度
hltdc.Init.TotalWidth = 800 + 40 + 20 + 10;  // 总宽度
hltdc.Init.TotalHeigh = 480 + 9 + 2 + 1;     // 总高度

DMA2D就更有意思了。它是个2D图形加速器,可以独立于CPU进行像素操作。比如你要把一个ARGB8888的图层转换成RGB565格式,或者把两个图层做alpha混合,DMA2D都能搞定。我习惯把DMA2D叫做「显示界的DMA」,因为它确实解放了CPU。

我在项目中遇到过需要做滑动菜单效果的情况。如果用CPU逐像素处理,帧率直接掉到个位数。后来改用DMA2D做图层滚动,配合LTDC的双缓冲机制,效果流畅多了。具体做法是:在后台缓冲区绘制下一帧,然后用DMA2D把数据搬运到前台缓冲区,LTDC自动显示。CPU全程只负责逻辑处理,不碰像素。

关键点: LTDC和DMA2D是独立工作的。LTDC只管从帧缓冲区读数据并发送给LCD,DMA2D只管在内存之间搬运和处理数据。两者互不干扰,这才是真正的硬件加速。

3.3 外部显存:SRAM与PSRAM的选择

做显示系统,内存永远不够用。你想想看,一个800x480的RGB565帧缓冲区,就需要800 * 480 * 2 = 768KB。如果再加一个图层做alpha混合,内存需求直接翻倍。MCU内部SRAM通常只有几百KB,所以外挂显存是必然的。

SRAM(静态随机存取存储器)速度最快,但容量小、价格高。我一般只在需要高速随机访问的场景用SRAM,比如做帧缓冲区或DMA2D的临时工作区。STM32的FMC接口可以轻松挂载SRAM,时序配置也不复杂。

PSRAM(伪静态随机存取存储器)就实惠多了。它本质上是DRAM,但内部集成了刷新逻辑,对外接口和SRAM一样。容量可以做到8MB甚至16MB,价格只有SRAM的几分之一。我做过一个项目,用i.MX RT1050外挂8MB PSRAM,同时做帧缓冲区和UI资源存储,效果很好。

不过PSRAM有个坑——它的访问速度比SRAM慢,而且有延迟。我曾经在PSRAM上直接跑DMA2D,结果发现图层混合时出现撕裂。后来查了手册才知道,PSRAM的随机访问延迟比SRAM高一个数量级。解决办法是把DMA2D的突发传输长度设大一点,比如16或32字节,这样能充分利用PSRAM的带宽。

类型 速度 容量 价格 典型应用
SRAM 快(<10ns) 小(<4MB) 帧缓冲区、DMA2D工作区
PSRAM 中等(~70ns) 大(<16MB) 帧缓冲区、UI资源存储
SDRAM 快(~10ns) 大(<64MB) 大尺寸帧缓冲区、视频播放
避坑指南: 我曾经在STM32H7上外挂PSRAM做双缓冲,结果发现切换缓冲区时屏幕会闪一下。排查了半天,原来是PSRAM的刷新周期和LTDC的帧同步没对齐。解决办法是在VSYNC中断里切换缓冲区,确保在消隐区完成切换。

最后说一句,选显存方案时别只看容量。你得考虑MCU的FMC/SDRAM接口支持什么类型的存储器,以及你的显示控制器需要多快的访问速度。我个人的经验是:小屏(<5寸)用内部SRAM就够了;中屏(5-7寸)用PSRAM性价比最高;大屏(>7寸)或者需要视频播放的,老老实实上SDRAM。

好了,MCU平台和驱动方案这块就聊到这儿。下一章咱们会深入讲讲显示接口的硬件设计,包括RGB、LVDS、MIPI DSI这些接口的实战布线技巧。到时候再聊。