拓冰建站拓冰建站
首页 / 资讯中心 / 正文

STM32F746上基于CubeMX和TouchGFX的GUI移植实战指南

我先把Final坑踩完再放出正文。直接给结果。1. 为什么用CubeMX搭TouchGFX这套组合解决什么问题STM32F746Discovery这块板子很多人买回来第一件事就是点个灯、跑个RTOS然后就吃灰了。其实这块板子最值钱的地方在于板上集成了4.3寸480x272的RGB屏、SDRAM、QSPI Flash、音频Codec天生就是做图形界面GUI的料。但真要把TouchGFX跑起来很多人在第一步就卡住了TouchGFX工程到底怎么和HAL库关联时钟和显存配置怎么弄LTDC和DMA2D又是什么关系网上资料大多是零散的要么只讲CubeMX配置要么只讲TouchGFX Designer画界面很少有人把整条链路串起来讲清楚。这篇文章就是我实际在F746Discovery上从零到一完成TouchGFX移植的全过程记录**基于STM32CubeMX 6.x TouchGFX Designer 4.2x MDK-ARM或STM32CubeIDE**的成熟组合一步步带你把工程跑起来。无论是刚接触TouchGFX的新手还是已经能跑Demo但想搞懂原理的人都可以参考这套流程。先说结论用STM32CubeMX做底层初始化用TouchGFX Designer做UI设计两个工具通过.ioc文件互联是目前官方推荐也是坑最少的一条路。你不需要手写LTDC初始化不需要手动配FMC访问SDRAM这些CubeMX都能生成你只需要明白每个配置选项背后的意义出问题时才知道去哪里排查。环境版本上我强烈建议使用最新稳定版。TouchGFX从4.10开始版权免费开放4.18之后基本不需要再关心License文件的问题STM32CubeMX 6.10以上自带TouchGFX Generator插件不需要额外装别的乱七八糟的东西。MDK和CubeIDE二选一即可我这次用MDK演示CubeIDE流程几乎一样。2. STM32CubeMX工程配置把底层基础打牢2.1 新建工程与芯片选型打开STM32CubeMX点击“New Project”在Board Selector选项卡里输入STM32F746G-DISCOVERY直接选中这块板卡。为什么要用Board Selector而不是MCU Selector因为官方板定义文件里已经帮你预设了板上外设的默认引脚比如LCD的LTDC引脚、SDRAM的FMC引脚、触摸的I2C引脚不用自己对着原理图一个个找。选中之后CubeMX会自动加载板卡的默认配置左侧Pinout Configuration区域你会看到很多外设已经被勾选。此时先不要急着改先把工程名和存放路径设置好。Project Name建议用小写字母和下划线比如touchgfx_f746_demo路径不要带空格和中文否则后面MDK编译会出一些莫名其妙的问题。点击右上角GENERATE CODE前建议先做三件事设置好工具链Toolchain/IDE选择MDK-ARM V5.32或STM32CubeIDE、确认固件包版本已安装、确认TouchGFX Generator组件可用。如果左侧列表中看不到TouchGFX Generator说明CubeMX版本太老或者安装时没有勾选TouchGFX组件这个插件是CubeMX内置的不需要单独下载但部分精简安装包会把它裁掉建议直接到ST官网下载最新版CubeMX重装。2.2 时钟树配置80MHz还是216MHz别拍脑袋定STM32F746最高主频216MHz但TouchGFX的官方Demo普遍跑在200MHz左右不是216MHz为什么因为TouchGFX示例工程为了兼顾低功耗和稳定性做了折中。不过我们自己移植完全可以用216MHz只要电源配置正确VOS scale 1、Overdrive使能稳定性没问题。我实测216MHz下跑复杂动画没有异常。重点在于配置方法在Clock Configuration页面输入HSE为25MHzDiscovery板载晶振就是25MHz然后配置PLL。关键路径是PLLCLK - SYSCLK而LTDC的像素时钟LCD-TFT也是从PLL的另一个输出分频得到的所以PLL配置直接决定屏幕刷新率。我的实际配置如下HSE25MHz主PLLPLLM 25PLLN 432PLLP 2PLLQ 9PLLR 7SYSCLK 25 / 25 * 432 / 2 216MHz总线分频AHB /1APB1 /4APB2 /2LTDC像素时钟 25 / 25 * 432 / 9 48MHz这里用到的是PLLQ不是PLLP有人会问PLLQ为什么是9因为480x272的RGB屏行场消隐加一起大约需要16.7MHz到20MHz的像素时钟但TouchGFX内部渲染可能还需要一些余量。48MHz不是必须的如果你用的是其他分辨率屏幕需要根据屏的Datasheet算像素时钟。我试过24MHz也能出画面但刷新率会明显低触摸跟手性变差所以还是按官方推荐配置来。注意LTDC像素时钟不是越高越好。RGB接口的屏幕对时钟上限有要求超过了会花屏或黑屏。F746Discovery原装屏RK043FN48H的典型像素时钟是9.6MHz但TouchGFX示例工程用到了更高频率也没问题因为内部有FIFO缓冲。2.3 外设初始化LTDC、FMC-SDRAM、I2C触摸、DMA2D在Pinout页面按以下清单核对并启用外设LTDCLCD-TFT这是显示的核心外设。配置里需要设置水平同步宽度HSYNC40像素垂直同步宽度VSYNC9行水平前沿HBP30像素垂直前沿VBP15像素水平后沿HFP30像素垂直后沿VFP15像素这些参数是屏厂规格书里给的不能随便改否则画面会偏移或者闪屏。颜色格式选RGB565还是RGB888TouchGFX支持RGB565和ARGB8888两种主流格式。RGB565显存占用减半但色彩有损失ARGB8888色彩好但显存翻倍。F746Discovery带有8MB SDRAM跑ARGB8888毫无压力我建议直接选ARGB8888。FMC外部存储控制器SDRAM配置为16位数据宽度、13位行地址、11位列地址、4个Bank。时序参数TRCD、TRP、TRC等需要参考SDRAM芯片手册IS42S16400J但TouchGFX生成的代码里其实会自动带一份合适的配置前提是你在CubeMX里把SDRAM的型号参数选对。这里我要强调一个容易被忽略的点SDRAM的“Bank数”必须选4如果选2虽然也能初始化但内存访问可能出现随机崩溃。I2C触摸Discovery板上的触摸芯片FT5336挂在I2C1上地址0x38。CubeMX会自动识别板载I2C配置你只需要确认中断引脚Touch INT已启用外部中断。这个中断很重要TouchGFX依靠它来判断触摸事件如果不配中断触摸会变得迟钝甚至完全失灵。DMA2D图形加速器CubeMX不需要单独配置DMA2D它只是一个挂在AHB总线上的外设TouchGFX的驱动会直接操作它的寄存器。但是必须确保DMA2D的时钟AHB1已经使能这在CubeMX里默认就是使能的但如果你手动精简过时钟树容易把它关掉那TouchGFX的拷贝和混合操作就会全部退化为CPU搬运性能直接掉一半以上。2.4 TouchGFX Generator配置三要素很多教程到这里就结束了但移植TouchGFX的关键其实在这一节。在CubeMX左侧列表里找到Middleware and Software Packs - TouchGFX Generator配置以下三项Application Monitor建议选择Console方便通过串口或者IDE的调试控制台查看TouchGFX运行日志。如果选No出问题时排查成本会很高。不要选GUI Builder的Monitor那是给模拟器用的。TouchGFX Generator的归属建议单独生成到Middlewares目录并且在生成时勾选“Generate TouchGFX configuration”这样它会自动生成TouchGFX文件夹里面包含target和generated两个子目录。target里是硬件抽象层驱动LCD、触摸、DMA2D的适配代码generated里是UI框架代码。Framebuffer策略这里选择Double buffer双缓冲。双缓冲意味着需要两块帧缓冲区的显存ARGB8888格式下480x272分辨率一块缓冲区需要480 * 272 * 4 522,240字节约510KB两块就是约1MB。SDRAM完全放得下。双缓冲的好处是TouchGFX在绘制下一帧时可以同时让LTDC读取上一帧画面不会撕裂这是GUI最基本的体验保障。2.5 生成工程顺序决定成败生成顺序有个讲究先单独生成一次CubeMX工程确认编译通过然后再用CubeMX联调TouchGFX。如果你第一次生成就把TouchGFX Generator打开CubeMX会尝试当场调用TouchGFX Designer如果此时TouchGFX Designer没安装或者版本不匹配生成会报错。所以新手建议分两步第一步TouchGFX Generator选择No先生成普通工程用MDK打开编译确保HAL层没问题。第二步回到CubeMX把TouchGFX Generator打开配置好之后再次生成。此时CubeMX会在工程里插入TouchGFX的相关代码并自动调用TouchGFX Designer生成一个默认的UI工程。这里有个非常坑的细节如果CubeMX生成时报“TouchGFXEngine.dll not found”之类的错误大概率是TouchGFX Designer没有安装成功或者环境变量没配好。重装TouchGFX Designer到默认路径C:\ST\TouchGFX\4.21.x能解决99%的问题。别问我怎么知道的。3. TouchGFX Designer设计UI并导出工程3.1 认识TouchGFX Designer它不是画图工具是代码生成器很多人第一次打开TouchGFX Designer会以为这是一个类似Photoshop的界面设计工具其实不对。它的核心工作是生成C代码界面上的拖拽只是让你以可视化的方式组合控件最终生成的是一套完整的UI应用代码。对于F746Discovery你在Creator阶段只需要关心两块Screens屏幕一个应用至少有一个ScreenCanvas画布每个Screen上有哪些控件我建议第一个实验不要追求花哨就做一个最经典的“模拟仪表盘”或“按钮 文本 波形图”组合。原因是控件越简单出问题的环节越少先跑通整条链路再逐步加复杂度。3.2 创建新工程目标平台选对没在TouchGFX Designer中新建工程选择“STM32F746G-DISCOVERY”模板此时它会自动加载该板卡的LCD分辨率480x272和色彩格式ARGB8888。你不要手动修改这些参数因为CubeMX生成的硬件抽象层是基于这些参数编译的改了会导致画面偏移。创建完成后左侧是控件库中间是画布右侧是属性面板。从控件库里拖一个Button和TextArea到画布上。双击文本可以修改默认文本内容也可以在Texts选项卡里新增一个Text关联字体。字体这里有个大坑TouchGFX默认不嵌入中文字体如果你的界面要显示中文需要在Texts - Typographies里添加中文字体文件比如微软雅黑或思源黑体并设置Unicode范围。加载一个完整的中文字体文件Flash占用会飙升到几MBF746的QSPI Flash能装下但要注意不是所有位置都能存。我建议做实验阶段先用英文界面把流程跑通后再加中文别一开始就给自己挖坑。3.3 添加交互按钮按下改变文本内容在TouchGFX Designer里交互Interaction是通过“添加规则”的方式实现的。选中Button控件在右侧Interactions选项卡里点击“”添加一个Click事件动作选择Set Text目标选择之前拖进去的TextArea文本内容选择另一条文本。这样运行时按下按钮文本就会变化。这个交互生成的代码在generated/gui_generated/src/screen1_screen/Screen1ViewBase.cpp里你不需要手动修改Base类文件TouchGFX在每次重新生成UI时会覆盖generated目录下的所有文件所以如果你想自定义逻辑应该改Screen1View.cpp和Screen1Presenter.cpp而不是Base文件。3.4 导出工程让UI代码和HAL代码见面在TouchGFX Designer里点击右上角的“Generate Code”按钮它会将生成的UI代码输出到CubeMX工程目录下的TouchGFX/generated和TouchGFX/gui目录。然后在CubeMX里再次点击生成CubeMX会调用TouchGFX Generator把UI代码与HAL层代码整合到一起。如果不是用CubeMX直接生成而是手动把TouchGFX工程和HAL工程拼在一起会非常痛苦涉及到编译宏、链接脚本、启动文件等多个地方的修改。所以这也是为什么我前面强调用CubeMX TouchGFX Designer的组合两个工具之间天然兼容省去大量手工集成。快速判断UI是否生成成功打开工程目录下的TouchGFX/generated/gui_generated文件夹如果能看到按Screen名称命名的子文件夹以及generated目录下有fonts、images、texts等子目录说明TouchGFX Designer已经成功生成了UI资源代码。4. 代码集成、编译与烧录实测4.1 工程目录结构解读搞清楚每一块是干什么的打开MDK工程后你会看到左侧文件树里多出了几个分组Application/User/CoreCubeMX生成的main.c、stm32f7xx_it.c等Application/User/TouchGFX/target硬件抽象层包括TouchGFXHAL.cpp、STM32F7DMA.cpp、LCD相关驱动Application/User/TouchGFX/app_touchgfx.cTouchGFX的入口初始化函数TouchGFX/generatedUI框架生成的代码包括文本、图片、字体、交互逻辑TouchGFX/guiUI业务逻辑自己改代码的地方核心入口在main函数里。在main()中CubeMX会生成一个MX_TouchGFX_Init()调用以及一个MX_TouchGFX_Process()循环调用。前者负责初始化TouchGFX框架后者必须放在主循环的while(1)里不断驱动UI刷新。/* main.c 中的关键代码片段 */ int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_LTDC_Init(); MX_FMC_Init(); MX_I2C1_Init(); /* 其他外设初始化... */ MX_TouchGFX_Init(); while (1) { MX_TouchGFX_Process(); } }4.2 帧缓冲与内存分配检查编译前有一个非常关键的检查点确认链接脚本中SDRAM的内存区间是否被正确纳入可执行区域。TouchGFX的帧缓冲默认分配在SDRAM中但SDRAM的地址范围必须在链接脚本中声明为可用内存否则链接时会出现“Region overflow”或者“Undefined symbol”之类的错误。F746的FMC-SDRAM映射地址是0xC0000000开始最大8MB0xC0000000 - 0xC07FFFFF。打开MDK工程的.sct文件分散加载文件检查是否包含SDRAM区域LR_IROM1 0x08000000 0x00200000 { ER_IROM1 0x08000000 0x00200000 { *.o (RESET, First) *(InRoot$$Sections) .ANY (RO) .ANY (XO) } RW_IRAM1 0x20000000 0x00050000 { .ANY (RW ZI) } RW_SDRAM 0xC0000000 0x00800000 { *.o (TouchGFX_Framebuffer) .ANY (RW ZI) } }如果你的.sct文件里没有SDRAM区域需要手动添加。CubeMX自动生成的工程默认不会自动把SDRAM加入MDK的链接脚本这是一个非常隐蔽的坑。我的做法是把TouchGFX帧缓冲相关的模块强制放到SDRAM区域其余变量放在内部SRAM这样既能充分利用SDRAM大容量又不会因为SDRAM访问速度慢大约15ns访问周期拖累实时性高的代码。4.3 MDK编译配置优化等级和C标准不能乱选MDK编译TouchGFX工程时有几个编译选项会直接影响能不能编过、以及跑起来性能如何C标准必须支持C11及以上。TouchGFX 4.x的代码大量使用了auto、nullptr、右值引用等C11特性MDK老版本默认C98是编不过的。MDK 5.37之后默认就是C11老版本请在Options for Target - C/C - C Language里手动选择。优化等级调试阶段建议选-O0或者-O1跑正式性能测试再开-O2或-O3。我遇到过一个现象-O3下TouchGFX的某个成员函数因为严格别名优化被改写了行为导致界面卡死后来改成-O2就好了。所以不是所有代码都适合开最高优化。微库MicroLIB不要勾选MicroLIB。TouchGFX的C运行时需要完整的标准库支持MicroLIB阉割了部分C特性连接时会报大量“undefined reference”。One ELF Section per Function建议勾选。这样链接器可以去掉没有被引用的函数减小固件体积同时避免某些永远不会被调到的代码报错。4.4 烧录与首次运行看见画面之前还有三道关编译通过后用ST-LinkDiscovery板载连接电脑MDK里选择下载算法为STM32F7xxx Flash点击Download。如果一切顺利你会看到以下现象第一关白屏或黑屏。这说明LTDC已经初始化但帧缓冲地址不对。检查TouchGFXHAL.cpp里setFrameBufferStartAddress的地址是否指向SDRAM。TouchGFX默认会计算一个地址一般是从0xC0000000开始偏移若干字节如果你在CubeMX里配置了其他用途的SDRAM分区可能冲突。第二关画面有内容但不刷新。这通常意味着TouchGFX的主循环没有跑起来或者定时器中断配置有问题。F746的TouchGFX依赖一个TIM来产生帧同步和动画时钟在CubeMX里默认配置了TIM7作为基础定时器如果你在优化时把这个定时器关掉了UI会变成“静态图”。第三关触摸无响应。先看中断配置。FT5336的触摸中断引脚在CubeMX里默认配置为EXTI13因为PA13被复用了不对这个板子的触摸中断在PI7。打开stm32f7xx_it.c确认EXTI15_10_IRQHandler中是否调用了HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7)。TouchGFX的触摸驱动通过轮询I2C获取触摸点但需要中断唤醒。5. 常见问题速查与高性价比调优清单5.1 编译报错与链接问题速查表错误现象可能原因解决方案No space in execution regions with .ANY selector内部SRAM已满变量没有分配到SDRAM在.sct中增加SDRAM区域将大数组分配到SDRAMUndefined symbol TouchGFXGeneratedHAL::getInstance()TouchGFX Generator未生成HAL代码回到CubeMX确认TouchGFX Generator打开并重新生成fatal error: touchgfx/hal/HAL.hpp: No such file or directory头文件路径缺失Options for Target - C/C - Include Paths中添加TouchGFX/target和TouchGFX/generated/includeError: L6218E: Undefined symbol __aeabi_assert勾选了MicroLIB取消MicroLIB选项Error: L6406E: No space in execution regions链接脚本Flash区域太小检查芯片型号是否选对F746是1MB Flash不要误选512KB型号编译通过但烧录后立即HardFaultSDRAM时序配置不合理检查FMC-SDRAM初始化时序TRCD/TRP/TRC是否过小适当放宽5.2 界面性能不达标的三个排查方向如果界面跑起来了但切换动画卡顿或者触摸延迟明显优先从这三个方向排查第一个方向DMA2D是否真正参与渲染。打开调试器在TouchGFXHAL.cpp的blitCopy函数里设置断点如果断点从未命中说明TouchGFX没有启用DMA2D加速。检查TouchGFXConfiguration里是否设置了framebuffer策略为双缓冲并且在HAL初始化时是否调用了setFrameBufferStrategy。第二个方向SDRAM访问仲裁。FMC总线上同时挂着LTDC和DMA2D两者都要频繁访问SDRAM如果总线优先级配置不当DMA2D的带宽会被LTDC抢占。在CubeMX的FMC配置里有一个Memory Bus Priority设置建议将DMA2D的优先级设为HighLTDC设为Medium。这个细节官方文档里提到过但很多人没注意到。第三个方向CPU主频和Flash等待周期。F7系列在216MHz下Flash的等待周期需要配置为7个周期如果等待周期不够CPU取指会变慢整个UI线程的渲染效率会下降。打开system_stm32f7xx.c确认FLASH_ACR寄存器的LATENCY位是否设置正确。5.3 双缓冲和局部更新的底层原理TouchGFX性能好的核心在于三个技术局部更新Partial Rendering、脏矩形Dirty Rectangles和DMA2D硬件加速。它并不会每帧都重绘整个屏幕而是只重绘发生变化的区域。比如你只是把按钮从“按下”状态切回“释放”状态TouchGFX会计算出按钮所在的最小矩形区域只刷新这块区域。F746的LTDC支持设置显示窗口的位置和大小TouchGFX利用这个特性只把新数据写入帧缓冲区中对应的区域。明白这个原理后你就能理解为什么画面中的静态部分越多整体帧率越高。如果你的界面元素大量使用图片而不是实时绘制的向量图形TouchGFX可以直接搬运像素而不需要CPU逐像素计算DMA2D在这种场景下能发挥最大优势。实测经验一个包含背景图、3个按钮、2个文本和1个波形图的界面在F746216MHz ARGB8888 双缓冲下帧率稳定在55~60fpsCPU占用大约40%。如果不启用DMA2D帧率会掉到30fps左右。所以DMA2D一定要确认在正常工作。6. 从能跑到好用几个值得投入的小优化当你已经把Demo跑起来下一步建议做这三件事投入产出比最高第一件事把“单缓冲”升级为“双缓冲VSYNC同步”。很多新手跑起来后发现画面有撕裂感tearing这是因为LTDC读取帧缓冲和TouchGFX写入帧缓冲没有同步。在TouchGFX Designer的工程设置里确认Frame buffer策略是Double buffer然后在main.c里开启LTDC的VSYNC中断TouchGFX会利用这个中断来同步翻页。配置好后画面会非常干净。第二件事用图片压缩减小Flash占用。TouchGFX支持L8格式的图片这是一种索引色格式可以将图片压缩到原来RGB888的1/3大小。如果你的界面里有大面积背景图用L8格式可以显著减小固件体积同时性能几乎不受影响。TouchGFX Designer里选中图片资源在属性面板里把Image Format改成L8然后重新生成代码即可。第三件事开启功耗优化。在不需要刷新画面的时候可以让TouchGFX进入Block状态此时可以进入低功耗模式。TouchGFX提供了HAL::setFrameRateCompensation和OSWrappers::waitForVSync等接口配合STM32的WFI指令在电池供电的设备上可以节省大量功耗。F746Discovery本身是开发板功耗优化意义不大但这个思路在后续做产品时会很有用。7. 最后再分享一个调式技巧串口日志的妙用整个移植过程中我最推荐大家从一开始就开启TouchGFX的Application Monitor的Console输出。在main.c中添加一个简单的串口重映射比如用printf重定向到USART然后TouchGFX内部的所有Assert、错误信息、内存分配失败日志都会通过串口工具输出到电脑上。很多图形界面上的疑难杂症比如“画面闪烁”“触摸有时灵有时不灵”“动画突然停顿”在串口日志里往往能直接看到对应的错误信息。比如有一次我遇到动画卡顿日志里不停刷[ERROR] Frame buffer underflow一查是SDRAM带宽不足增加DMA2D优先级后问题立刻消失。没有串口日志的话这种问题排查起来真的像大海捞针。在我做的这些实验里踩得最惨的坑就是生成顺序和.sct文件的SDRAM分区这两个问题耗费的时间比写代码还多。所以这篇详细版把这个过程尽量写透希望能帮你少走这些弯路。如果你在移植过程中遇到了其他奇怪的问题可以先按这篇文章的步骤重新走一遍大部分问题都出在配置遗漏或者版本不匹配上。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门