一W25QFV基础内容
1.SPI通信基础知识
SPI(Serial Peripheral Interface)是同步串行外设接口,它就像一个“全双工”的传送带,单片机和 Flash 之间可以同时收发数据。
四根线逻辑:
SCK (Serial Clock):时钟线,由主机(CW32)提供,决定传输节奏。
MOSI (Master Out Slave In):主机输出,从机输入。数据从 CW32 流向 W25Q。
MISO (Master In Slave Out):主机输入,从机输出。数据从 W25Q 流回 CW32。
CS/NSS (Chip Select):片选信号,低电平有效。它是整个通信的“开关”,必须先拉低才能通话。
通信模式:W25Q 系列通常支持 Mode 0 和 Mode 3。 咱们在 CW32 中配置的是 SPI_CPOL_High 和 SPI_CPHA_2Edge(Mode 3),确保在 48MHz 高频下数据采样依然稳定。
W25Q64 存储架构(必须理解)
很多人分不清扇区和块,导致擦除时误删数据。记住这个公式:
1 Page (页) = 256 字节:写入的基本单位。
1 Sector (扇区) = 16 页 = 4KB:擦除的最小单位。
1 Block (块) = 16 扇区 = 64KB:大面积清空的单位。
总容量:128 个块 = 8MB。
核心规则:Flash 的物理特性是“只能把 1 变成 0”。因此,写入新数据前必须先擦除(变为全
0xFF)。
二硬件连接与引脚分配
SPI2 接口分配
在 CW32F030 中,我们选择了 SPI2 避开 PAN3031 无线模块的 SPI1。
PB12 (CS):软件控制片选。
PB10 (SCK):时钟。
PB14 (MISO):数据接收。
PB15 (MOSI):数据发送。
注意事项
供电:严禁接 5V,必须接 3.3V。
保护引脚:若模块上有 WP 或 HOLD,必须接 3.3V,否则无法擦写。
三硬内部闪存结构
1.W25Q64FV 串行闪存(Serial Flash)的内部架构框图(Block Diagram)
2.存储层级结构(右侧部分:仓库的组织)
这部分的图表展示了 W25Q64 的“仓库”是如何划分房间的:
Block(块):整个芯片共有 128 个 Block(从 Block 0 到 Block 127),每个 Block 的容量是 64KB。
Sector(扇区):每个 Block 内部又划分为 16 个 Sector(从 Sector 0 到 Sector 15),每个 Sector 的容量是 4KB。
这就是为什么你的程序中 SPI_FLASH_SectorErase 是以 4KB 为单位擦除的,因为它对应图中左侧的小方格。
Page(页):在最底层,数据被存放在 Page 中。图中下方的 256-Byte Page Buffer 说明了每次写入(Program)操作的最大单位是 256 字节。
地址范围示例:
Sector 0 的地址范围是 000000h 到 000FFFh。
Sector 1 的地址范围是 001000h 到 001FFFh。
3.控制与逻辑(中间部分:管理办公室)
这部分展示了芯片处理你指令的“大脑”:
SPI Command & Control Logic:这是指挥中心。它接收你通过单片机发送的 03h(读)、02h(写)、06h(写使能)等指令,并将其翻译成内部操作。
Status Register(状态寄存器):这就是我们之前用来解除“写保护”的地方。它连接着 Write Control Logic,控制着芯片是否允许被擦除或写入。
High Voltage Generators:Flash 存储需要高电压来“泵”电子进入存储单元。这个模块负责产生擦除和编程所需的高压。
4.外部接口(左侧部分:大门)
这是你连接单片机的 6 根线:
/CS, CLK, DI(IO0), DO(IO1):标准的 SPI 通信引脚。
/WP (Write Protect) 和 /HOLD:硬件保护和挂起引脚。图中显示它们直接连向控制逻辑。正如我们之前讨论的,如果模块上没有这些引脚,它们通常在 PCB 内部被连到了高电平。
四芯片初始化与协议逻辑
1.上电与初始化 (Power On & Initialization)
起始点:当芯片接通电源(Power On)后,它并不能立即工作,而是先进入 设备初始化(Device Initialization) 阶段。
默认模式:初始化完成后,芯片会默认进入 标准 SPI(Standard SPI)模式。在这个模式下,它同时支持你之前提到的双线(Dual SPI)和四线(Quad SPI)指令。
2.模式切换:SPI ↔ QPI
图中的中间部分展示了如何在两种主要的通信协议之间转换:
进入 QPI (Enable QPI):通过发送指令 38h,芯片可以从 SPI 模式切换到 QPI(Quad Peripheral Interface)操作 模式。
注:QPI 模式下,指令本身也通过 4 根线发送,速度比标准 SPI 更快。
退出 QPI (Disable QPI):通过发送指令 FFh,芯片会退回到标准的 SPI 模式。
3.软件复位机制 (Reset)
图中两条回环的曲线展示了软件复位的逻辑:
复位指令串:无论是处于 SPI 还是 QPI 模式,只要连续发送 66h (Reset Enable) + 99h (Reset) 这一组指令,芯片就会强制退回到“设备初始化”状态。
意义:如果你在代码运行中发现芯片“卡死”或不响应(比如你之前遇到的 JedecID 读出全为 0xFF 的情况),可以通过这组复位指令尝试让芯片重新初始化,而无需物理断电。
4. SPI 与 QPI 操作模式 (6.1 节)
这部分定义了单片机(主机)与 Flash(从机)之间“对话”的物理方式。
标准 SPI (Standard SPI):
Mode 0:空闲时 CLK 为低电平。
Mode 3:空闲时 CLK 为高电平。
信号线:使用 CLK、/CS、DI (数据入) 和 DO (数据出) 四根线。
时序:在 CLK 上升沿写入数据,在下降沿读取数据。
模式支持:支持 Mode 0 和 Mode 3。
多线增强模式 (Dual / Quad SPI):
Dual SPI:将 DI 和 DO 变成双向引脚(IO0, IO1),速度翻倍。
Quad SPI:利用所有四根数据线(IO0-IO3),速度提升 4-6 倍。需要先设置状态寄存器中的 QE 位 才能开启。
QPI 模式:
一种极速模式,连“指令码”都通过 4 根线发送(原本需要 8 个时钟,现在只需 2 个)。通过 38h 指令切换进入。
5.硬件辅助功能 (6.1.5 节)
暂停功能 (Hold Function):
当 /CS 为低(选中状态)时,拉低 /HOLD 引脚可以暂停当前的 SPI 通信。
应用场景:如果 SPI 总线上挂了多个设备,而单片机突然需要处理更高优先级的任务,可以先“挂起”Flash,处理完后再恢复,无需重新发送指令。注意:此功能在 Quad/QPI 模式下不可用。
6.写入保护机制 (6.2 节)
这是你之前遇到“写不进去”问题的理论根源。为了防止由于噪声或意外掉电导致数据损坏,芯片设计了多层“锁”:
上电自动锁:
VCC 门限:电压低于阈值时,芯片自动复位并禁止所有操作。
启动延迟:上电后有一段延迟时间 (tPUW),期间禁止编程和擦除指令。
写使能锁 (WEL):
关键点:上电后默认是“写禁止”状态。
逻辑:在执行页编程、扇区擦除或写状态寄存器前,必须先发送 Write Enable (06h) 指令。
自动回锁:完成一次编程或擦除后,芯片会自动回到“写禁止”状态。
软件/硬件组合锁:
软件锁:通过状态寄存器中的 BP0-BP2 位,可以锁定特定区域(甚至整片区域)为只读。
硬件锁:配合 /WP 引脚。如果软件锁被激活且 /WP 为低,则状态寄存器无法被更改。
7.开发者 Tips
关于时钟:确认你的 CW32 SPI 极性配置与手册中的 Mode 0 或 Mode 3 匹配。
关于速度:虽然标准 SPI 简单,但对于 500 个节点的大数据上报,未来可以考虑开启 Dual/Quad 模式提速。
关于稳定:在重要擦写操作前,务必检查状态寄存器的 WEL 位。
关于防死机:如果通信紊乱,建议发送软件复位指令序列 (66h + 99h)。
8.W25Q64FV 状态寄存器
8.1 实时状态位:芯片在干什么?
这两位是你编写底层驱动函数(如 WaitForWriteEnd)时必须频繁读取的。
BUSY (S0 - 只读):
功能:当芯片正在执行页编程、扇区/块擦除或写状态寄存器时,该位为 1。
注意:此时芯片进入“闭关模式”,除了读取状态和暂停指令外,会忽略其他所有指令。
实战意义:在48MHz 系统中,如果两次写入操作之间不检查 BUSY 位,由于 CPU 跑得比 Flash 写入快得多,会导致数据丢失。
WEL (S1 - 只读):
功能:写使能锁存位。执行完 06h 指令后变为 1。
复位逻辑:在掉电、执行完写入/擦除指令后,该位会自动归 0。
实战意义:这解释了为什么你每写入之前都必须重新发送一次写使能指令。
8.2 存储保护位:哪些数据不准改?
这就是遇到“读 ID 正常但写不进数据”的根本原因。
BP2, BP1, BP0 (S4, S3, S2):
功能:定义 Flash 阵列中受保护(只读)的范围。默认值为 0(不保护)。
TB (S5) & SEC (S6):
TB (Top/Bottom Protect):决定从芯片的“头”开始锁,还是从“尾”开始锁。
TB = 0:从顶部(Upper)地址开始保护。
TB = 1:从底部(Lower)地址开始保护。
SEC (Sector/Block Protect):决定锁定的精度。
SEC = 0:以 64KB 的“块” 为单位进行保护。
SEC = 1:以 4KB 的“扇区” 为单位进行精细保护。
CMP (S14):
当 CMP = 0 时(默认状态):你设置的位代表“哪一小块被保护”。
例如:设置 SEC=1, TB=1, BP=001,则只有地址 000000h – 000FFFh 这 4KB 区域被锁死,其余地方都能写。
当 CMP = 1 时:逻辑完全反转,你设置的位代表“哪一小块不被保护”。
例如:同样的配置在 CMP=1 时,除了那 4KB,剩下的 8,188KB 全部变只读。这非常适合用来锁定整个数据库,只留出一个小窗口写当前配置。
8.3 系统配置与安全:高级功能
SRP0 & SRP1 (S7, S8):
功能:定义状态寄存器本身的保护方式(软件、硬件、掉电锁定或永久锁定)。
实战对照表:
SUS (Suspend Status):
功能:暂停指示灯。
状态标识:这是一个只读位。
触发条件:当你发送 75h (Erase/Program Suspend) 指令后,该位会被硬件自动置为 1。
清除条件:当你发送 7Ah (Resume) 指令,或者芯片掉电重启后,该位会归 0。
LB1-LB3 (S11-S13):
功能:安全寄存器锁定位。这是一次性编程(OTP)的。一旦锁定,对应的安全寄存器将永久变为只读。
QE (S9 - Quad Enable):
功能:开启四线 SPI/QPI 模式的“开关”。
代价:一旦开启 QE,芯片上的 WP 和 HOLD 引脚功能会被禁用,转为数据线 IO2 和 IO3。
1.SPI 线数的演变:从“单车道”到“四车道”
标准的 SPI 确实是通过 DI(数据入)和 DO(数据出)进行单位(1-bit)传输的,但 W25Q64FV 支持多种“提速”模式:
标准 SPI (Standard SPI):使用 DI 和 DO。 每次时钟周期只传 1 位数据,就像单车道。
双线 SPI (Dual SPI):将 DI 和 DO 变成 IO0 和 IO1,两根线同时传数据。 速度提升 2 到 3 倍。
四线 SPI (Quad SPI):这是最关键的突破。 它把原本用来写保护的 WP 和暂停通信的 HOLD 引脚也“征用”了,变成了 IO2 和 IO3。 这样就有 4 根线同时跑数据,速度提升 4 到 6 倍。
2.什么是“极速” QPI 模式?
QPI(Quad Peripheral Interface)是 Quad SPI 的“完全体”。
在普通 Quad SPI 模式下,你发送“指令”(比如读取数据)时,仍然得通过 IO0 这一根线慢慢发 8 个时钟周期。 但在 QPI 模式 下:
指令也要并传:连“指令码”和“地址”都是 4 根线一起发。
效率翻倍:发送 1 字节指令原本要 8 个时钟,现在只需要 2 个时钟。
适用场景:非常适合你的网关在短时间内需要从 Flash 读取大量 500 个从机节点配置的场景。
3.为什么必须手动设置 QE 位?
这就是手册里那个 QE (Quad Enable) 位的核心作用:
引脚功能切换:默认情况下,WP 是用来防止误擦除的,HOLD 是用来暂停 SPI 的。
激活四线:当你把 QE 位置 1 时,芯片内部逻辑会彻底关掉写保护和暂停功能,把这两个引脚的控制权交给数据传输引擎,变成 IO2 和 IO3。
不可逆风险:手册警告,如果你的电路板上 WP 或 HOLD 是直接接死在 GND 上的,一旦你强行开启 QE 位,会产生硬件短路冲突!
WARNING:如果你的 WP 或 HOLD 引脚直接接了地(或者没接),严禁将 QE 位置 1,否则会引发硬件冲突。
8.4 系统配置与安全:高级功能
PROTECTED BLOCK(S)(受保护的块)
它指出了被锁定的物理块编号。
物理结构:W25Q64 共有 128 个块(编号从 0 到 127),每个块的大小固定为 64KB。
含义:表格中的这一项会列出具体哪些块变成了“只读”。例如,显示 124 thru 127 表示第 124、125、126、127 这四个块被锁定了。
PROTECTED ADDRESSES(受保护的地址)
它给出了被锁定区域的十六进制地址范围。
寻址空间:W25Q64 的总地址范围是 000000h 到 7FFFFFh(总计 8MB)。
作用:它能让你在编写程序时,直观地通过地址判断某个变量存放在这里是否安全。例如,如果地址显示 7C0000h – 7FFFFFh,那么任何针对这个范围内地址的擦除或写入指令都会被芯片忽略。
PROTECTED DENSITY(受保护的容量)
它描述了被锁定区域的总存储大小。
单位:通常以 KB 或 MB 为单位。
数值:它是受保护块数量的累加值。例如,如果保护了 4 个块,受保护容量就是 4 *64KB= 256KB;如果全片保护,则显示为 8MB 或 ALL。
PROTECTED PORTION (2)(受保护的部分/比例)
它是一个描述性的标签,用来说明受保护区域在整片芯片中的位置和占比。
L (Lower):代表从芯片的底部(低地址,即 0 地址处)开始向上保护。
U (Upper):代表从芯片的顶部(高地址,即 7FFFFFh 处)开始向下保护。
比例:例如 Upper 1/32 表示芯片顶部 1/32 的容量被保护。
| BP2 | BP1 | BP0 | 受保护块范围 (Blocks) | 受保护地址范围 (Addresses) | 受保护容量 | 保护比例/备注 |
| 0 | 0 | 0 | NONE | NONE | NONE | 无保护(出厂默认) |
| 0 | 0 | 1 | 126 和 127 | 7E0000h – 7FFFFFh | 128 KB | Upper 1/64 |
| 0 | 1 | 0 | 124 到 127 | 7C0000h – 7FFFFFh | 256 KB | Upper 1/32 |
| 0 | 1 | 1 | 120 到 127 | 780000h – 7FFFFFh | 512 KB | Upper 1/16 |
| 1 | 0 | 0 | 112 到 127 | 700000h – 7FFFFFh | 1 MB | Upper 1/8 |
| 1 | 0 | 1 | 96 到 127 | 600000h – 7FFFFFh | 2 MB | Upper 1/4 |
| 1 | 1 | 0 | 64 到 127 | 400000h – 7FFFFFh | 4 MB | Upper 1/2 |
| 1 | 1 | 1 | 0 到 127 | 000000h – 7FFFFFh | 8 MB | ALL(整片锁死) |
示例1:
例如,如果你想保护最开始的 $$4text{KB$$ 扇区(存 500 个从机的配置),你需要设置:
SEC = 1 (扇区级保护)
TB = 1 (从底部地址开始)
BP[2:0] = 001
结果:地址 000000h – 000FFFh 被永久锁定,除非再次修改状态寄存器。
根据 W25Q64FV 手册的位定义图,我们要配置的是 Status Register-1。
| 位 (Bit) | 标识 | 设定值 | 功能描述 |
| S7 | SRP0 | 0 | 软件保护模式 |
| S6 | SEC | 1 | 开启扇区级保护(让保护粒度细化到 4KB) |
| S5 | TB | 1 | 保护底部 (Bottom) 区域(从地址 0 开始向上锁定) |
| S4 | BP2 | 0 | 块保护位 2 |
| S3 | BP1 | 0 | 块保护位 1 |
| S2 | BP0 | 1 | 块保护位 0(结合 SEC/TB,锁定 1 个 4KB 单元) |
| S1 | WEL | 0 | 写使能位(只读位,由硬件指令控制) |
| S0 | BUSY | 0 | 忙标志位(只读位) |
当 SRP0 = 0 (默认值):软件保护模式。 只要你发送了 Write Enable (06h) 指令,你就可以通过 SPI 指令随意修改状态寄存器(包括那些保护位 BP0-BP2)。这时候,引脚 /WP 是不起作用的。
当 SRP0 = 1:进入“准硬件保护”状态。 此时看 /WP 引脚的电平:
如果 /WP 为高电平:依然是软件保护,可以改。
如果 /WP 为低电平:硬件锁定模式。状态寄存器被“焊死”了,任何 SPI 指令都改不了它。
SRP0 就像是保险柜的“电子锁使能”。SRP0=0 时,你有密码就能开;SRP0=1 且 /WP 拉低时,相当于不仅要密码,还得插一把实体钥匙才能开。
TB = 1 (从底部 Bottom 开始保护)
保护范围: 从地址 000000h 开始向上覆盖。
适用场景: 你要把 500 个从机的配置存放在最开始的 4KB 扇区。
优势: 大多数单片机的 Bootloader 或核心配置参数习惯放在地址 0 附近。如果你把这部分锁死,程序最核心的“根”就安全了。
TB = 0 (从顶部 Top 开始保护)
保护范围: 从芯片最高地址(比如 8MB 芯片的 7FFFFFh)向下覆盖。
适用场景: 如果你把 Flash 的末尾用来存字库、固件包或者不经常变动的大型静态资源。
二进制组合:0110 0100十六进制转换:0x64
/*** @brief 锁定 Flash 底部第一个 4KB 扇区 (0x000000 - 0x000FFF)* @note 用于保护 500 个从机配置不被误操作擦除*/void FLASH_Lock_Config_Sector(void){// 1. 发送写使能指令 (06h)// 修改状态寄存器前必须先开启写使能锁存器 (WEL)SPI_FLASH_WriteEnable();// 2. 写入状态寄存器 1 (01h)// 写入计算值 0x64,对应手册表 7.1.11 中的 4KB Lower 1/2048 保护SPI_FLASH_WriteStatusReg1(0x64);// 3. 等待内部写入周期完成// 写入非易失性寄存器需要一定的硬件处理时间 (tW)SPI_FLASH_WaitForWriteEnd();printf("rn[系统] 500节点配置区 (0x0000) 已永久锁定!rn");}/*** @brief 解除全片锁定 (在需要批量更新从机名单时调用)*/void FLASH_Unlock_All(void){SPI_FLASH_WriteEnable();// 将 BP0-BP2, SEC, TB 全部清零SPI_FLASH_WriteStatusReg1(0x00);SPI_FLASH_WaitForWriteEnd();printf("rn[提醒] Flash 已进入全区读写模式。rn");}
示例2:
列举一个在网关开发中非常实用的场景:锁定最后 256KB 的区域用于存放“固件备份”或“OTA 升级包”。
在 多节点的网关中,如果远程升级失败,则必须确保 Flash 中存有一份绝对安全的“出厂固件”。
根据7.1.11 映射表,我们要实现的是保护芯片最高地址处的 4 个块。
SEC = 0:使用 64KB 块级保护。
TB = 0:从 顶部 (Upper) 开始向下锁定。
BP2=0, BP1=1, BP0=0:对应 Upper 1/32 比例(即 256KB)。
状态寄存器 1 (SR1) 位排列:
SRP0(0) | SEC(0) | TB(0) | BP2(0) | BP1(1) | BP0(0) | WEL(0) | BUSY(0)
二进制:0000 1000十六进制:0x08
/*** @brief 配置 Flash 存储区的写保护范围* @param ConfigValue: 写入状态寄存器 1 的十六进制值*/void W25Q_Set_Protection(uint8_t ConfigValue){// 1. 发送写使能指令 (06h)// 所有的擦除、编程、写状态寄存器操作前必须发此指令SPI_FLASH_WriteEnable();// 2. 写入状态寄存器 1 (01h)// 此操作会将保护配置写入非易失性存储单元SPI_FLASH_WriteStatusReg1(ConfigValue);// 3. 等待写入完成// 写入状态寄存器需要硬件处理时间 tWSPI_FLASH_WaitForWriteEnd();}/*** @brief 实战:保护水表配置区与固件备份区*/void Flash_Security_Init(void){// 场景 A:保护底部 4KB (存 500 个从机 ID)// 对应位:SEC=1, TB=1, BP=001 -> 0x64W25Q_Set_Protection(0x64);printf("Config Area (Bottom 4KB) Protected.rn");// 场景 B:保护顶部 256KB (存固件镜像)// 对应位:SEC=0, TB=0, BP=010 -> 0x08// W25Q_Set_Protection(0x08);}
注意:
WEL 位自动清零:一旦 WriteStatusReg1 指令完成,芯片会自动把 WEL 位清零。这意味着下一次想修改保护范围,必须再次调用 WriteEnable()。
写指令被忽略:如果你的 4G 模块代码尝试向受保护的 0x7C0000 地址写入数据,Flash 会正常接收 SPI 信号但不执行任何动作。这会导致 Buffercmp 校验失败并报错 Error 1。
寄存器锁定 (SRP0/1):如果你不小心把 SRP0 或 SRP1 设置成了硬件保护模式且 WP 接了地,那么即使在代码里发出解锁指令也无法更改保护范围了。
五W25Q64指令系统与通讯规约
5.1 身份验证:Manufacturer and Device ID
在正式读写数据前,第一步永远是“对暗号”。
核心指令:9Fh (JEDEC ID)。
识别码分析:
Manufacturer ID: EFh (代表 Winbond 华邦)。
Memory Type: 40h (代表 SPI 模式)。
Capacity: 17h (代表 64Mb 容量)。 64Mb 位容量 (Mb) 8 MB字节容量 (MB)
意义:你在调试时读出的 0xEF4017 就是由这三个字节组成的。如果读不到这个数,说明 SPI 物理链路或时钟极性(Mode)配置有误。
5.2 核心指令集 (Standard SPI Instructions)
A23-A16、A15-A8、A7-A0 组合起来就是一个完整的 24 位物理地址。
为什么是 3 个字节? 2^24 次方等于 16,777,216。这意味着用 3 个字节的地址,最大可以管理 16MB 的存储空间。
A23-A16 (Byte 2):地址的高位字节(最重要的一段门牌号)。
A15-A8 (Byte 3):地址的中间字节。
A7-A0 (Byte 4):地址的低位字节。
这就像你寄快递。Byte 1 是“寄东西”;Byte 2 是“省”;Byte 3 是“市”;Byte 4 是“区”。只有这四个字节加在一起,快递员(Flash 硬件)才知道具体要把东西送到哪。
| 维度 | 理解 | 实际底层逻辑 | 理由 |
| 指令 (Instruction) | 8 位 | 8 位 (1 Byte) | 表中 Byte 1 的固定长度。 |
| 地址 (Address) | 24 位 | 24 位 (3 Bytes) | 对应 A23-A0,决定了 16MB 的寻址空间。 |
| 数据宽度 (Data) | 16 位 | 8 位 (1 Byte) | SPI 物理上是串行的(1位),逻辑上以 8位 为一帧。 |
第一类:光杆司令(只有 Byte 1)
例子:Write Enable (06h)、Write Disable (04h)。
原因:这些是“全局开关”。比如“准许写”,它不需要指定地址,只要说一声就行。所以 Byte 2 之后全是空的。
第二类:查岗指令(Byte 1 + 寄存器数据)
例子:Read Status Register-1 (05h)。
后面跟的是 (S7-S0):这代表你发出 05h 后,Flash 会在接下来的 Byte 2 时间里回传它的状态位。
原因:你想看它的健康报告,不需要地址,直接读就行。
第三类:精准打击(Byte 1 + 3字节地址)
例子:Sector Erase (20h)、Page Program (02h)。
后面跟的是 A23...A0:
如果你说“擦除”,Flash 会问:“擦哪儿?”
所以你必须在 Byte 2、3、4 告诉它具体的 24 位地址。
Page Program (02h) 后面还有 D7-D0:那是你要写入的真实数据(Data)。
SPI_ReadWriteByte(0x02); // Byte 1: 指令 (动词:页编程)SPI_ReadWriteByte((Addr >> 16) & 0xFF); // Byte 2: 地址高 8 位 (A23-A16)SPI_ReadWriteByte((Addr >> 8) & 0xFF); // Byte 3: 地址中 8 位 (A15-A8)SPI_ReadWriteByte(Addr & 0xFF); // Byte 4: 地址低 8 位 (A7-A0)
将 Table 7.2.2 中的指令按功能分类介绍:
控制类:
06h (Write Enable): 写使能。这是所有擦除和写入操作的“开门指令”,执行后状态寄存器的 WEL 位会置 1。
01h (Write Status Register): 写状态寄存器。这就是我们用来实现“底座 4KB 永久锁定”的关键。
擦除类:
20h (Sector Erase 4KB): 以扇区为单位擦除。 你的 500 个节点配置信息通常占用一个或多个扇区。
读写类:
02h (Page Program): 页编程。一次最多写入 256 字节。
03h (Read Data): 普通读取。
5.3 指令发送的“字节流”逻辑
你需要解释手册表格中 BYTE 2 到 BYTE 6 的含义,这对写代码非常关键:
地址发送:大多数指令(如 02h, 03h, 20h)后面都紧跟三个字节的地址(A23-A16, A15-A8, A7-A0)。
Dummy Byte (哑字节):像 0Bh (Fast Read) 这种指令,中间需要一个 Dummy 字节(通常发 0xFF)给芯片内部留出反应时间。
数据流:指令和地址发完后,紧接着就是连续的数据字节流。
注意:
1. “页卷回”风险(Note 3)—— 开发者最容易掉的坑
内容:Page Program 最多支持 256 字节。如果发送超过 256 字节,地址会卷回(Wrap)到当前页的开头并覆盖之前的数据。
技术影响: 假设一次性存入 500 个水表的 ID(假设每个 ID 8 字节,共 4000 字节),你不能只发一个 02h 指令。
对策: 你必须编写一个“自动分页写入”函数。每写 256 字节,必须重新发送起始地址并检测 BUSY 位。
2. 安全寄存器的物理隔离(Note 5)
内容: 芯片额外提供了 3 个各 256 字节的 Security Registers(安全寄存器),它们有独立的地址空间(001000h、002000h、003000h)。
建议: 建议把网关的核心出厂配置(如网关唯一的通信密钥、4G 模块的授权码)存在这里,而不是主存储区。因为这里支持 OTP(一次性编程)锁定,一旦锁定,物理上无法改写,防黑客效果极佳。
3. 双线/四线模式下的“位分片”(Note 6 - 11, 14)
内容: 详细描述了在 Dual/Quad/QPI 模式下,地址位和数据位是如何分布在 IO0-IO3 上的。
关键点: 在 QPI 模式下(Note 14),指令码(C7-C0)也是通过 4 根线并传的。
对策: 如果你发现切换到 QPI 后读出的 ID 变了,多半是 SPI 控制器的字节序或位序配置与 Note 14 的时钟周期(CLK #0, 1)对不上。
| 分类 | 涉及注释 | 核心要点 |
| 数据传输 | Note 1 | 必须 MSB First(最高有效位在前)。 |
| 效率提升 | Note 2 | 读取状态寄存器或 ID 时,CS 不拉高数据会一直重复,适合做死循环查询(Polling)。 |
| 寻址限制 | Note 12, 13 | 执行 Word Read 必须 2 字节对齐(A0=0);执行 Octal Word Read 必须 16 字节对齐。 |
| 模式控制 | Note 15, 16 | QPI 模式下的“哑时钟”(Dummy Clocks)数量和“卷回长度”是可以通过参数 P7-P0 编程修改的。 |
4. 关于地址对齐(Note 12/13):
在你的水表数据结构体设计时,建议将结构体大小设置为 16 字节的倍数。这样在调用高速读取指令时,地址永远是自然对齐的,不会触发 Note 12/13 的限制。
5. 于页边界写入:
很多开发者认为 02h 指令可以从地址 0 一直写到地址 8MB,这是错误的。受 Note 3 限制,写入一旦超过页边界(256字节),数据会像“贪吃蛇撞墙”一样回到页首。在处理 比如500 个节点的数据上报时,务必在代码中加入页边界判断逻辑。
5.4 指令时序图分析
Mode 0 (CPOL=0, CPHA=0)
状态:时钟线(CLK)平时休息时是低电平。
动作:CLK 一旦从低变高(第一个边沿),单片机和 Flash 就立刻抓取数据。
特点:反应最快,效率极高。
Mode 1 (CPOL=0, CPHA=1)
状态:时钟线平时也是低电平。
动作:CLK 从低变高时,大家先“准备”一下数据;等到 CLK 从高变低(第二个边沿)时,才真正抓取数据。
特点:给了硬件半个时钟周期的缓冲时间。
Mode 2 (CPOL=1, CPHA=0)
状态:时钟线平时休息时是高电平。
动作:CLK 一旦从高变低(第一个边沿),立即抓取数据。
特点:采样发生在下降沿。
Mode 3 (CPOL=1, CPHA=1)
状态:时钟线平时也是高电平。
动作:CLK 从高变低时准备数据,等 CLK 从低变高(第二个边沿)时抓取数据。
特点:这是 W25Q64 最常用的模式之一。因为它在上升沿采样,且平时 CLK 为高,抗干扰能力较强。
W25Q64 的时序主要分为以下几类模板:
单字节模板:只有指令,没有地址和数据。如 Write Enable (06h)、Reset (99h)。
指令 + 地址模板:先发指令,再发 24 位地址。如 Sector Erase (20h)。
指令 + 地址 + 数据输出模板:发完指令和地址,Flash 开始往外吐数据。如 Read Data (03h)。
指令 + 地址 + 哑周期 + 数据输出模板:中间多了一个缓冲。如 Fast Read (0Bh)。
Write Enable (06h) 指令
左图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (CS)
图中看到 CS从高电平跳变到低电平(下降沿),这代表单片机告诉 Flash:“准备好,我要下令了”。
第二步:确认时钟 (CLK) 模式
注意图中虚线标出的 Mode 3 和 Mode 0。无论空闲时是高还是低,数据都是在 CLK 的上升沿被 Flash 采样的。
第三步:发送指令 (DI IO_0)
在 8 个时钟脉冲内,单片机在 DI 线上依次送出二进制位。
指令是 06h,换算成二进制是 0000 0110。
你看图中 DI 线的波形:前 5 位是低电平,第 6、7 位跳高,最后一位变低。这就是典型的串行发送。
第四步:忽视输出 (DO / IO_1)
你会发现 DO 线上写着 High Impedance(高阻态)。因为这是“写使能”指令,Flash 只需要听,不需要回答,所以它的输出引脚处于断开状态。
右图分析:极速 QPI 模式
这就是你之前好奇的“四线模式”。
核心区别:带宽翻了 4 倍
在左图中,发一个 06h 需要 8 个时钟周期。
在右图中,单片机同时利用 IO_0, IO_1, IO_2, IO_3 四根线发数据。
指令 06h (0000 0110) 被拆分了:第一个时钟周期传前 4 位,第二个周期传后 4 位。
结果:只需 2 个时钟周期 就发完了。对于 500 个节点频繁写入的场景,这种模式能显著降低 CPU 占用。
Read Status Registere (50h) 指令 读取状态寄存器
左图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (CS)
图中看到 CS 从高电平跳变到低电平(下降沿),这代表单片机告诉 Flash:“准备好,我要下达一条临时配置 使能指令了”。
第二步:确认时钟 (CLK) 模式
依然兼容 Mode 0 和 Mode 3。数据在 CLK 的上升沿被 Flash 稳定采样,这保证了在高频通讯下的指令准确性。
第三步:发送指令 (DI / IO_0)
在 8 个时钟脉冲内,单片机在 DI 线上依次送出二进制位。 指令是 50h,换算成二进制是 0101 0000。 观察图中 DI 线的波形:第 1 位低,第 2 位高,第 3 位低,第 4 位高,随后连续 4 位保持低电平。这种“跳变”波形就是 50h 指令的唯一特征。
第四步:忽视输出 (DO / IO_1)
DO 线上显示为 High Impedance(高阻态)。因为 50h 只是一个声明类的“使能”动作,Flash 此时只需要听指令,不会返回任何数据。
右图分析:极速 QPI 模式
这就是为了在追求极致效率的场景下设计的“并行模式”。
核心区别:位宽翻了 4 倍
在左图中,串行发送一个 50h 指令需要 8 个时钟周期。 在右图中,单片机利用 IO_0 到 IO_3 四根数据线同时发力。 指令 50h (0101 0000) 被拆分成了两个部分:第一个时钟周期并行传输高 4 位 (0101),第二个周期并行传输低 4 位 (0000)。
结果:只需 2 个时钟周期
指令传输耗时缩短到了原来的 1/4。在多任务高并发的环境下,这种节省能有效降低总线占有率,让 CPU 有更多时间处理其它业务逻辑。
50h 不会置位 WEL 位。它仅仅是为了紧随其后的 Write Status Register (01h) 指令服务,使其修改后的寄存器值在断电后自动消失(易失性)。这在需要动态调整内存保护范围、但又不希望频繁擦写硬件寄存器的应用中非常有用。
Write Status Register (01h) 指令 写状态寄存器
上图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (/CS) 图中看到 /CS 从高电平跳变到低电平(下降沿),开启通讯。注意:在执行此图操作前,你必须已经先发送过 06h(写使能)指令,否则这一整张图的操作都会被 Flash 忽略。
第二步:确认时钟 (CLK) 模式 支持 Mode 0 和 Mode 3。数据在 CLK 的上升沿 被采样。对于写寄存器这种关键操作,时序的稳定性直接决定了你的 500 个水表节点名单是否会被“锁死”。
第三步:发送指令 (DI / IO0) 在第 0 到 7 个时钟脉冲内,单片机送出二进制位 0000 0001 (01h)。这是告诉 Flash:“我要改写你的状态寄存器了”。
第四步:顺序写入寄存器数据
Status Register 1 in:在第 8 到 15 个脉冲,单片机送入 8 位数据(S7-S0)。这是你设置 BP、SEC、TB 位的地方。
Status Register 2 in:在第 16 到 23 个脉冲,紧接着送入第二个 8 位数据(S15-S8)。这是设置 QE(四线使能)或 CMP 位的地方。
关键细节:图中星号(*)标注了 MSB(最高位)在前。
第五步:忽视输出 (DO / IO1) DO 线上依然是 High Impedance(高阻态)。因为此时是单片机向 Flash “下达命令”,Flash 只负责记录,不回话。
下图分析:极速 QPI 模式
核心区别:极高的写入效率 在 SPI 模式下,改写两个寄存器总共需要 24 个时钟周期(8 指令 + 8 SR1 + 8 SR2)。 而在 QPI 模式下:
发送指令 (01h):仅需 2 个时钟(IO0-IO3 同时传位)。
写入 SR1:仅需 2 个时钟。
写入 SR2:仅需 2 个时钟。
结果:总共只需要 6 个时钟周期 就能完成配置。这对于在 FreeRTOS 任务中需要快速切换保护状态的操作来说,极大地减少了 CPU 的阻塞时间。
MSB(Most Significant Bit) 就是最高有效位。
LSB (Least Significant Bit) 翻译过来叫 最低有效位。
举例说明:发送数字 0x41 (二进制 0100 0001)
假设我们要把这个数据从单片机发给外设:
情况 A:MSB First (SPI 模式)
电线上出现的顺序是:0 -> 1 -> 0 -> 0 -> 0 -> 0 -> 0 -> 1
结果:对方收到后按原样拼好,还是 0x41。
情况 B:LSB First (某些传感器或串口)
电线上出现的顺序是:1 -> 0 -> 0 -> 0 -> 0 -> 0 -> 1 -> 0
结果:如果你用 MSB 的逻辑去读,读出来的数就变成了 1000 0010 (即 0x82)。数据彻底错了!
进阶概念:大端与小端 (Endianness)
这是教小白时最容易混淆的。MSB/LSB 关注的是一个字节内部的位顺序,而大端/小端关注的是多个字节组合时的顺序。
大端模式 (Big-Endian):高位字节存在低地址。
小端模式 (Little-Endian):低位字节存在低地址(STM32/CW32 内部通常用这个)。
Page Program (02h) 指令 页编程
上图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (CS) 图中看到 CS 从高电平跳变到低电平(下降沿),开启一次写入会话。 注意:在执行此操作前,必须先发送过 06h (写使能),否则写入无效。
第二步:确认时钟 (CLK) 模式 支持 Mode 0 和 Mode 3。数据在 CLK 的上升沿 被采样。对于大数据量(256 字节)写入,稳定的时钟边沿是防止数据位偏移的关键。
第三步:发送指令与地址 (DI / IO0)
在第 0 到 7 个时钟脉冲内,单片机送出二进制位 0000 0010 (02h)。
紧接着发送 24 位地址 (A23-A0)。这决定了数据从哪个位置开始存。
第四步:顺序写入数据流 (Data Byte 1 to 256)
地址发完后,紧接着送入数据字节。
Data Byte 1:在第 32 到 39 个脉冲送入。
持续写入:只要不拉高 CS,可以一直往后发数据,最高支持 256 字节。
图中星号(*)再次强调了 MSB(最高位)在前。
第五步:忽视输出 (DO / IO1) DO 线全程处于 High Impedance(高阻态),因为写入过程中 Flash 只需要接收信息。
下图分析:极速 QPI 模式
核心区别:吞吐量质的飞跃 在 SPI 模式下,写满一页(256 字节)需要发送大量的时钟脉冲;而在 QPI 模式下:
发送指令 (02h):仅需 2 个时钟。
发送地址:仅需 6 个时钟。
发送数据:每个字节仅需 2 个时钟。
结果:数据传输速度提升了 4 倍。对于 500 个节点并发产生的大量数据,QPI 模式能极大缩短总线占用时间。
Sector Erase (20h)指令 扇区擦除
左图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (/CS) 图中看到 /CS 从高电平跳变到低电平(下降沿),开启擦除会话。注意:执行此操作前,必须先发送过 06h (写使能),确保状态寄存器的 WEL 位为 1。
第二步:确认时钟 (CLK) 模式 支持 Mode 0 和 Mode 3。数据在 CLK 的上升沿 被采样。对于擦除地址的传输,时序的精准决定了你是否会“误抹除”其它重要数据。
第三步:发送指令 (DI / IO0) 在第 0 到 7 个时钟脉冲内,单片机送出二进制位 0010 0000 (20h)。这是告诉 Flash:“我要擦除一个 4KB 的扇区”。
第四步:发送 24 位地址 (DI / IO0) 在第 8 到 31 个脉冲,单片机送出目标扇区的起始地址(A23-A0)。图中星号(*)标注了 MSB(最高位)在前。Flash 会根据这个地址锁定对应的 4KB 空间。
第五步:忽视输出 (DO / IO1) DO 线全程处于 High Impedance(高阻态)。擦除指令是单向命令,Flash 在此阶段不返回数据。
右图分析:极速 QPI 模式
核心区别:指令与地址传输极速化 在 SPI 模式下,发送“指令+地址”需要 32 个时钟周期。而在 QPI 模式下:
发送指令 (20h):仅需 2 个时钟(IO0-IO3 并行)。
发送地址:仅需 6 个时钟。
结果:总共只需 8 个时钟 即可启动擦除任务。这在 500 节点高并发、任务切换频繁的 FreeRTOS 环境下,能显著降低总线占用率。
Fast Read (0Bh) 指令
左图分析:标准 SPI 模式 (Standard SPI)
第一步:拉低片选 (/CS) 图中看到 CS 从高电平跳变到低电平(下降沿),开启读取会话。与写入指令不同,读取指令不需要先发“写使能”。
第二步:确认时钟 (CLK) 模式 支持 Mode 0 和 Mode 3。数据在 CLK 的上升沿 被采样。
第三步:发送指令与地址 (DI / IO0)
指令:单片机送出 0Bh。
地址:紧接着送出 24 位地址。到这里为止,它和普通读取(03h)长得一模一样。
第四步:引入“哑时钟” (8 Dummy Clocks) 这是最关键的区别!在地址发完后的第 32 到 39 个时钟周期,DI 线上发什么都无所谓(Don't care)。
意义:这 8 个节拍是给 Flash 内部电路留出的“取货时间”。
第五步:数据输出 (DO / IO1) 从第 40 个时钟开始,Flash 准时在 DO 线上吐出第一个字节。只要你不拉高 CS,它会一直按顺序吐出 500 个节点的所有数据。
右图分析:极速 QPI 模式
核心区别:带宽与灵活度
极速传输:指令仅需 2 个时钟,地址仅需 6 个时钟。
可调哑时钟:QPI 模式下,你可以通过 C0h 指令设置哑时钟的数量(2, 4, 6 或 8 个)。
IO 切换:在 Dummy 阶段结束后,IO0-IO3 会立即从输入模式切换为输出模式,四线同时“开火”吐数据。
资料链接:
https://telesky.yuque.com/bdys8w/01/zr02y6vd0r7mnzcl?singleDoc# 《W25Qxx存储模块》
扫码加入QQ群3群| 610403240
109