4. SPI Flash 指令集:标准指令集与厂商特定指令
SPI Flash 的指令集是驱动开发的核心操作手册。本章将系统梳理标准指令集(READ、WRITE、ERASE)、厂商特定指令以及指令时序图的解析方法。掌握这些指令的编码、参数和时序约束,是编写高效、稳定驱动的基础。
4.1 标准指令集概览
标准指令集由 JEDEC 定义,是所有 SPI Flash 芯片必须支持的基础操作。下表列出了最常用的标准指令及其功能描述:
| 指令名称 | 指令码 (8-bit) | 功能描述 | 地址字节数 | 数据字节数 |
|---|---|---|---|---|
| READ | 0x03 | 读取数据(标准速度,最高 50 MHz) | 3 | 1~N |
| FAST_READ | 0x0B | 快速读取(含 dummy 周期,支持更高频率) | 3 | 1~N |
| PAGE_PROGRAM | 0x02 | 页编程(写入数据到页缓冲区) | 3 | 1~256 |
| SECTOR_ERASE | 0x20 | 扇区擦除(4 KB 扇区) | 3 | 0 |
| BLOCK_ERASE_64K | 0xD8 | 块擦除(64 KB 块) | 3 | 0 |
| CHIP_ERASE | 0xC7 | 全片擦除 | 0 | 0 |
| WRITE_ENABLE | 0x06 | 写使能(执行写/擦除前必须发送) | 0 | 0 |
| READ_STATUS_REG | 0x05 | 读取状态寄存器(检查 BUSY 位) | 0 | 1 |
关键提示: 所有写操作(PAGE_PROGRAM、ERASE)之前,必须发送
WRITE_ENABLE (0x06) 指令。否则 Flash 会忽略后续操作。这是 SPI Flash 防止误写的硬件保护机制。
4.2 指令时序图解析
理解时序图是驱动开发的基本功。SPI 时序图以 CS(片选)、SCLK(时钟)、SI(数据输入)、SO(数据输出)四根信号线展示指令的完整执行过程。下面以 PAGE_PROGRAM 指令为例进行解析。
时序要点:
- CS 拉低 启动操作,在整个指令、地址、数据发送期间必须保持低电平。
- 指令码(如 0x02)在 SCLK 上升沿被 Flash 采样,高位在前 (MSB first)。
- 24-bit 地址 紧随指令码,指定写入的起始地址。
- 数据字节 连续发送,最多 256 字节(一页)。超过页边界会自动回绕到页首。
- CS 拉高 后,Flash 开始内部编程(tPP 时间),此时 BUSY 位置 1。
4.3 扇区擦除与块擦除指令
擦除操作是 SPI Flash 写入前必须执行的步骤。Flash 只能将 1 写为 0,擦除操作将整个扇区/块恢复为全 1 (0xFF)。
| 擦除类型 | 指令码 | 擦除大小 | 典型时间 (tSE/tBE/tCE) | 适用场景 |
|---|---|---|---|---|
| SECTOR_ERASE | 0x20 | 4 KB | 30~400 ms | 小范围数据更新,如配置参数存储 |
| BLOCK_ERASE_32K | 0x52 | 32 KB | 120~1600 ms | 中等数据块更新,如日志文件 |
| BLOCK_ERASE_64K | 0xD8 | 64 KB | 250~3200 ms | 大块数据更新,如固件升级 |
| CHIP_ERASE | 0xC7 | 整片 | 2~20 s | 出厂初始化或全片擦除 |
避坑指南: 擦除操作不可中断。如果在擦除过程中掉电或复位,扇区数据可能处于部分擦除状态(非全 1 也非原数据)。建议在擦除前备份关键数据,或使用双备份策略。
4.4 厂商特定指令
除了标准指令,各厂商会扩展私有指令以实现差异化功能。下表对比了主流厂商的特定指令:
| 厂商 | 特定指令 | 指令码 | 功能描述 |
|---|---|---|---|
| Winbond | READ_UNIQUE_ID | 0x4B | 读取 64-bit 唯一芯片 ID,用于防伪或绑定 |
| Winbond | READ_SFDP | 0x5A | 读取串行 Flash 可发现参数(容量、时序等) |
| Macronix | 4READ | 0x13 | 4 字节地址模式读取(支持 >16MB 容量) |
| Macronix | DEEP_POWER_DOWN | 0xB9 | 进入深度休眠模式(功耗降至 1 µA) |
| GigaDevice | READ_SECURITY_REG | 0x48 | 读取安全寄存器(OTP 区域) |
| ISSI | BURST_READ | 0x0C | 连续突发读取(无需重复发送地址) |
开发建议: 在驱动初始化阶段,通过
READ_ID (0x9F) 指令获取厂商 ID 和设备 ID,然后根据 ID 动态加载对应的厂商特定指令表。这样可以实现一套驱动兼容多款 Flash 芯片。
4.5 指令集架构图
下图展示了 SPI Flash 指令集的完整架构,包括标准指令、厂商扩展指令以及它们与硬件模块的关系:
4.6 指令集选择策略
在实际驱动开发中,选择合适的指令集需要综合考虑以下因素:
- 兼容性优先: 优先使用标准指令(READ 0x03、PAGE_PROGRAM 0x02、SECTOR_ERASE 0x20),确保驱动在不同厂商芯片间可移植。
- 性能优化: 当需要更高读取速度时,使用 FAST_READ (0x0B) 或 DUAL/QUAD READ 指令(如 0x3B、0x6B)。
- 容量适配: 对于容量超过 16 MB 的 Flash,必须使用 4 字节地址模式指令(如 Macronix 的 0x13)。
- 功耗管理: 在电池供电设备中,利用 DEEP_POWER_DOWN (0xB9) 指令降低待机功耗。
- 安全需求: 需要防伪或设备绑定时,使用 READ_UNIQUE_ID (0x4B) 获取芯片唯一标识。
最佳实践: 在驱动代码中维护一个
flash_instruction_set 结构体,包含所有指令码的映射。初始化时通过读取 JEDEC ID 自动填充该结构体,实现驱动与芯片的解耦。
/* 指令集结构体示例 */
typedef struct {
uint8_t read; /* 标准读取 */
uint8_t fast_read; /* 快速读取 */
uint8_t page_program