首页 / 资讯中心 / 文章详情

STM32H750外部QSPI Flash下载算法FLM制作与Keil集成全攻略

STM32H750外部QSPI Flash下载算法FLM制作与Keil集成全攻略 ★ FEATURED ARTICLE
如果你跟我一样被STM32H750的128KB内置Flash坑过那这篇内容应该能帮你省下不少时间。H750这颗芯片的CPU主频可以跑到480MHz性能很强但片上Flash只有128KB稍微上点UI、协议栈、字库容量就见底了。我手头的项目就在片外挂了一颗W25Q324MB通过QSPI接口把代码和应用数据都放到外面但真正开始搞的时候发现“把程序弄进去”这件事一点也不省心。最初我用的是串口升级方案一个bootloader加一个app上位机通过Ymodem协议发bin文件中间要处理应答、校验、断点续传一堆事情每次改一行代码都要重新编译、打包、发串口再等它慢慢烧进去非常耽误事。后来我抽时间把MDK的FLM下载算法做出来在Keil里按一下F8就能直接烧到外部W25Q32还能在线打断点调试体验和调试内部Flash几乎一样彻底告别串口搬运。这篇文章以W25Q32这颗常用的4MB QSPI Flash为例从原理到工程配置完整走一遍内容包括FLM文件的结构、下载算法的工程搭建、QSPI底层驱动的写法、用户工程里的Flash Download设置以及从外部Flash启动时常见的“卡死”问题排查。不管你是第一次接触FLM还是已经试过但没跑通这篇都能给你一个可落地的参考。1. 为什么需要自己写下载算法1.1 STM32H750的存储困局STM32H750在宣传上很吸引人Cortex-M7内核480MHz主频带FPU和DSP指令还有512KB的RAM价格也合适。但它的内部Flash只有128KB连同系列的H743都有2MBH750却只给这么多摆明了是让你外挂存储。128KB听起来不算太少可现在随便一个图形界面、传感器算法库、日志系统堆进去就超了。我当时的项目里光字库和图片资源就要占用将近300KB内部Flash根本装不下。W25Q32这颗Flash容量4MB32Mbit工作在Quad SPI模式下读写速度都不错单价也低是H750外扩存储很常见的搭配。容量问题解决了新的问题来了程序放在外部Flash上怎么烧进去怎么启动怎么调试这三个问题里烧录就是下载算法要解决的核心。1.2 没有下载算法时的几种“土办法”在没有自定义FLM之前常见的烧写外部Flash方式有几种但都各有各的难受。第一种是串口升级。内部Flash先烧一个bootloader上电后通过串口接收bin文件再写入外部Flash。好处是方案灵活量产时可以用坏处是开发阶段太慢我编一句“Hello world”级别的工程也要走一遍拆包、校验、擦除、写入的流程擦除4MB Flash的时间都够喝杯水的了。而且这个过程里不能打断点出了问题只能靠串口日志猜。第二种是用调试器先把bin文件加载到内部RAM然后手工执行一段RAM中的搬移代码把RAM里的数据写到外部Flash。这种方式本质上就是手写一个简易烧写器调试起来同样痛苦每次都要重新加载RAM地址还要手动计算非常容易出错。第三种是在ST-Link/J-Link下做一个“Copy”操作的初始化脚本用U-Flash这类工具把bin文件写到外部Flash。这种方式能用但脚本一旦遇到时序问题难查而且和Keil的集成度不够不能实现“Flash Download”里的擦除、编程、校验一体化管理。这些土办法绕了一圈之后你会发现最终还是要落到“下载算法”上。因为MDK本身已经定义了完整的Flash烧写框架我们只要按它的约定写一个FLM文件就能让Keil像操作内部Flash一样操作外部QSPI Flash。1.3 下载算法帮你做了哪些事FLMFlash Loader Module是一个运行在MCU RAM中的小程序负责完成Flash的初始化、擦除、编程和校验。当你在Keil里点击Download时MDK会把FLM加载到指定的RAM区域然后通过调试器调用FLM里的函数向外部Flash发送QSPI命令完成写入。有了FLM以后烧写流程就变成了点击编译下载MDK自动定位用户程序加载地址比如0x90000000调试器加载FLM到RAM先执行Init初始化QSPI按配置执行擦除操作整片或扇区调用ProgramPage把映像写入Flash调用Verify校验写入数据最后UnInit收尾程序可以直接运行。这个流程全程在Keil界面里自动化完成不需要额外的上位机软件也不需要串口线效率高一个数量级。2. FLM文件原理与结构2.1 FLM其实是一个运行在RAM里的ELF程序很多第一次接触FLM的人会以为它是一个普通固件文件其实FLM是标准的ELF格式ARM ELF包含代码段、数据段和调试信息。MDK通过调试器把它加载到RAM里然后像调用子程序一样调用里面的函数。从这个角度看FLM和用户程序的本质区别只有一个FLM永远在RAM中运行地址和跳转都不涉及外部Flash自身的执行。这一点很重要因为烧写算法发生在Flash还没内容的时候不能指望从外部Flash取指令。2.2 标准函数接口Init、Erase、Program、Verify在MDK的Flash框架里FLM对外暴露的函数是固定的名字和语义都不允许随便改否则Keil无法识别。下面这几个是核心函数我用表格整理了一下它们的作用和调用时机函数名作用调用时机Init初始化Flash控制器、配置GPIO、读取芯片ID每次下载开始前UnInit反初始化恢复GPIO状态下载结束后EraseChip整片擦除勾选“Erase Full Chip”时EraseSector擦除指定扇区W25Q32最小4KB勾选“Erase Sectors”时ProgramPage编程一页数据最长256字节每个页面写入时调用Verify校验写入内容和源数据是否一致下载结束后校验阶段除了这些函数FLM里还必须定义一个全局结构体FlashDevice用于向MDK描述这颗Flash的基本属性。结构体里的关键字段包括Flash起始地址、总容量、页大小、擦除后的默认值W25Q32擦除后是0xFF、编程超时和擦除超时等。当你把FLM添加到Keil的Flash Download对话框时Keil读取的正是FlashDevice里的信息所以在算法工程里一定要仔细填这个结构体。2.3 FlashDevice描述符如何影响下载行为FlashDevice结构体大概长这样struct FlashDevice const FlashDevice { 0x0100, // 版本号不能乱填 W25Q32 QSPI 4MB, // 设备名称会显示在Flash Download对话框中 EXTSPI, // 设备类型外部SPI/QSPI Flash 0x90000000, // Flash映射地址 0x00400000, // 总容量4MB 256, // 页大小W25Q32一页256字节 0xFF, // 擦除后的数据值 0, // 保留 2000, // 编程超时毫秒 3000, // 擦除超时毫秒 0x1000, // 块大小4KB扇区对应的属性 {0} // 保留字段 };设备名称会直接出现在Keil的Flash Download算法列表里建议写清楚芯片型号和接口方便以后区分。3. 动手前的准备W25Q32与H750的QSPI接线3.1 硬件连接和引脚复用不同开发板上的QSPI引脚布局不一样但绝大多数H750板子都习惯把QUADSPI映射到PF和PG这组引脚上我用的板子连线如下信号引脚QSPI_CLKPG6QSPI_CSPG7QSPI_IO0 (DI)PF8QSPI_IO1 (DO)PF9QSPI_IO2PF10QSPI_IO3PF11如果你的板子引脚不同一定要去H750数据手册的Alternate Function表里查一下QUADSPI对应的复用编号不能想当然按这个接。引脚接错时最典型的症状是JEDEC ID读出来全是0xFF或者0x00折腾半天都定位不到问题。3.2 W25Q32的关键指令和两种编程模式W25Q32是Winbond的QSPI Flash容量4MB支持标准SPI、Dual SPI、Quad SPI。在下载算法阶段我们主要用命令模式Command Mode来发指令而不是内存映射模式Memory Mapped Mode。常用指令如下指令功能指令码Write Enable写使能0x06Read Status Register-1读状态寄存器0x05Read JEDEC ID读芯片ID0x9FSector Erase4KB扇区擦除0x20Page Program页编程标准SPI0x02Quad Input Page Program页编程四线输入0x32Quad Output Fast Read四线快速读0x6B页编程一次最多256字节并且不能跨页。也就是说如果待写入的数据跨越了两个256字节的页边界必须拆成两次Page Program命令。这个坑在写ProgramPage函数时需要特别小心因为MDK的FlashDevice里PageSz配置成256它会按页去调用ProgramPage但如果你自己封装驱动时把地址计算错跨页数据就会写到错误位置。3.3 STM32H750 QUADSPI外设的基础配置H750的QUADSPI外设功能很强大但也容易把人绕晕。我在下载算法里只用了它最基本的“间接模式”功能流程是写指令寄存器配置指令码写数据寄存器发送数据查状态标志判断完成。关键点有这几个时钟使能QUADSPI挂在AHB3总线上需要先使能外设时钟GPIO复用所有QUADSPI引脚要配置为AF模式复用编号在H750数据手册里是AF9或AF10不同引脚不同QUADSPI控制寄存器需要初始化为Flash Size、CS高电平时间等参数发送指令时一定要先“写使能”WREN否则Flash会拒绝擦除和编程。这些配置我后面会直接放到代码里不过先建议你把QUADSPI的CR、DCR、FCR、TCR这几个寄存器的作用在参考手册里过一遍不然遇到问题时很难判断是配置问题还是Flash时序问题。4. 创建MDK下载算法工程4.1 新建算法工程模板在Keil里做FLM有两种方式一是基于MDK自带的模板改二是从零建一个空工程。我推荐从零建因为模板里带了一些和具体芯片无关的文件反而容易搞混。打开MDK后新建工程芯片选STM32H750VBTx然后添加以下几类代码文件一个startup汇编文件启动文件用来保证FLM在RAM运行时的基本环境一个QSPI驱动源文件我习惯叫bsp_qspi_flash.c实现底层读写擦除一个FLM接口源文件类似flash_prg.c实现Init、EraseSector、ProgramPage等函数在头文件里引入FlashOS.h这个头文件在Keil安装目录下比如C:\Keil_v5\ARM\Flash_Template\FlashOS.h。FlashOS.h定义了FlashDevice结构体和各函数原型是FLM框架的“契约”不建议自己另写一份。4.2 编写QSPI底层驱动QSPI底层驱动是整个FLM里最重要的一环。下载算法的目标不是追求极限速度而是稳定所以我在第一次做的时候用的都是常规标准SPI指令等跑通了再切换到Quad模式优化速度。先看初始化函数这段代码非常重要很多“读ID失败”的问题都出在这里static void QSPI_Flash_Init(void) { GPIO_InitTypeDef gpio {0}; /* 1. 使能相关时钟 */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_QSPI_CLK_ENABLE(); /* 2. 配置GPIO复用功能 */ gpio.Pin GPIO_PIN_6 | GPIO_PIN_7; gpio.Mode GPIO_MODE_AF_PP; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate GPIO_AF10_QUADSPI; HAL_GPIO_Init(GPIOG, gpio); gpio.Pin GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11; gpio.Alternate GPIO_AF10_QUADSPI; HAL_GPIO_Init(GPIOF, gpio); /* 3. 复位QUADSPI外设 */ __HAL_QSPI_RESET_HANDLE(); /* 4. 配置QUADSPI */ QUADSPI-CR 0; QUADSPI-DCR 0; QUADSPI-DCR | (31 16); /* Flash Size: 4MB 2^2222-121? 这里根据自己的实现调整 */ QUADSPI-DCR | (1 8); /* CS高电平时间 */ QUADSPI-CR | (2 24); /* 时钟分频根据主频调整 */ QUADSPI-FCR 0x1F; /* 清除所有标志 */ }时钟分频这个参数需要根据自己的系统时钟算一下。W25Q32最高可以跑104MHz但H750的QUADSPI时钟源来自AHB3直接给太高的分频会导致读写不稳定。我建议先保守一点把QSPI时钟控制在50MHz以内保证下载算法稳定后续再优化。再看读取JEDEC ID的函数static uint32_t QSPI_ReadJEDEC_ID(void) { uint32_t id 0; /* 发送0x9F命令接收3字节 */ QUADSPI-FCR 0x1F; // 清除标志 QUADSPI-DLR 2; // 需要读取3-12? 配置数据长度 QUADSPI-AR 0; QUADSPI-CCR (0x1 22) | (0x9F 16) | (0x3 14) | (0x1 10); while ((QUADSPI-SR (1 2)) 0); // 等待传输完成 id (QUADSPI-DR 0xFF) 16; id | (QUADSPI-DR 0xFF) 8; id | (QUADSPI-DR 0xFF); return id; }这里面的寄存器位宽和值不同参考手册写法略有差异重点是思路先发命令再等完成标志然后读数据。如果你发现读出的ID不对先不要怀疑芯片用逻辑分析仪看时序最常错的就是DLR数据长度和CCR里的模式位。4.3 实现FLM标准接口函数底层驱动验证通过以后FLM接口函数就简单了本质上就是把驱动包一层壳。int Init(unsigned long adr, unsigned long clk, unsigned long fnc) { QSPI_Flash_Init(); if (QSPI_Flash_ReadID() ! 0xEF4016) { // W25Q32的JEDEC ID return 1; // 初始化失败 } return 0; }Init里读JEDEC ID是非常推荐的做法它可以尽早暴露接线问题。clk参数是MDK传入的时钟频率在支持动态调频的场合可以拿来配置分频但对下载算法来说直接用固定分频就够了。擦除扇区int EraseSector(unsigned long adr) { QSPI_Flash_WriteEnable(); // 必须先写使能 QSPI_Flash_SendCmd(0x20, adr); // 4KB扇区擦除 while (QSPI_Flash_CheckBusy()); // 等待WIP位清零 return 0; }页编程int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf) { if (sz 0) return 0; QSPI_Flash_WriteEnable(); QSPI_Flash_PageProgram(adr, sz, buf); while (QSPI_Flash_CheckBusy()); return 0; }这里需要注意FlashDevice里PageSz设置为256MDK会保证传给ProgramPage的sz不会超过256字节并且adr不会跨越页边界。但如果你处理的Flash页大小不是2的整数次幂或者MDK版本行为有变化最好在ProgramPage内部加一个按256字节循环写入的保护逻辑稳一点没坏处。4.4 配置分散加载文件和工程选项FLM工程最关键的一步是让算法代码加载到RAM里运行而且这个RAM地址不能和后续用户程序冲突。我用的H750跑下载算法时选择AXI SRAM起始地址0x24000000大小给64KB左右就够了。在Keil的Options for Target里这样设置Target页IROM1设置为空IRAM1地址填0x24000000大小填0x10000Linker页取消勾选“Use Memory Layout from Target Dialog”改用自定义的分散加载文件Output页把输出文件名改成“QSPI_W25Q32”并且勾选“Create Flash Loader”如果你的MDK版本有这个选项的话没有的话可以直接把生成的.axf复制改名为.flm。一个最简单的分散加载文件长这样; 下载算法只放到RAM中执行 LOAD_REGION 0x24000000 0x00010000 { EXEC_REGION 0x24000000 0x00010000 { * (RESET, First) * (RO) * (RW, ZI) } }如果你用的不是新版本MDK生成FLM时可能会遇到找不到“Create Flash Loader”选项的情况。老版本的常见做法是编译生成.axf之后手动复制为.flm后缀Keil也是认的因为它本质上是ELF文件后缀名不影响格式解析。4.5 编译生成的常见错误这个阶段最容易遇到两类编译错误。第一类是找不到FlashOS.h或相关头文件。解决方法是把Keil安装目录下的Flash模板文件夹加进Include Path比如C:\Keil_v5\ARM\Flash_Template。第二类是链接错误L6220E提示加载区地址和执行区地址不匹配。这通常是因为你在Target页里没有清空IROM1或者在分散加载文件里RO地址和RAM地址写反了。FLM的原则是代码最终在RAM里执行所以分散加载里的执行区一定要在RAM段。还有一点建议编译器优化等级先设置为-O0或者-O1。QSPI寄存器操作涉及大量硬件时序编译器优化等级过高时某些寄存器读写的顺序可能被重排导致Flash操作神秘失败。我们在定位问题时尽量排除这个变量。5. 在用户工程里配置下载算法5.1 把FLM文件安装到Keil生成好的QSPI_W25Q32.flm要放到Keil能识别的位置。一般是放在C:\Keil_v5\ARM\Flash\目录下或者放在当前工程目录内然后在Flash Download对话框里手动指定。放到ARM\Flash下更通用因为这个路径是所有工程共享的。放好之后重新打开Keil进入Options for Target - Debug - Settings - Flash Download点击Add按钮应该能在算法列表里看到“W25Q32 QSPI 4MB”这个条目这就是FlashDevice结构体里的设备名称。5.2 配置RAM for Algorithm这里有个非常常见的坑RAM for Algorithm的地址和大小设置不对。下载算法本身要占用一段RAM这段RAM在烧写期间不能和调试器、用户程序冲突。我一般用0x24000000大小0x1000064KB。如果你用户程序的RW/ZI也放在0x24000000那在下载阶段问题不大因为下载算法运行时用户程序还没跑但在启动阶段如果用户程序运行时把这段RAM全部覆盖而FLM已经退出也不影响。所以只要保证烧写期间不冲突就行。Flash Download里的设置如下配置项值RAM for Algorithm Start0x24000000RAM for Algorithm Size0x10000Programming AlgorithmQSPI_W25Q32擦除方式先选Erase Full Chip调试量产再考虑Erase Sectors还有一点如果你的H750用来做下载算法RAM的是AXI SRAM而用户App里又开了D-Cache并且配置了同一个区域建议把用户App的RW/ZI放到SRAM10x30000000或者DTCM0x20000000可以避免cache一致性问题带来的随机卡死。5.3 用户工程的分散加载文件下载算法配置好之后用户程序还必须在链接时把代码段放到0x90000000这个地址这就是分散加载文件要干的事。下面是一个简单可用的示例; 程序存放在外部QSPI Flash地址0x90000000 LR_EXT_FLASH 0x90000000 0x00400000 { ER_EXT_FLASH 0x90000000 0x00400000 { startup_stm32h750xx.o (RESET, First) * (InRoot$$Sections) .ANY (RO) } RW_IRAM1 0x20000000 0x00010000 { .ANY (RW ZI) } }这里RW/ZI区域我放在DTCM0x20000000里速度最快但要留意DTCM不支持DMA访问。如果你的程序里用了DMA搬运内存DMA目的地址不能是DTCM需要调整到0x24000000或0x30000000。这个细节没有在大多数教程里讲清楚我在这里提前说明免得你程序“莫名其妙”死在DMA中断里。5.4 启动时向量表重定位程序运行在0x90000000但Cortex-M7上电后默认从0x00000000取向量表所以必须让CPU知道向量表已经移到外部Flash了。最简单的做法是确保在main函数之前完成向量表重定位。如果使用BootROM启动向量表已经在Flash最开始如果由内部Flash的loader跳转过来则需要在跳转前设置好SCB-VTOR 0x90000000;这个位置要尽量早最好在Reset_Handler里跳转main之前就执行。如果你用CubeMX生成工程有一个SystemInit函数可以在里面加也可以在跳转代码里加。如果忘记设置VTOR最常见的现象是程序一上电就进HardFault或者死在启动文件里IDE会停在“Reset_Handler”那一行看着像芯片没起来其实是向量表位置不对。6. 从外部QSPI Flash启动的两种方式6.1 使用内部Flash放一个极简Loader下载算法解决的是“怎么把App写进外部Flash”而启动方案解决的是“上电后怎么让App跑起来”。我建议第一次调试时先采用内部Flash加Loader的方式逻辑简单可控性强。内部Flash只占用前几个KB存放一个非常小的Loader它要做的事只有三件初始化系统时钟初始化QUADSPI并进入Memory Mapped模式设置SCB-VTOR 0x90000000跳转到0x90000000处的Reset_Handler。流程不复杂但要注意跳转前关闭全局中断并且保证栈指针已经被当前代码使用。代码如下typedef void (*pFunction)(void); void JumpToApp(void) { uint32_t app_addr 0x90000000; uint32_t sp_val *(volatile uint32_t *)app_addr; uint32_t rv_val *(volatile uint32_t *)(app_addr 4); pFunction jump; __disable_irq(); SCB-VTOR app_addr; __set_MSP(sp_val); jump (pFunction)rv_val; jump(); }这个方案有个额外好处Loader里的QSPI初始化和FLM中的QSPI初始化可以共用很多代码在你调试FLM时可以互相印证。比如FLM里读ID成功Loader里读ID也应该成功如果Loader能正常工作就说明FLM的底层驱动基本没问题问题多半出在FLM的接口封装层。6.2 使用H7 BootROM直接启动QSPI Flash如果你不想占用内部Flash空间也可以用STM32H7内置的BootROM直接启动外部QSPI Flash。这项工作需要在CubeProgrammer里配置Option Bytes把BOOT_ADD0或BOOT_ADD1设置为0x90000000并让芯片从上电时的BOOT引脚选择对应的启动地址。H7 BootROM会初始化默认引脚上的QSPI Flash并进入Memory Mapped模式然后跳转到0x90000000。听起来很方便但有一个大坑BootROM支持的引脚和时序是固定的如果你的QSPI Flash没有挂在系统BootROM预设的引脚上它就启动不起来。因此这个方案不能通吃所有板子需要查一下芯片应用笔记里“QSPI Boot”的引脚表。我的建议是如果你的板子刚好是官方推荐的QSPI引脚布局那BootROM方案很香如果不是老实回到Loader方案。6.3 排查“片外App卡死”的完整思路很多朋友下载都成功了程序也写进QSPI了但一运行就在某个地方卡死网上搜半天也搜不到原因。我把自己踩过几次的排查路径整理一下按顺序检查先看复位向量对不对。0x90000000偏移0处必须是有效的栈指针值0x90000004处必须是Reset_Handler地址。用调试器读内存就能确认。检查QSPI是否进入Memory Mapped模式。下载算法只是用命令模式写Flash不代表功能模式已经映射。如果程序上电时没有完成映射CPU取指就会取到0xFFFFFFFF或者空数据自然跑飞。检查VTOR是否指向0x90000000。中断向量表没重定位的话第一个中断就会卡死。检查D-Cache和MPU配置。Cortex-M7上使能D-Cache后如果MPU没有把QSPI映射区域配置为合适的缓存属性读数据可能出现陈旧值。开Cache前一定要先配置MPU。这几个问题排查完绝大多数“片外App卡死”都能定位。如果你在中断或DMA访问外部Flash时卡死还要额外检查QSPI是否正忙、是否在中断服务函数里发起了新的Flash操作。7. 常见问题与排查技巧实录7.1 问题速查表我在做这个FLM的过程中遇到并解决了不少奇怪问题这里整理成一张速查表给遇到类似情况的朋友直接对照现象可能原因解决办法下载时提示“Erase Failed”QSPI时钟过高、Flash未写使能降低分频确认写使能命令已发送下载时提示“Verification Failed”页编程地址/长度处理错误检查ProgramPage是否按256字节页边界处理下载后程序完全跑飞VTOR未设置、QSPI未映射设置VTOR到0x90000000确保进入Memory Mapped模式程序运行过程中随机HardFaultCache一致性问题配置MPU、关闭D-Cache或调整RW/ZI到非Cache区域中断服务函数里访问Flash卡死QSPI正忙/状态标志未清除等待忙位、清除标志后再发命令Keil里新增算法后找不到FLMFLM放错目录或后缀名不对放到ARM\Flash目录确认后缀是.flm老版本MDK无法生成flm版本太老不支持Flash Loader生成编译后把.axf复制改名为.flm下载算法运行时死在跳转处启动文件/分散加载配置错误清理中断、确保加载区与执行区一致7.2 制作流程中的几个独家建议第一个建议先把QSPI驱动做成一个独立的裸机验证工程。具体做法是用CubeMX生成一个工程直接操作QUADSPI寄存器读写Flash串口打印JEDEC ID、擦除结果、写入回读结果。这个工程一旦验证通过FLM的底层驱动等于完成了80%。不要一上来就直接写FLM否则出问题时分不清是FLM框架问题还是驱动问题。第二个建议ProgramPage函数里记得用volatile修饰状态寄存器相关的变量并且每次擦写完成后都检查WIP位。我之前遇到过编译器优化把忙等循环优化掉的情况导致下载完成后数据实际没写进去折腾了半天才发现是优化的问题。开-O0或者加volatile都能避免。第三个建议第一次测试下载算法时在Flash Download对话框里选“Erase Full Chip”不要选“Erase Sectors”。扇区擦除日志里看似更快但如果你要排查问题整片擦除能排除“残留数据影响”的干扰。第四个建议关于MDK工程编码如果你的工程里有中文注释并且团队里有人用VS Code或Git工具打开文件很容易出现GBK和UTF-8互相干扰的乱码问题。建议把源代码文件统一转换为UTF-8编码并在MDK里把Editor的Encoding设置为UTF-8。转换完以后重新编译一遍确保没有因为编码问题破坏字符串字面量。7.3 关于下载速度的优化W25Q32标准SPI模式下页编程速度有上限大约在几百KB每分钟的量级对于一个4MB的Flash来说全片编程会有点慢。如果你的项目经常需要全量烧写可以做两点优化。第一ProgramPage启用Quad Input Page Program0x32指令这样写入速度能提升不少。第二EraseSector启用Quad模式下的相关指令减少擦除等待时间。但不要一上来就追求四线先把标准SPI流程跑通然后一档一档往上加。QSPI是高速数字接口引脚时序、上下拉、走线长度都会影响最高稳定频率量产时千万别把时钟拉到极限去赌良率。8. 写在最后的一些经验这套FLM方案做下来之后我的开发效率提升非常明显。以前一个版本从编译到烧写完毕至少两三分钟现在按下F8十几秒就完成擦除、编程、校验还能直接在外部Flash上打断点调试确实有种“终于正常了”的感觉。我对第一次动手做FLM的朋友有一个建议不要把目标一开始就定得太大。先做一个只支持整片擦除、标准SPI读取、标准SPI页编程的最小FLM能跑通下载和调试以后再逐步加入四线指令、扇区擦除、快速读模式这些优化。每一步都验证通过再进入下一步弯路最少。最后再分享一个小技巧如果你在调试FLM过程中遇到下载失败但代码看起来都正常试着换一根SWD线或者把调试器速率从4MHz降到1MHz再试一次。这个问题不常发生但一旦发生排查起来极其诡异。硬件调试就是这样软件逻辑正确只是前提信号完整性和稳定的调试链路同样重要。希望这篇分享能帮你少踩几个坑顺利把外部QSPI Flash用起来。
阅读完成 · 觉得有帮助?
咨询建站