十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

国产SPI NOR Flash替代实战:SM25QH128与JFM25F32A选型与驱动要点

国产SPI NOR Flash替代实战:SM25QH128与JFM25F32A选型与驱动要点 简介面向嵌入式开发者的Flash芯片操作笔记聚焦国微SM25QH128与复旦微JFM25F32A两款常用存储芯片适用于STM32、ARM单片机及FPGA存储控制场景。资源系统梳理了SPI接口下的读写时序、擦除机制、状态寄存器WEL/WIP判断方法完整给出复位、写使能、页编程、扇区擦除、块擦除、全芯片擦除等指令码列表并详细展示JFM25F32A读写操作流程图与状态机状态定义IDLE、写使能、读状态、擦除、页编程、读数据等。在Verilog实现部分重点讲解“状态机线性序列机”的设计思想通过计数器与多if并行结构控制各状态细节并附有实际编程例子与时序图可帮助开发者深入理解FPGA下SPI Flash驱动的编写方法。此外还总结了编程注意事项包括擦除后写入、命令执行时间参数、WEL/WIP轮询、异常处理等并给出硬件选型建议。资源包共1个文件类型为PDF大小607KB内容精炼、图文结合便于随时查阅。已有3464人学习/下载适合正在调试Flash驱动或设计存储控制逻辑的工程师参考。 做嵌入式开发这几年手里过过不少Flash芯片但真正让我觉得有必要单独写一篇笔记的还是这两颗国产器件国微的SM25QH128和复旦微的JFM25F32A。一个是16MB的大容量SPI NOR Flash一个是4MB的小容量SPI NOR Flash恰好覆盖了我最近两个项目的存储需求。放在一起用下来发现虽然它们都兼容市面上主流的SPI NOR Flash操作方式但在具体应用时还是有相当多的细节需要注意。这篇笔记我就把选型思路、硬件设计、驱动要点、烧录配置到问题排查完整梳理一遍给正在评估这两款芯片或者已经踩坑的同行一个参考。在展开之前先说一下这两颗芯片的基本定位。SM25QH128是国微电子推出的128Mbit串行NOR Flash容量达到16MB适合存代码映像、字库、文件系统这类大块数据JFM25F32A是复旦微电子的32Mbit串行NOR Flash容量4MB更适合存启动代码、配置参数、日志记录这类中小规模数据。它们都是标准的SPI接口器件支持Single/Dual/Quad SPI模式直接对标市面上常见的Winbond、GD、MXIC等品牌的同类产品。我这次把它们放在一起做对比测试是因为当前不少项目都在做器件的国产化替换评估这两颗芯片能否无缝替代原有方案对很多工程师来说都是刚需。1. 选型思路与整体设计拆解1.1 为什么需要SPI NOR Flash而不是别的方式嵌入式系统里存代码和数据的方案无非就那么几类MCU内置Flash、外挂SPI NOR Flash、外挂SPI NAND Flash、eMMC、SD卡。NAND和NOR的差异相信大家都有概念NOR读取快、可靠性高、支持随机寻址、可以直接映射执行代码缺点是容量做不大、成本相对高NAND容量大、成本低但坏块管理复杂、需要纠错算法、只能块操作不适合直接运行代码。所以当项目需要一颗“能跑代码、能存参数、出问题好排查”的芯片时SPI NOR Flash永远是优先级最高的选择。SM25QH128和JFM25F32A正好覆盖了两个典型场景前者用来给FPGA存配置文件后者给MCU存Bootloader和运行日志。选它们而不是继续用进口品牌主要看中三点供货稳定、价格可控、国产器件在指令集上对标的成熟方案兼容性做得不错。1.2 两款芯片的硬件参数对照为了便于对比我直接放一张整理后的参数表这些数据来自数据手册和实际测量做选型评估时可以快速参考。参数项国微SM25QH128复旦微JFM25F32A说明容量128Mbit16MB32Mbit4MB对应不同存储需求接口SPI/Dual SPI/Quad SPISPI/Dual SPI/Quad SPI均支持最高四线读取供电电压2.7V~3.6V2.7V~3.6V典型3.3V系统直连页大小256字节256字节页编程单位一致扇区大小4KB4KB擦除最小单位块大小64KB64KB大块擦除时使用最高时钟133MHz普通读104MHz普通读Quad模式下实际吞吐有差异ID读取支持JEDEC RDID支持JEDEC RDID用于驱动识别和型号校验从表格可以看出这两颗芯片在命令接口和存储结构上高度接近。这意味着什么呢意味着底层驱动如果用标准SPI NOR Flash命令集编写那么迁移成本非常低大部分代码可以复用。我在做驱动移植的时候基本只需要修改读ID的校验逻辑和容量相关的宏定义状态机、命令序列、擦写流程完全不用动。2. 硬件设计与PCB布局要点2.1 引脚定义与最小电路搭建SPI NOR Flash的引脚复用程度比较高SM25QH128和JFM25F32A的引脚定义基本一致CS、CLK、DIIO0、DOIO1、WPIO2、HOLDIO3、VCC、GND。在Quad模式下WP和HOLD就切换为数据引脚使用所以硬件设计时必须把它们引出来不能直接接地或拉高否则后面想要用Quad模式读取时会发现IO2和IO3不可控。这里我要特别强调一下WP引脚的处理。很多开发板的Flash设计为了省事会把WP直接接地这在普通SPI模式下问题不大因为不用四线模式时这个引脚确实不参与数据传输。但如果你的项目要用Quad SPI或者需要配置状态寄存器里的非易失位WP接地就会导致引脚失效芯片可能无法正确进入QPI模式甚至某些状态寄存器位无法修改。正确的做法是通过10k电阻上拉到VCC需要时再通过GPIO控制拉低。2.2 供电、去耦与信号完整性这两颗芯片对供电要求不算苛刻3.3V系统可以直接使用但去耦电容不能省。我在原理图上习惯放一个100nF陶瓷电容贴近VCC引脚同时在PCB板上再放一个4.7uF钽电容做低频去耦这样在连续擦写时电压波动会小很多。实测下来如果去耦电容离Flash太远或者在擦除峰值电流时电压跌落超过0.3V偶发就会出现擦除失败、状态寄存器读回异常的问题。另外一个容易忽视的地方是SPI时钟线的信号完整性。当SPI时钟超过50MHz时CLK和DI/DO之间的走线长度差、过孔数量都会影响时序裕量。我之前在四层板上做过一个验证CLK走线长了1.5cmQuad读模式下读取数据偶发出错降频到80MHz就稳定了。所以如果设计目标是想让Flash跑在最高频率布局时尽量让主控到Flash的走线等长、短直过孔不超过两个。3. 驱动代码与关键操作细节3.1 标准命令集与读ID校验SM25QH128和JFM25F32A都兼容标准的JEDEC命令集最常用的是以下几个命令0x9FRDID读取ID、0x06写使能、0x04写禁用、0x03普通读、0x0B快速读、0x204KB扇区擦除、0x5232KB块擦除、0xD864KB块擦除、0x02页编程、0x05读状态寄存器1、0x01写状态寄存器1。驱动初始化的第一步永远是读ID这个习惯一定要养成。通过读ID确认芯片型号、容量再决定后续操作流程可以避免因为芯片替换导致驱动流程错误。实际代码里我会这样处理uint8_t flash_read_id(void) { uint8_t id[3] {0}; flash_cs_low(); spi_transfer_byte(0x9F); id[0] spi_transfer_byte(0x00); id[1] spi_transfer_byte(0x00); id[2] spi_transfer_byte(0x00); flash_cs_high(); return id; }这块重点不是代码本身而是要理解读ID的时序要求CS拉低后连续发送0x9F和三个空字节Flash会把制造商ID和设备ID依次移出。SM25QH128读出来的ID和我们预期的值对得上才行如果读出来不对先不要怀疑芯片是假的检查一下SPI模式是否配置正确。这两颗芯片支持SPI Mode 0和Mode 3但默认推荐用Mode 0也就是CPOL0、CPHA0很多初学者在这一步会把模式配错导致所有命令全部失效。3.2 状态寄存器与忙检测机制SPI NOR Flash执行擦除和编程是异步的发完命令后芯片内部慢慢操作这时候主控需要轮询状态寄存器1的Bit0BUSY位。BUSY为1表示Flash正在忙为0表示空闲。标准流程是发0x05命令读一个字节检查Bit0循环直到Bit0变成0。这里有一个需要特别注意的细节页编程和擦除时写完命令后要等一段时间再查BUSY位不需要拼命查询。因为每次查询也要占用SPI总线反而影响效率。我一般用定时器做一个1ms间隔的轮询既不会过于频繁也能及时得知操作完成。状态寄存器1还有几个位需要注意Bit1是WEL写使能锁存位每次写操作前都要发0x06置1写完状态寄存器或完成后会自动清零。Bit2是BP0、BP1、BP2三个块保护位这些位用于设置写保护区域出厂默认是全部区域可写但有可能在之前调试时被改过。如果遇到擦写失败第一件事就是读状态寄存器确认BP位是否为0、WEL位是否正常。放大视角看状态寄存器这些位的组合逻辑并不复杂但我在实际项目中确实见过因为BP位被配置成全保护导致整个Flash无法写入的案例排查过程走了不少弯路所以建议大家一定把读状态寄存器这个排查习惯建立起来。3.3 写使能和Quad模式的切坑经验每次执行页编程、扇区擦除、块擦除、写状态寄存器之前都必须先发0x06写使能命令否则操作会被Flash拒绝。这个顺序不能乱也不能偷懒。我在调试驱动时多次遇到“命令发出去了数据就是写不进去”的情况最后发现都是写使能环节出了问题。有的主控SPI速度太快0x06发完还没等Flash反应过来紧接着就发页编程命令导致Flash没收到写使能信号。解决方法是先把CS拉低发0x06再拉高确保命令完成然后再进行后续操作。Quad模式的切换也要注意。这两颗芯片默认是标准SPI模式如果要用Quad读命令0x6B或者QPI模式整个器件切换到四线模式必须先把状态寄存器2的QE位Quad Enable置1。这个位在出厂时可能是0需要手动写入。我在调用Quad读之前会先执行一个Read Status Register 2的指令0x35确认QE位状态如果为0则写1然后再发0x01写状态寄存器命令完成配置。当然QE位属于非易失性状态位写完一次之后掉电也能保持不需要每次开机都配置。4. 烧录与下载配置实操4.1 Keil J-Link外挂Flash算法MCU项目里最常见的就是通过J-Link烧录外部Flash。以STM32为例Keil MDK的Flash Download页面里默认只有内部Flash的编程算法要烧外部Flash就得先下载或者自己写一个外挂Flash的FLM算法文件。这块用成熟的Winbond或者ST自家的SPI NOR Flash算法文件如果把Flash型号改成SM25QH128或JFM25F32A关键在于算法文件里配置的容量和扇区大小必须和实际芯片一致否则烧录时算法会按错误的地址范围访问Flash轻则烧录失败重则把数据写到越界区域。实际配置时我会把SPI Flash算法加载到Keil的烧录列表里设置起始地址为0x90000000STM32外部Flash映射起始地址大小填16MB或4MB编程算法选择对应的SPI NOR Flash算法。如果烧录时报告Error: Flash Download failed - Target DLL has been cancelled先检查算法文件是否匹配、接线是否牢靠、芯片ID是否被算法识别。这个报错在Keil里特别容易混淆很多人以为是调试器连接问题其实大部分时候是Flash算法不匹配导致的。4.2 STM32CubeProgrammer的外部Flash操作STM32CubeProgrammer在1.6.0版本之后就支持外部SPI Flash编程使用起来比Keil直观一些。操作路径是选择External Flash加载器选择对应的SPI Flash型号连接后可以直接擦除、编程、校验。我在这颗复旦微JFM25F32A上测试过CubeProgrammer自带的Flash loader列表里并没有直接列出这个型号但可以通过手动指定参数的方式进行连接。需要填写的关键参数包括SPI时钟极性/相位、Flash大小、页面大小、扇区大小、读命令等。把JFM25F32A的256字节页大小、4KB扇区大小填好之后烧录验证都正常通过。这也侧面说明复旦微这颗芯片和标准的SPI NOR Flash协议兼容性做得不错。4.3 FPGA配置Flash的写入FPGA项目中SM25QH128这类大容量Flash通常用来存储配置文件。以Xilinx 7系列为例Vivado的硬核SPI配置接口可以直接操作外部Flash但默认支持的Flash列表里可能没有这颗国微芯片。遇到这种情况有两个处理办法一是选择兼容的同类配置比如按照同容量的标准SPI NOR Flash进行配置多数情况下能正常工作二是通过Vivado的配置工具手动添加Flash型号参数包括ID、容量、页大小等。我测试时发现Xilinx的配置IP在读取Flash ID时如果发现ID不匹配会报错并拒绝操作。这种情况下只要确保配置数据里写入的Flash ID字段与实际芯片一致即可。具体做法是在生成配置时选择User Defined Flash手动填入SM25QH128的ID信息。一次填好之后后续下载bitstream到Flash和从Flash启动都稳定不需要再做额外适配。这里多提一句FPGA配置模式里SPI x1和SPI x4的引脚复用不一样需要根据原理图实际接法选择否则配置文件写进去了也启动不了。5. 常见问题与排查技巧实录5.1 Flash ID读不出来或读错这是我遇到最多的问题也是最让人头大的问题。一开始就发现ID不对先排查硬件接线和SPI模式这一步可以排除80%的问题。检查CS、CLK、DI、DO是否接反确认SPI模式是Mode 0极性相位都对用示波器看CLK和MOSI/MISO信号是否正常。软件方面确认读ID命令0x9F后的三个空字节是否完整发送不少芯片对连续时钟数很敏感少一个时钟就少返回一个字节。还有一个容易忽略的坑芯片进入深度掉电模式后所有命令都会被忽略必须发送0xAB释放掉电命令才能唤醒。如果在调试时程序中途异常退出Flash可能停留在深度掉电状态表现为读ID全0或全FF。这时候手动发送一次0xAB然后用0x9F重新读ID大概率就恢复正常了。5.2 擦除时间异常长或者擦除后数据不为全FF正常擦除一个4KB扇区这两颗芯片的典型时间都在几十毫秒量级64KB块擦除也基本在100~300毫秒。如果发现擦除时间长达数秒甚至超时先怀疑电压不稳、SPI时钟太低或者芯片处于异常状态。电压问题的排查方法是示波器看VCC在擦除期间是否有明显跌落。擦除结束但数据读回来不为全FF这种情况就严重一些。常见原因是擦除范围不对比如软件要求擦除4KB扇区但实际擦除的是32KB块导致校验时发现邻近区域的数据被抹掉或者擦除命令被中断Flash进入了半擦除状态。解决办法是严格按照扇区边界计算擦除地址不要越界操作。坏块问题在NOR Flash里概率极低但存在如果反复擦除同一块区域后数据异常考虑换一个区域验证。5.3 烧录中途报错Target DLL has been cancelled这个报错前面提到过Keil用户特别容易遇到。除了算法匹配问题还有一种情况是调试器连接本身不稳定。我的经验是先用J-Link Commander尝试连接目标板确认能识别到MCU再用简单的脚本去读外部Flash ID如果能读通说明硬件链路没问题问题就出在FLM算法与芯片匹配上。另外有一种比较隐蔽的情况外部Flash的CS引脚被复用为其他功能比如接了一颗LCD的片选或者被GPIO配置成了别的模式导致烧录时CS信号被拉死。排查时用示波器抓取CS信号确认在烧录期间有正常的低电平脉冲。这一步基本能定位所有“目标DLL被取消”的硬件层面问题。5.4 写保护导致的操作失败务必要保持写保护的检查顺序。操作系统上电、驱动初始化之后读一次状态寄存器1和2打印或记录BP位和QE位的状态。这样可以快速确认是否处于全保护模式。JFM25F32A出厂时默认是未保护状态但我在一次测试中发现读取到的BP位全为1后来才想起是之前调试写状态寄存器时数据填错了。遇到这种情况不需要慌发0x06写使能然后写0x00到状态寄存器1即可解除保护。QE位如果需要置位就重新写入通过0x01命令一次性完成状态寄存器1和2的配置。注意SPI NOR Flash的写保护配置属于非易失性操作即使掉电后也会保持。因此在解除保护并完成测试后一定要把状态寄存器恢复到出厂默认值避免后续产品量产时写入异常。6. 个人使用体验与几条建议最后聊一下用下来的整体感受。国产SPI NOR Flash这两年的进步确实明显SM25QH128和JFM25F32A在指令兼容性、时序稳定性上已经能做到和主流进口品牌互换使用对于大多数嵌入式应用来说性能和可靠性都够用。我个人的体会是用这类新器件之前一定要先做三层验证第一层是基础读写确认正常读写、擦除没问题第二层是边界测试包括跨扇区读写、连续擦写压力测试、高低温和电压拉偏第三层是应用场景模拟比如模拟意外掉电、上电瞬间反复复位确保Flash内容不会在异常情况下被破坏。完成这三层验证后续量产才踏实。还有一个小建议两颗芯片虽然协议接近但建议在驱动中通过读ID区分型号并把ID作为配置项管理。这样以后如果同项目里换来换去驱动只需改配置表不用动代码。我目前的做法是建立一个Flash设备描述表包含厂商ID、设备ID、容量、页大小、扇区大小、命令集版本等字段这样以后不管接什么Flash只要ID匹配驱动就能自动适配。省心得多。本文还有配套的精品资源点击获取
返回列表