W25Q64需配置为SPI Mode 0(CPOL=0, CPHA=0),上电后必须先发0xAB唤醒并等待WIP=0,每次写操作前须发0x06使能写,页编程限256字节且不可跨页,扇区擦除最小单位为4KB。

W25Q64 的 SPI 模式和引脚连接必须匹配
W25Q64 是 Mode 0(CPOL=0, CPHA=0)设备,即空闲时 SCK 为低电平,数据在 SCK 上升沿采样。单片机的 SPI 外设必须配置为相同模式,否则读出全 0 或乱码是常态。
典型接线(以 STM32F103 为例):
-
CS→ GPIO(需软件控制,不能依赖硬件 NSS,因 W25Q64 不支持多从机自动片选) -
CLK→ SPIx_SCK -
DI(MOSI)→ SPIx_MOSI -
DO(MISO)→ SPIx_MISO -
WP#和HOLD#建议上拉到 VCC(不用于写保护或挂起时可固定高电平)
注意:部分国产单片机(如 GD32)SPI 默认可能为 Mode 3,未改模式就通信会失败;用逻辑分析仪抓波形时,重点看 SCK 空闲态和采样沿是否对得上。
初始化前必须发送 Release Power-Down 并确认状态
上电后 W25Q64 默认进入深度掉电模式(0xB9),此时所有指令(包括读 ID、读状态)都无响应。必须先发 0xAB 命令唤醒,再读状态寄存器确认 BUSY 位清零。
常见错误现象:调用 read_id() 返回 0xFFFFFF 或全 0 —— 很大概率是没唤醒或 CS 未正确拉低。
- 发送
0xAB后需延时 ≥ 3μs(查 datasheet 第 13 页),再读状态寄存器0x05 - 状态寄存器第 0 位(
WIP)为 0 才表示就绪;若为 1,说明芯片仍在忙(比如刚复位完内部初始化未完成) - 建议封装一个
wait_ready()函数,循环读0x05直到返回值 & 0x01 == 0
读写扇区前必须先发送 Write Enable 指令
W25Q64 写操作(擦除、编程)默认被禁止,每次写前必须发 0x06 设置状态寄存器的 WEL 位,否则 0x20(扇区擦除)、0x02(页编程)会静默失败 —— 芯片不报错,但后续读数据不变。
关键细节:
-
WEL位在每个写操作后自动清零(非仅一次使能永久有效),所以擦完一个扇区、写下一个页前都要重新发0x06 - 发
0x06后无需等待,但之后第一次读状态寄存器应看到WEL= 1(即返回值 & 0x02 != 0) - 如果发了
0x06却读不到WEL,检查是否 CS 释放过早(必须保持 CS 低电平完成整个指令周期)
示例片段(伪代码):
spi_cs_low();
spi_write_byte(0x06); // Write Enable
spi_cs_high();
<p>spi_cs_low();
spi_write_byte(0x05); // Read Status Register
uint8_t sr = spi_read_byte();
spi_cs_high();
if ((sr & 0x02) == 0) { /<em> error: WEL not set </em>/ }</p>
页编程不能跨页边界,且每页最多 256 字节
W25Q64 的“页”是 256 字节物理单元,0x02 指令只允许在单页内顺序写入(地址低 8 位决定页内偏移),跨页(如地址 0x00FF → 0x0100)会导致后半部分写入失败,但不会报错。
实际使用中容易忽略的点:
- 写入长度 > 256 字节时,必须按页切分:计算起始地址所在页(
addr & ~0xFF),写满一页再发下一条0x02 - 每次
0x02前仍需确保WEL已置位,且目标页未被擦除(未擦直接写无效) - 页编程本身不校验写入结果,建议写完立刻读回比对,尤其在干扰强的工业环境中
真正麻烦的是擦除粒度远大于写入:扇区擦除(0x20)最小单位是 4KB,而你可能只改几个字节 —— 这意味着必须读出整扇区 → 修改内存副本 → 擦除扇区 → 全页写回。别跳过这步,否则旧数据残留。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











