NXP i.MX RT1170 通过 FlexSPI 外接 NOR Flash(如 W25Q512N)时,Keil MDK 默认无匹配下载算法,导致程序无法烧录调试。核心解决思路是基于 Keil 自带模板,修改 Flash 属性描述、实现标准编程接口,复用 NXP SDK 的 FlexSPI 驱动,生成专属.FLM 算法文件。本文详解从工程搭建到验证的完整流程,新手也能快速适配任意 FlexSPI NOR Flash。
1. 核心背景与目标
1.1 痛点场景
- 硬件:RT1170EVKB 开发板 + W25Q512NWEIQ(64MB NOR Flash,FlexSPI1 接口,AHB 映射地址 0x30000000);
- 问题:Keil 无官方下载算法,更换外部 Flash 后无法烧录调试;
- 优势:复用 NXP SDK 驱动,无需从零开发 FlexSPI 操作函数,效率翻倍。
1.2 最终目标
生成适配 W25Q512N 的.FLM 下载算法,实现 Keil 环境下 “擦除→编程→验证” 全流程,支持程序烧录与在线调试。
2. 环境准备
2.1 硬件清单
- 开发板:NXP i.MX RT1170EVKB;
- 外部 Flash:Winbond W25Q512NWEIQ(64MB,Quad SPI 模式);
- 调试器:CMSIS-DAP(或 J-Link,本文以 CMSIS-DAP 为例)。
2.2 软件工具
- IDE:Keil MDK 5.x;
- SDK:NXP MCUXpresso SDK for RT1170EVKB(含 FlexSPI NOR Flash 驱动);
- 核心模板:Keil 自带
_Template(路径:Keil_v5→ARM→Flash→_Template)。
3. Keil 下载算法核心结构
Keil 自定义下载算法由 3 个核心文件 + 底层驱动组成,结构清晰,无需复杂开发:
- FlashDev.c:描述 Flash 硬件属性(容量、页大小、地址、超时等),Keil 通过该文件识别 Flash;
- FlashPrg.c:实现 Keil 标准编程接口(Init、EraseSector、ProgramPage 等),调用 SDK 驱动;
- FlashOS.h:Keil 提供的接口规范头文件,必须保留,无需修改;
- 底层驱动:复用 SDK 的
flexspi_nor_flash_ops.c,包含 Flash 初始化、擦除、编程等现成函数。
Keil 调用流程
Init()(初始化FlexSPI)→ EraseSector/EraseChip(擦除)→ ProgramPage(编程)→ Verify(校验)
4. 分步构建流程(重点实操)
4.1 工程搭建与配置
(1)复制模板工程
- 找到 Keil 安装目录下的
_Template文件夹,复制到自定义开发目录(如 “RT1170_Flash_Algorithm”); - 保留文件夹内所有文件(FlashDev.c、FlashPrg.c、FlashOS.h 等),重命名工程为 “RT1170_W25Q512N.uvprojx”。
(2)工程选项配置
- 打开工程,点击「Options for Target」→「Device」,选择 “MIMXRT1176DVMAA:cm7”(匹配 RT1170 内核);
- 「C/C++」选项卡:
- 定义宏:
CPU_MIMXRT1176DVMAA_cm7; - 包含路径:添加 SDK 的 FlexSPI、CMSIS 相关头文件路径(如 “SDK/devices/MIMXRT1176/drivers”“SDK/CMSIS/Core/Include”);
- 优化等级:设为 “O1”,避免驱动函数被优化失效。
- 定义宏:
4.2 FlashDev.c 修改(描述 Flash 属性)
核心是让 Keil 识别 W25Q512N 的关键参数,直接替换以下代码:
// W25Q512NWEIQ(64MB,FlexSPI1映射地址0x30000000)
struct FlashDevice const FlashDevice = {
FLASH_DRV_VERS, // 驱动版本(固定不变)
"W25Q512NWEIQ 64MB Flash",// 设备名称(自定义,便于识别)
EXTSPI, // 设备类型:外部SPI/QSPI
0x30000000, // AHB映射起始地址(必须与硬件一致)
0x04000000, // 设备容量:64MB(0x04000000字节)
256, // 编程页大小:256字节(W25Q512N固定)
0, // 保留参数:设为0
0xFF, // 擦除后默认值:0xFF
100, // 页编程超时:100ms(留足裕量)
3000, // 扇区擦除超时:3000ms(4KB擦除足够用)
// 扇区布局:全片4KB均匀扇区
0x001000, 0x00000000, // 扇区大小4KB(0x1000),起始偏移0
SECTOR_END // 扇区布局结束标记
};
- 关键注意:起始地址、容量、页大小必须与 Flash datasheet 和硬件映射一致,否则烧录失败。
4.3 FlashPrg.c 定制(实现标准接口)
无需开发 FlexSPI 操作,直接调用 SDK 的
flexspi_nor_flash_ops.c函数,实现 Keil 要求的 5 个核心接口:#include "FlashOS.H"
#include "fsl_flexspi.h"
#include "flexspi_nor_flash_ops.h"
#define FLEXSPI_BASE FLEXSPI1 // 对应硬件FlexSPI1
#define FLASH_BASE_ADR 0x30000000 // AHB映射基地址
// 1. 初始化FlexSPI和Flash
int Init(unsigned long adr, unsigned long clk, unsigned long fnc) {
(void)adr; (void)clk; (void)fnc;
flexspi_nor_flash_init(FLEXSPI_BASE); // 复用SDK初始化函数
return 0;
}
// 2. 反初始化(无需操作,返回0即可)
int UnInit(unsigned long fnc) {
return 0;
}
// 3. 整片擦除
int EraseChip(void) {
return flexspi_nor_erase_chip(FLEXSPI_BASE); // SDK函数
}
// 4. 扇区擦除(adr为Keil传入的AHB地址,需转换为Flash偏移)
int EraseSector(unsigned long adr) {
return flexspi_nor_flash_erase_sector(FLEXSPI_BASE, adr - FLASH_BASE_ADR);
}
// 5. 页编程(将buf数据写入adr地址)
int ProgramPage(unsigned long adr, unsigned long sz, unsigned char *buf) {
return flexspi_nor_flash_page_program(FLEXSPI_BASE, adr - FLASH_BASE_ADR, (uint32_t*)buf);
}
- 核心技巧:Keil 传入的是 AHB 映射地址,需减去
FLASH_BASE_ADR转换为 Flash 内部偏移,否则地址错乱。
4.4 SDK 集成要点
- 从 NXP SDK 中复制
flexspi_nor_flash_ops.c和对应的头文件(flexspi_nor_flash_ops.h)到工程目录; - 工程中添加这两个文件,确保编译时能链接到
flexspi_nor_flash_init等函数; - 若更换其他 Flash(如 W25Q128JVSIQ),只需修改
flexspi_nor_flash_ops.c中的 LUT(查找表),无需改动下载算法框架。
4.5 编译生成.FLM 算法文件
- 工程选项→「Output」→确认输出文件名(如 “RT1170_W25Q512N.axf”);
- 「User」选项卡→「After Build/Rebuild」添加命令:
cmd.exe /C copy "Objects%L" ".RT1170_W25Q512N.FLM" - 点击编译,成功后会在工程目录生成
RT1170_W25Q512N.FLM文件; - 将.FLM 文件复制到 Keil 安装目录:
Keil_v5→ARM→Flash。
5. 验证与调试
- 打开 RT1170 的 Keil 工程(如 LED 闪烁例程),配置 FlexSPI NOR Flash 模式;
- 工程选项→「Debug」→「Settings」→「Download」→「Add」,选择新增的 “W25Q512NWEIQ 64MB Flash”;
- 配置 RAM 用于算法运行:起始地址
0x20000000(DTCM),大小0x8000(32KB); - 点击「Load」烧录程序,Keil 会显示 “Erase Done→Programming Done→Verify OK”,验证成功;
- 启动调试,可正常设置断点、单步运行,说明算法生效。
6. 关键注意事项
- 超时设置:FlashDev.c 中的编程 / 擦除超时需留足裕量(如 W25Q512N 页编程典型 3ms,设为 100ms),避免 Keil 误判失败;
- LUT 适配:更换 Flash 型号时,核心是修改
flexspi_nor_flash_ops.c的 LUT,确保 FlexSPI 时序匹配; - 地址映射:AHB 映射地址必须与硬件配置一致(RT1170 FlexSPI1 默认 0x30000000);
- 工程独立:下载算法工程需单独构建,仅生成.FLM 文件,不参与应用程序编译。
RT1170 Keil 自定义下载算法的核心是 “模板 + SDK 复用”:FlashDev.c 描述硬件属性,FlashPrg.c 实现标准接口,SDK 提供 FlexSPI 底层驱动,三步即可生成专属算法。该方案不仅适配 W25Q512N,更换其他 FlexSPI NOR Flash 时,仅需修改 Flash 属性和 LUT,通用性极强。
阅读全文
211