☰
正点原子F407 FSMC屏幕跑TouchGFX:显存与刷新机制全解析
2026/10/28 15:39:06 网站建设 项目流程

简介:基于正点原子F407开发板的FSMC接口屏幕TouchGFX移植完整Keil工程,面向STM32F407嵌入式开发者,尤其适合希望从裸机或简单GUI升级到高交互图形界面的学习者。工程通过FSMC配置液晶屏并联调TouchGFX图形库,完整覆盖片选地址映射、GPIO与时序配置、并行数据读写控制、Keil编译器及链接脚本设置、触摸驱动适配、启动代码初始化等关键环节。压缩包约77.58MB,共1592个文件,以C/C++/H/CPP源码文件为主体,另有a、lib静态库、icf链接脚本、uvprojx与uvoptx工程配置、png图像及相关辅助工具,可直接在Keil中打开构建;目录结构按功能模块拆分,便于快速定位驱动与界面代码。已有402人学习下载。借助该工程,开发者既能对照代码理解FSMC控制屏幕的底层时序逻辑,也能系统掌握TouchGFX在F407上的移植流程,还可借鉴库裁剪与FPU加速等性能优化做法,显著减少后续GUI项目从零移植的调试工作量。

1. 正点原子F407开发板用FSMC屏幕跑TouchGFX:值不值,怎么干

正点原子F407开发板、FSMC接口TFT屏幕、TouchGFX这三个词放在一起,多数人的第一反应是“F407内存太小,跑不动这种重量级GUI框架”。实际折腾过一轮之后,我的结论正好相反:FSMC并口屏幕反而是F407跑TouchGFX最可行的方案之一。只要把framebuffer放到板载外部SRAM,把TouchGFX底层刷新从LTDC换成FSMC写屏函数,一块800x480的屏也能流畅做控件动画和触摸交互。这篇文章讲的就是这条完整链路,适合已经能用正点原子例程点亮屏幕、准备把界面从裸机UI升级成TouchGFX的开发者。

2. FSMC屏幕和TouchGFX的分工:先把时序和显存这笔账算清

移植失败的人,多半是一上来就抄TouchGFX官方工程。官方F407板子的LCD走的是LTDC控制器,屏幕上没有FSMC,也没有正点原子那套LCD寄存器地址宏。你的板子驱动屏幕的通道是FSMC并口,TouchGFX却默认你在用LTDC,这两套东西合不上,UI自然出不来。动手之前,先搞清楚FSMC和TouchGFX各自负责什么。

2.1 FSMC接口为什么适合当TFT屏幕的数据通道

FSMC,全称Flexible Static Memory Controller,在F407上的重要作用就是能以可配置的时序访问外部存储器或设备。TFT LCD控制芯片(比如ILI9341、NT35510)的8080并口正好是一组可被FSMC模拟的信号:CS、RD、WR、RS和16位数据线。FSMC把屏幕映射成一段内存地址,向某个地址写入是给LCD发命令,向另一个地址写入是给LCD送像素数据。正点原子F407开发板上的屏幕正是用这种方式挂在FSMC Bank1上的,片选通常接NE1,RS线接在某根地址线上。

为什么不继续用正点原子例程里同样能驱动的SPI屏幕来跑TouchGFX?SPI接口带宽太低。以常见18MHz SPI计算,传一格800x480的RGB565帧要三百多毫秒,而FSMC并口在168MHz主频下,16位数据线一次写操作在30到60纳秒,同样数据量只需要几十毫秒。FSMC的带宽勉强够TouchGFX做局部刷新,SPI则只适合静态显示。

时序参数是第一个要对数据手册的地方。F407的HCLK是168MHz,一个HCLK周期约5.95ns。FSMC访问SRAM类设备时,一个写周期由地址建立时间ADDSET、地址保持时间ADDHLD和数据建立时间DATAST组成。对NT35510这类控制器,CS滞后和WR脉冲宽度都需要留余量。我一般从下面这组参数开始调:

时序参数FSMC字段168MHz建议值对应时间
地址建立时间FSMC_AddressSetupTime0x01约12ns
地址保持时间FSMC_AddressHoldTime0x000
数据建立时间FSMC_DataSetupTime0x04约24ns
总线周转时间FSMC_BusTurnAroundDuration0x000

这组参数的含义是:FSMC拉低CS的同时给出地址和数据线上有效信号,WR低脉冲宽度由DATAST决定。如果把DATAST调到1,写周期会快到只有约12ns,超过不少LCD控制器的Write Cycle Low时间,屏幕就会随机花屏。ADDSET也不是越大越好,太大会让有效写入带宽下降,TouchGFX的刷新率跟着跌。

2.2 TouchGFX的渲染架构:framebuffer是命根子

TouchGFX不是一句函数调用画一个像素的裸机绘图库。它的渲染流程是:先在内存中的帧缓冲(framebuffer)上完成所有控件绘制,渲染结束后再把帧缓冲内容整体或局部拷贝到LCD。这样做的优势是UI绘制过程不会闪屏,代价是内存成本高。

正点原子F407探索者开发板默认配的4.3寸屏分辨率是800x480,RGB565格式下一帧就是8004802,约750KB。F407内置SRAM只有192KB,这点空间连一帧都放不下。探索者板载的IS62WV51216是1MB外部SRAM,挂在FSMC Bank1的NE3片选上,地址在0x68000000,这块RAM才是能放framebuffer的地方。移植核心思路一句话:TouchGFX渲染到的framebuffer放在外部SRAM,再通过FSMC把变化区域写到LCD。

还有一个关键点:TouchGFX的画面变化通常不是全屏,而是通过rect区域描述。一个按钮按下的高亮可能只占几十乘几十像素。TouchGFX的HAL会回调flushFrameBuffer(Rect rect),告诉你哪个区域需要刷出去。我们对接FSMC屏幕时,就按这个rect设置LCD的显示窗口,再把framebuffer里对应位置像素通过FSMC写过去,避开整屏刷新,给F407留出渲染余量。

2.3 Keil工程里的三层代码结构

一个能跑的TouchGFX Keil工程,从代码归属上分三层,这也是移植时改动的边界。

层级主要文件来源改动量
BSP层lcd.c / lcd.h / 触摸驱动正点原子LCD与触摸例程基本不改
桥接层BoardConfiguration.cpp / HAL初始化 / flush回调TouchGFX Designer生成后修改核心改动
业务层gui目录 / generated目录TouchGFX Designer生成按UI需求改

BSP层是你已经跑通的例程,负责把FSMC初始化和LCD读写函数准备好。桥接层是移植的主战场,负责告诉TouchGFX:framebuffer放哪、触摸坐标怎么采、刷新时走什么函数。业务层不用关心底层,你在TouchGFX Designer里拖控件,它生成代码,你写回调处理点击事件。

注意:TouchGFX Designer每次重新生成代码都会覆盖generated目录。需要定制的地方要么写在它保留的USER_CODE区段,要么复制到自己的源文件里,否则下一轮生成时改动直接消失。

另外,TouchGFX代码是C++写的,Keil工程必须用AC6编译器并开启C++14支持。在Keil MDK里新建工程后,Packs里要有STM32F4系列设备包,否则编译generated代码会报一堆C++语法错误。工程选项里Language C++选GNU++14,优化等级从O2开始测。

3. 搭建带FSMC驱动的Keil工程:先让屏幕亮起来再谈UI

很多移植教程教你直接打开TouchGFX Designer生成工程,然后复制正点原子的lcd.c进去,编译通过就以为成功。真这么干大概率被Keil几千行报错教做人:头文件路径没有lcd.h、FSMC库函数版本不一致、启动文件冲突。这一章说一条我验证过多次的稳妥路径:先搭一个能亮屏的裸机工程,再在此基础上叠加TouchGFX。

3.1 从正点原子例程拆出FSMC/TFT驱动

正点原子F407的例程包里,LCD显示实验的代码结构是现成的:lcd.h里有屏幕尺寸、颜色格式、全局变量;lcd.c里是LCD控制器初始化、读写寄存器和像素底层的函数。这些代码依赖STM32F4xx标准外设库(StdPeriph),如果你的Keil工程用HAL库,直接复制会报FSMC_NORSRAMInitTypeDef找不到。

我的建议是:如果你不熟悉两套库的差异,就沿用正点原子例程自带的标准外设库版本。TouchGFX本身不挑库,BSP层只调LCD驱动函数,HAL库和StdPeriph都能包。把例程里FSMC相关的GPIO配置、FSMC_NORSRAM_Init整个拿出来,放进你的工程,再写一个简单的LCD_Test验证亮屏。下面这段是FSMC配置的核心片段,去掉了大量GPIO初始化,保留真正要调的参数。

/* * fsmc_lcd_init.c * 正点原子F407 FSMC接口LCD初始化(裁剪版) * HCLK = 168MHz,数据线16位,片选NE1 */ #include "stm32f4xx.h" void LCD_FSMC_Init(void) { FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef writeTiming; // 端口时钟和GPIO配置省略:数据线PE0~PE15,控制线CS/WE/OE对应FSMC引脚 writeTiming.FSMC_AddressSetupTime = 0x01; // ADDSET = 1 个HCLK writeTiming.FSMC_AddressHoldTime = 0x00; // ADDHLD = 0 writeTiming.FSMC_DataSetupTime = 0x04; // DATAST = 4 个HCLK writeTiming.FSMC_BusTurnAroundDuration = 0x00; // 总线周转时间 writeTiming.FSMC_ClockDivideBy = 0x00; writeTiming.FSMC_DataLatency = 0x00; writeTiming.FSMC_AccessMode = FSMC_AccessMode_A; FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; // NE1片选 FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &writeTiming; FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &writeTiming; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE); }

这段代码的逻辑是:先把读和写统一用一套时序结构体,再初始化Bank1第1个片选。如果你的屏幕接在NE2或NE3,把FSMC_Bank1_NORSRAM1改成对应枚举,地址偏移会跟着变。时序ADDSET和DATAST从HCLK换算而来,上电后如果屏颜色发虚,优先把DATAST从0x04加到0x06,不要一上来怀疑TouchGFX。

3.2 用Keil MDK把工程搭起来:设备包、编译器和启动文件

如果哪天在Keil里新建工程时找不到F407,十有八九是设备包没装好。Keil MDK新装好的时候,Pack Installer里的STM32F4系DFP包可能显示Offline,设备下拉列表里自然没有STM32F407ZGTx。常见做法是:打开Pack Installer,在Device里找到STMicroelectronics -> STM32F4 Series -> STM32F407,装上对应版本,再回Keil新建工程。如果Pack显示Offline,先检查本机是否已经离线装过包,或者让Pack Installer刷新一下在线仓库。

工程选好芯片后,启动文件用工程自带的startup_stm32f40xx.s,然后按正点原子例程的时钟树配168MHz主频。TouchGFX帧率计算、FSMC时序都基于这个主频,配错的话DATAST时间参数全都不准。我习惯在SystemInit()后读SystemCoreClock,确认等于168000000再继续。

把上一节的fsmc_lcd_init.c和正点原子的lcd.c加进工程,在main()里先初始化FSMC和LCD,点亮纯色背景,这一步跑通了,底层通道就证明没问题。

// main.c 最小亮屏验证 #include "lcd.h" #include "fsmc_lcd_init.h" int main(void) { LCD_FSMC_Init(); // GPIO + FSMC + LCD控制器初始化 LCD_Clear(0xFFFF); // 刷白屏,FSMC出错会花屏或全黑 while (1) { LCD_Fill(0, 0, 100, 100, 0x001F); // 左上角画一块蓝色 } }

这段代码就是“后悔药”:确认屏亮之前不碰TouchGFX,所有问题隔离在BSP层。LCD_Clear是刷整屏,出现纵向条纹、颜色错位,优先去调FSMC时序,而不是往下走。

3.3 把TouchGFX库文件和生成代码装进工程

TouchGFX Designer生成工程时,默认会为一款评估板输出完整目录,包含TouchGFX库源码、generated目录和platform目录。我们不要直接拿那个工程改板级定义,更推荐的做法是:在TouchGFX Designer里选一个同为Cortex-M4F的F407模板,设置屏幕分辨率为800x480、颜色格式RGB565,生成工程。

生成后,把工程里的TouchGFX核心源码复制到你Keil工程的TouchGFX目录。在Keil里添加的组我一般这样分:

  • TouchGFX/Generated:TouchGFX Designer生成,代码里有USER_CODE保留区
  • TouchGFX/HAL:板级HAL实现,刷新回调和framebuffer地址都在这里改
  • TouchGFX/Platform:不同编译器下的内存和OS抽象,与Keil编译配置强相关
  • TouchGFX/GUI:业务UI代码

编译前确认两件事:第一,工程语言设置为C++14,编译器用ARM Compiler 6,也就是AC6;第二,TouchGFX源码里有一处memory接口引用了编译器片段,Keil下要看platform/keil子目录的配置,不是所有平台代码都能直接编过。第一次编译能过的时候,往往已经能跑一个不接LCD的TouchGFX空工程了。

4. 把TouchGFX接到FSMC屏幕:从HAL到刷新回调的完整对接

到这一章,BSP层已经证明能点亮屏幕,TouchGFX代码也能编译。剩下的问题只有一个:TouchGFX怎么把framebuffer里的画面搬到你那块FSMC屏幕上。官方生成的HAL层默认LCD挂在LTDC上,只要是正点原子这类FSMC接口屏,就得动HAL层。这一章讲清楚改哪几个文件、函数之间怎么衔接、改完怎么验证。

4.1 修改BoardConfiguration:关掉LTDC,换成FSMC屏

TouchGFX Designer为F407评估板生成的工程里,BoardConfiguration.cpp负责初始化LCD控制器LTDC、DMA2D和中断。正点原子的FSMC屏没有LTDC,这段初始化代码编译能过,但运行时去访问不存在的LTDC寄存器就会卡死。移植第一步,把LCD_Config()里的LTDC初始化砍掉,换成你已经调通的FSMC初始化。

// BoardConfiguration.cpp 中 LCD 初始化部分修改示意 #include "lcd.h" #include "fsmc_lcd_init.h" void LCD_Config() { // 删除 LTDC_Init() 和 DMA2D 相关寄存器配置 // 那些是给官方F407 LTDC屏用的 // 换成正点原子FSMC屏幕初始化 LCD_FSMC_Init(); LCD_Clear(LCD_COLOR_BLACK); }

不要在这个函数里塞太多东西。LCD_Config在系统上电时调用一次,只负责把屏幕底子打好。TouchGFX有自己的一套显示刷新机制,这里只做初始清屏。如果在里面绘制整个UI,后面的flush回调会跟它打架,出现第一帧花一下再正常的现象。

4.2 把flushFrameBuffer接到FSMC的写窗口函数

TouchGFX运行时的刷新入口是HAL::flushFrameBuffer(const Rect& rect)。官方LTDC方案里,这个函数什么都不用做,LTDC会持续从framebuffer读像素;FSMC方案没有这种自动搬运能力,必须在flush里主动把rect区域内的像素写到LCD。

写屏幕不是直接从左到右扫一行,而是先把LCD的显示窗口设置成rect对应的坐标区间,然后在窗口内连续写像素。常见的NT35510流程是这样:

// TouchGFX_User_Callbacks.cpp #include <touchgfx/hal/HAL.hpp> // 每帧渲染完成后,TouchGFX会把需要刷新的区域交给这个函数 static void TouchGFX_FlushFrameBuffer(const touchgfx::Rect& rect) { uint16_t* fb = (uint16_t*)touchgfx::HAL::getInstance()->getFramebuffer(); const uint16_t width = 800; const uint16_t height = 480; uint32_t offset = rect.y * width + rect.x; LCD_SetWindow(rect.x, rect.y, rect.width, rect.height); LCD_SetCursor(rect.x, rect.y); for (uint32_t i = 0; i < rect.width * rect.height; i++) { LCD_WR_DATA(fb[offset + (i / rect.width) * width + (i % rect.width)]); } }

这段代码的逻辑是:framebuffer是一块连续线性内存,第y行第x列的像素地址是y*width + x。Rect给出变化区域的左上角坐标和宽高。第一步把LCD窗口和光标移到rect起点,然后按行读framebuffer写LCD。这里有个参数特别容易错:LCD_SetWindow和framebuffer的行宽必须分辨率一致;如果你在TouchGFX Designer里设的800x480,而lcd.h里的宽度也是800,那没问题。宽高不一致时颜色就会斜向错位,查起来非常费劲。

更高效的做法是:如果LCD控制器写完一个窗口会自动换行,可以跳过SetWindow,直接用rect坐标算偏移,连续写rect宽乘高的像素。但NT35510这种屏要小心,跳过SetWindow容易在右边界出现数据错位,我建议新手上路都老老实实先设窗口。

4.3 在HAL初始化里指定framebuffer地址

framebuffer地址不能用默认值。HAL默认从内部SRAM或链接脚本指定的地址取帧缓冲,这个地址要指向正点原子板载的外部SRAM,否则192KB内部RAM在分完堆栈后,连一个800x480的缓冲都装不下。改法是在生成工程里找到类似TouchGFXConfiguration.cpp的位置,把framebuffer地址传给HAL。

// TouchGFXConfiguration.cpp 节选 #include <touchgfx/hal/HAL.hpp> #include <touchgfx/hal/OSAL.hpp> // 正点原子F407探索者板载SRAM挂在FSMC Bank1 NE3,基址0x68000000 // 从0x68000000开始放framebuffer,单缓冲800x480x2字节 #define FRAMEBUFFER_ADDR ((uint8_t*)0x68000000UL) static uint8_t* getFramebuffer() { return FRAMEBUFFER_ADDR; }

地址换算有个坑:0x68000000是16位SRAM的基址,TouchGFX在RGB565模式下把它当uint16_t数组用,但这里按8位地址传,HAL内部会做类型转换。如果要双缓冲,第二个缓冲地址就是0x68000000 + widthheight2,我习惯在宏里写死,避免运行期乘法引入延迟。800x480单缓冲750KB已经吃掉了1MB SRAM的三分之二,双缓冲在这里放不下,所以F407+FSMC方案基本都是单缓冲加局部刷新。

4.4 触摸转发:让TouchGFX收到点按事件

正点原子屏幕的触摸芯片不管是GT9147还是其他IIC电容屏,TouchGFX都不会自动认识它。需要在应用循环里轮询触摸驱动,把坐标传给TouchGFX的HAL。常见做法是在touchgfx_config.cpp里加上这样的函数:

// 在应用主循环里周期调用 void TouchGFX_Task() { int16_t x, y; uint8_t pressed = Touch_Scan(&x, &y); // 正点原子触摸驱动 touchgfx::HAL::getInstance()->setTouchPress(pressed); touchgfx::HAL::getInstance()->setTouchCoordinate(x, y); }

注意坐标要和LCD坐标一致。正点原子例程带软件校准系数,直接用原始值会导致点击偏移。建议先在校准函数里把比例算好,再输出给TouchGFX。另外,触摸中断尽量别打断flush回调,容易在搬运像素时因IIC时序过长导致刷新撕裂。我一般把触摸扫描放到空闲任务里,每10到20毫秒采一次。

5. FSMC+TouchGFX移植避坑与常见问题排查:花屏、卡死、RTX资源看不见

翻车点很集中,大多是三个方向:总线时序、内存布局、调试器交互。这里把我在正点原子F407上踩过的坑按“现象、原因、解决”排列,方便一条条对着查。

5.1 屏幕花屏且颜色错乱:FSMC地址偏移和写时序共同作用

现象:用LCD_Clear刷纯色,屏幕上出现斜条纹或随机杂色;TouchGFX画面能出来,但控件边缘有彩色噪点。

原因:常见原因是FSMC写时序太快,LCD控制器采样到不稳定的数据。另一个隐蔽原因是LCD_REG与LCD_RAM地址相差错误,导致命令字被当成像素写。正点原子例程的LCD_BASE宏是针对它自家板子RS接线位置的;如果你是自己连FSMC线,要重新核对。

解决:先用比规格书更保守的时序测试,FSMC_DataSetupTime从0x04调到0x06或0x08,同时保持DataAddressMux为Disable。颜色恢复后再逐步降低DATAST到稳定最小值。地址偏移问题,用DMA读取LCD控制器ID的指令(比如0xDA00或NT35510的厂商ID命令),在调试器里观察读回值,能正确返回则地址对,否则重新算LCD_REG宏。

5.2 HardFault或直接黑屏:framebuffer放进了内部SRAM

现象:TouchGFX初始化代码一执行,Keil就跳到HardFault_Handler,或者屏幕黑屏但程序没有死。

原因:TouchGFX默认配置的framebuffer地址在内部SRAM,而F407只有192KB。800x480一帧就要750KB,加上RTX任务栈和TouchGFX对象池,瞬间溢出。这属于最典型的移植翻车。

解决:把帧缓冲地址指到外部SRAM,同时确认链接脚本没有把小节数据放到那个区域。用uint8_t*定义framebuffer地址后,在HAL初始化前调用一次memset把整块缓冲清成0,避免残留数据导致首帧乱码。如果板载SRAM也不够,就降分辨率到480x272以内,而不是去调TouchGFX内部的水印参数。

5.3 Keil仿真时RTX资源看不见、退出仿真就卡死

现象:工程用RTX5做任务调度,Keil在线调试时打开RTX任务和事件查看器,任务列表空白;调试结束后点停止仿真,Keil像死掉一样,只能任务管理器强杀。

原因:RTX资源看不见一半是OS配置问题,一半是调试脚本没加载。RTX5任务监控依赖Event Recorder,工程里要有EventRecorder组件,并且在Keil的Debug设置里让程序停在main()处。退出仿真卡死则常出现于FSMC正在连续访问外部SRAM时停止CPU,调试器去释放总线却等不到FSMC响应,Keil的调试后端就挂起。

解决:退出仿真前,先在main的while(1)里下断点,让程序停在一个安全位置。如果还卡死,把FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, DISABLE)放在断点之前,停止仿真时FSMC不再占用总线。RTX任务列表看不见时,检查工程里是否加入了EventRecorder源文件,并在RTX_Config.h里使能调试组件。Keil识别不到ST-Link导致无法进仿真时,先检查USB驱动,再用ST-Link Utilities擦除芯片重新上电,别急着怀疑工程坏了。调试界面里Periodic Window Update选项开太大也会拖慢RTX调试信息刷新,仿真时把它改小或关掉。

5.4 Keil打不开TouchGFX生成的.uvprojx:版本和路径的玄学

现象:TouchGFX Designer生成的工程文件双击后Keil报版本不兼容,或者打开了但大量源文件路径带红色感叹号。

原因:TouchGFX Designer版本和Keil MDK版本不匹配,生成的工程文件格式较新;路径里带中文或空格,旧版本Keil工程管理解析不好。

解决:统一用MDK 5.30以上版本打开。如果打不开,就在生成目录里新建空工程,手动添加文件。工程文件夹千万别放中文路径,这是Keil老毛病,也是TouchGFX路径解析最容易爆的点。天大的道理不如工程路径里一个中文字符的坑来得实在。

6. 让TouchGFX真正跑顺的最后一公里:帧率优化与验证

移植跑通之后,下一步是让帧率好看。我用的验证方法是:在UI上放一个每秒变化的数字,同时用GPIO翻转测刷新周期。在TouchGFX每帧回调里翻转PB0,示波器看PB0周期就是整体帧时间。

优化项改动位置效果
局部刷新确认TouchGFX的HAL使用了rect回调按钮动画从10fps提到25fps以上
连续写屏flush循环里避免逐像素函数调用刷新时间可省20%
单缓冲降低分辨率或缩小UI动画区域内存占用从750KB降到261KB

以800x480整屏为例,拷贝一次750KB,FSMC在DATAST=4时实际写约10MB每秒,整屏刷一次要75毫秒,只有13fps左右。如果UI动画只在屏幕小区域变化,TouchGFX的rect通常只有几千像素,局部刷新后帧间隔能压到30毫秒以内。

注意:看到网上拿DMA2D优化TouchGFX的文章,先说一句——DMA2D是F429/F469才有的外设,F407没有。别在F407上找这个寄存器,浪费时间。

我自己这轮移植下来,最大的教训是:分辨率选定之前先算内存账,FSMC时序验证之前不加TouchGFX文件。这两条习惯帮我避开了大半的坑。如果你也打算在正点原子F407上跑TouchGFX,希望这一套从底层时序到Keil调试的经验能帮到你,少走我走过的弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询