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) |
写入流程略微复杂:
- 写使能
- 扇区擦除
- 等
BUSY=0 - 写使能
- 页编程
0x02 + 地址 + 数据(1~256 字节) - 等
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 配置错误、中断未使能等。因此驱动开发一定要增加超时时间,作为系统兜底,避免永久卡死并方便异常处理。