W25Q64扇区为4KB(16页×256字节),页为写入最小单位(256字节),擦除最小单位是扇区,且写入前必须确保目标页所在扇区已擦除(全0xFF),否则只能将1→0而无法改写0→1。

W25Q64 的扇区和页结构必须先搞清
W25Q64 是 8MB(64Mbit)SPI Flash,地址空间为 0x000000–0x7FFFFF。它不支持字节级擦除或写入,必须按固定单位操作:扇区(Sector)擦除最小单位是 4KB,对应地址对齐到 0x1000;页(Page)写入最大单位是 256 字节,且写入前该页所在扇区必须已擦除(否则写入失败或数据错乱)。常见错误是直接对未擦除区域调用 page_program,结果读出来全是 0xFF 或部分位写不进去。
擦除一个扇区:发命令 + 地址 + 等待就绪
擦除流程分三步:发送 0x20(Sector Erase)命令,再发 3 字节地址(高位在前),最后轮询 read_status_register 直到 WIP(Write In Progress)位清零。注意地址必须是扇区首地址,比如擦除第 5 个扇区(编号从 0 开始)要传 0x00004000,而不是 0x000045A0——后者会擦错位置甚至触发保护异常。
- 确保 SPI 模式为 Mode 0(CPOL=0, CPHA=0),W25Q64 不兼容 Mode 3
- 擦除前检查
SRWD和BP位,若写保护使能(SR[2:0] != 0),需先发write_enable(0x06)命令 - 典型擦除耗时约 250ms,别用固定延时,必须轮询状态寄存器
往一页写入数据:对齐、分段、禁止跨页
页写入命令是 0x02,一次最多送 256 字节,且起始地址 addr % 256 必须为 0。例如想写入 0x12345 处的 10 字节,得先算出页首地址 0x12340,然后读出整页(256 字节)→ 修改目标字节 → 再整页写回。否则超出页边界的数据会被截断或触发写失败(状态寄存器 WEL 位可能仍为 1)。
- 每次写入前必须确认该页所属扇区已擦除,否则写入字节会保持原值(NOR Flash 特性:只能将 1→0,擦除才把 0→1)
- 不能连续发多个
0x02命令而不等就绪;每页写完都要轮询WIP清零(典型耗时 0.8ms) - 如果用 HAL_SPI_TransmitReceive,确保发送命令+地址+数据一气呵成,中间不能有 CS 抬升
实际驱动中容易漏掉的关键检查点
很多裸机驱动跑通单次读写就以为 OK,但长期运行后出现数据错乱,往往卡在这些地方:
立即学习“C++免费学习笔记(深入)”;
-
write_enable命令不是“设一次永久有效”——每次擦/写前都必须重发,因为 WEL 位在操作完成后自动清零 - 地址线高位(A23–A16)由 SPI 传输的第三字节提供,若 MCU 的 SPI 数据帧长度设为 8bit 但没处理好字节序,会导致地址偏移
- W25Q64 支持 Quad SPI,但默认是 Standard SPI;若误启 Quad 模式又没配对应 IO,通信会静默失败(无错误中断,只返回全 0xFF)
- 上电后默认处于深度掉电模式(
0xB9),首次使用前必须发release_from_deep_powerdown(0xAB)并等待 20μs
扇区擦除和页写入本身逻辑简单,难的是状态同步和边界校验。特别是多任务环境下,没加互斥锁导致两个线程同时对同一扇区发擦除命令,后果不可逆。


















