SPI NOR Flash硬件和指令

NOR Flash硬件

前提说明:本笔记以 SPI NOR Flash(Winbond W25Q64)为例,适用于 NOR 常见指令与擦写模型(如页编程、扇区擦除)。 若实际项目使用的是 SPI NAND,其页/块结构、读写流程、状态位含义及坏块/ECC 处理与 NOR 不同,不能直接套用本文细节。

物理特性

NOR Flash 的核心约束是“先擦后写”:

  • 覆写数据前必须先擦除
  • 擦除后的比特位恢复为 0xFF
  • 擦除耗时通常明显高于写入

存储层次结构

  • 页(Page):256 字节,最小写入单位
  • 扇区(Sector):通常 4KB(16 页),最小擦除单位
  • 块(Block):32KB 或 64KB,可擦除单位
  • 整片(Chip):支持全片擦除

大多数 SPI NOR Flash 都是这种层次。不同型号的差异通常体现在页大小、扇区/块组织和命令集细节;“256 字节”通常对应的是页而不是扇区。

状态寄存器

  • BUSY = 1:正在执行擦除/写入
  • BUSY = 0:操作完成,可进行下一步

用法:每次擦除、写入后,都要轮询状态寄存器,等待 BUSY = 0

  • WEL = 1:写使能已设置,可写入
  • WEL = 0:写使能未设置,不可写入

用法:每次擦除/写操作前都必须先让 WEL = 1

常用命令

操作命令/流程
读数据0x03 + 地址 -> 读数据
读状态寄存器0x05 -> 状态
写使能0x06(每次擦除/写后 WEL 自动清零,下次前需重新写使能)
扇区擦除(4KB)写使能 + 0x20 + 地址
块擦除(32KB)写使能 + 0x52 + 地址
块擦除(64KB)写使能 + 0xD8 + 地址
全片擦除写使能 + 0xC7(或 0x60

写入流程略微复杂:

  1. 写使能
  2. 扇区擦除
  3. BUSY=0
  4. 写使能
  5. 页编程 0x02 + 地址 + 数据(1~256 字节)
  6. BUSY=0

页编程最多写入 256 字节。若写到页末尾后继续送数据,地址会在当前页内回绕到页起始位置,覆盖已有数据;单次页编程不能跨页。

为什么叫“页编程”

这是翻译带来的直觉偏差。英文是 Page Program,其中 Program 在这里是“写入/烧写”含义,不是“写程序”。 所以“页写入”更直观,但行业里约定俗成叫“页编程”。

关于擦除

如果某个页自上次擦除后还没被写过,可以不重复擦除。比如刚完成全片擦除,或已擦除扇区但仅写入了该扇区中的其他页。

要点是:擦除最小单位是扇区,写入最小单位是页。擦除扇区会同时清掉这个扇区内其他页的数据,必要时应先备份再回写。

地址回绕

例子:从地址 0x10F0 写入 20 字节。

页边界(每 256 字节一页):

页0:0x0000 ~ 0x00FF
页1:0x0100 ~ 0x01FF

按地址直觉,你可能以为会这样:

0x10F0 ~ 0x10FF -> 写16字节(正常)
0x1100 ~ 0x1103 -> 写4字节(下一页开头)

但页编程实际会在当前页内回绕:

0x10F0 ~ 0x10FF -> 写16字节
地址回绕 -> 回到0x1000(本页开头)
0x1000 ~ 0x1003 -> 写4字节(覆盖页开头原数据)

但这只是现象,为什么会有这种回绕机制呢? 因为 Page Program 这条命令的本质是“在当前页连续写入”,内部地址自增只在页内有效(低 8 位递增)。 当超过该页末尾(256 字节边界)时,地址低 8 位会从 0xFF -> 0x00,高位不变,于是回到同一页开头继续写,造成覆盖。

需要注意的超时

虽然 Flash 硬件操作理论上一定会完成,但在实际工程里,软件可能永远等不到这个信号。 可能原因包括 SPI 配置错误、中断未使能等。因此驱动开发一定要增加超时时间,作为系统兜底,避免永久卡死并方便异常处理。