- W25Q64简介
- 硬件电路
- W25Q64框图
- 块Block
- 扇区Sector
- 页Page
- SPI控制逻辑
- 状态寄存器
- 写控制逻辑
- 高电压生成器
- 页地址锁存/计数器与字节地址锁存/计数器
- 256字节页缓存区
- Flash操作注意事项
- 状态寄存器
- BUSY 位
- 写使能锁存(WEL)
- W25Q64 SPI指令集
- 设备验证
- 指令集
- 指令集表1(通用指令)
- 指令集表2(读指令)
W25Q64简介
- W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器(数据掉电不丢失),常应用于数据存储、字库存储、固件程序存储等场景
- 存储介质:Nor Flash(闪存)
- 时钟频率:80MHz / 160MHz (Dual SPI,MOSI和MISO都可以接收和发送数据,相当于标准模式2倍的通信速度) / 320MHz (Quad SPI,4位并行)
- 存储容量(24位地址,Q256就得分为3字节地址模式(只能读前16MByte),4字节地址模式(读全部)):
W25Q40: 4Mbit / 512KByte
W25Q80: 8Mbit / 1MByte
W25Q16: 16Mbit / 2MByte
W25Q32: 32Mbit / 4MByte
W25Q64: 64Mbit / 8MByte
W25Q128: 128Mbit / 16MByte
W25Q256: 256Mbit / 32MByte
硬件电路
引脚 | 功能 |
---|---|
VCC、GND | 电源(2.7~3.6V) |
CS(SS) | SPI片选 |
CLK(SCK) | SPI时钟 |
DI(MOSI) | SPI主机输出从机输入 |
DO(MISO) | SPI主机输入从机输出 |
WP | 写保护,低电平有效 |
HOLD | 数据保持,低电平有效 ,相当于SPI总线进入一次中断,在中断里干别的事情,芯片保持状态,然后恢复中断前的时序 |
W25Q64框图
如上图,是存储器规划示意图
一整块存储空间,先划分为若干的块Block,其中每一块再划分为若干个扇区Sector,对于每个扇区,内部又分成很多页Page,存储器以字节为单位,每个字节都有唯一的地址,W25Q64的地址宽度是24位,3个字节,所以看到左下角第一个字节地址是00 00 00h,之后的空间,地址依次自增,直到最后一个字节,地址是7F FF FFh,最后一个字节是7F开头不是FF开头的原因:因为24位地址,最大寻址范围是16MB,而W25Q64只有8MB,所以地址空间只用了一半,8MB的空间排到最后一个字节,就是7F FF FFh
块Block
然后在这整个空间里,我们以64KB为一个基本单元,把吃划分成若干的块Block,从前往后,依次是块0、块1、块2、等等等等,那整块蛋糕是8MB,以64KB为一块进行划分,最后分得的块数,就是8MB/64KB=128块,块序号是块0到块127,块0的起始地址是00 00 00h,块0的结束地址是00 FF FFh,之后,块31的起始地址是1F 00 00h,块31的结束地址是1F FF FFh。
扇区Sector
如上图,我们还要再对每一块进行更细的划分,分为多个扇区Sector,虚线对应右侧各个块,在每个块里,起始地址是xx 00 00h,结束地址是xx FF FFh,在一块里,我们再以4KB为1个单元,进行切分,一块是64KB,总共切得16份,每一块里可分为扇区0和扇区15,每个扇区内的地址范围是xx 00 00h,到xx xF FFh,这就是对每一块,再细分为16个扇区的分配方式。
页Page
地址划分到扇区就结束了,但是当我们写入数据的时候,还会有个更细致的划分,就是页Page,页是直接对整个存储空问划分的,当然你也可以把它看作,在扇区里再进行划分,都是一样,页的大小是256个字节,一个扇区是4KB,以256个字节划分,能分得16页,如下图,每一行就是一页:
左边这里指了个箭头,写的是页地址的开始,右边这里也指了个箭头,写的是页地址的结束,在一页种,地址变化范围是xx xx 00h到xx xx FFh,一页内的地址变化,仅限于地址的最低一个字节
SPI控制逻辑
如上图,这里是SPI控制逻辑,也就是芯片内部进行地址锁存、数据读写等操作,都可以由控制逻辑来自动完成,控制逻辑就是整个芯片的管理员。
如上图,控制逻辑左侧就是SPI的通信引脚,有WP、HOLD、CLK、CS、DI和DO,这些引脚和主控芯片相连,主控芯片通过SPI协议,把指令和数据发送给控制逻辑,控制逻辑就会自动取操作内部电路来完成功能。
状态寄存器
控制逻辑上面有个状态寄存器,这个状态寄存器是比较重要的,比如芯片是否处于忙状态、是否写使能、是否写保护,都可以在这个状态寄存器里体现。
写控制逻辑
和外部的WP引脚相连,显然,这个是配合WP引脚实现硬件写保护的
高电压生成器
这个是配合Flash进行编程的,因为Flash是掉电不丢失的,如何实现掉电不丢失?比如你点亮一个LED表示1,熄灭LED表示0,但如果整个系统电都没有,那1和0就无从说起了,所以要想掉电不丢失,需要加高电压。
页地址锁存/计数器与字节地址锁存/计数器
这两个地址锁存和计数器,就是用来指定地址的,我们通过SPI总线发过来3个字节的地址,因为一页是256字节,所以一页内的字节地址,就取决于最低一个字节,而高位的2个字节,就对应的是页地址,所以在这里,我们发的3个字节地址,前两个字节,会进到这个页地址锁存计数器里,最后一个字节,会进到这个字节地址锁存计数器里。
如上图,然后,页地址,通过这个写保护和行解码,来选择我要操作哪一页
如上图,字节地址,通过这个列解码和256字节页缓存,来进行指定字节的读写操作,那又因为我们这个地址锁存,都是有一个计数器的,所以这个地址指针,在读写之后,可以自动加1,从指定地址开始,连续读写多个字节的目的了
256字节页缓存区
它其实是一个256字节的RAM存储器,数据读写就是通过这个RAM缓存区来进行的,写入数据先放到缓存区里,然后在时序结束后,芯片再将缓存区的数据复制到对应的Flash里,进行永久保存,由于SPI写入的频率是非常高的,而Flash的写入,由于需要掉电不丢失,写入比较慢,所以需要一个页缓存区,但它只有256字节,所以就有限制,就是写入的一个时序,连续写入的数据量,不能超过256字节,然后等你写完了,我芯片再慢慢地把数据,从缓存区转移到Flash存储器里,数据从缓存区转到Flash里需要一定的时间,所以在写入时序结束后,芯片会进入一段忙的状态
进入忙的状态后,它给状态寄存器的BUSY位置1,那在忙的时候,芯片就不会响应新的读写时序了,这是写入的执行流程,然后读取数据,读取虽然也通过缓存区,但是读取速度块,限制少。
Flash操作注意事项
写入操作时:
-
写入操作前,必须先进行写使能
-
每个数据位只能由1改写为0,不能由0改写为1
-
写入数据前必须先擦除,擦除后,所有数据位变为1
-
擦除必须按最小擦除单元(一个扇区)进行
也就是一次擦4090个字节,如果只想擦1个字节(小于4090字节的数据),只能先把一个扇区的数据读出来,然后再把一个扇区擦除,改 写完读出来的数据后,再把4096个字节全部写回去。我们也可以优化以下,比如上电后先把Flash数据读出来放在RAM里,当有数据变动时,我再统一把数据备份到Flash里,或者我把使用频繁的扇区,放在RAM里,当使用频率降低时,我再把整个扇区备份到FLash里,或者,如果你数据量确实非常少,只想存几个字节的参数就行了,那就让一个字节占一个扇区。 -
连续写入多字节时,最多写入一页的数据,超过页尾位置的数据,会回到页首覆盖写入(页缓存区导致的)
-
写入操作结束后,芯片进入忙状态,不响应新的读写操作(读busy寄存器就知道芯片是否进入忙状态)
读取操作时:
- 直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取
状态寄存器
这里状态寄存器总共有两个,状态寄存器1和状态寄存器2,比较重要的是状态寄存器1,状态寄存器1里,又有两个位,是比较重要的,一个BUSY,一个是WEL
BUSY 位
BUSY 是状态寄存器中的一个只读位(S0 位),当器件正在执行页编程、扇区擦除、块擦除、整片擦除或写状态寄存器指令时,该位会被置为 1。在此期间,器件会忽略除 读状态寄存器 和 擦除挂起 指令之外的其他指令(参见交流特性中的 tW、tPP、tSE、tBE 和 tCE 参数)。当编程、擦除或写状态寄存器指令完成后,BUSY 位会被清零为 0,表明器件已准备好接收后续指令。
写使能锁存(WEL)
写使能锁存(WEL)是状态寄存器中的一个只读位(S1 位),在执行 写使能 指令后会被置为 1。当器件进入写禁止状态时,WEL 状态位会被清零为 0。写禁止状态会在上电时出现,或者在执行以下任意指令后出现:写禁止、页编程、扇区擦除、块擦除、整片擦除以及写状态寄存器。
写入操作后自动写进制,相当于有个顺手关门的操作
W25Q64 SPI指令集
设备验证
制造商ID(MANUFACTURER ID) | (M7-M0) | |
---|---|---|
华邦串行闪存(Winbond Serial Flash) | EFh | |
设备ID(Device ID) | (ID7-ID0) | (ID15-ID0) |
指令(Instruction) | ABh、90h | 9Fh |
W25Q64BV | 16h | 4017h |
指令集
指令集表1(通用指令)
指令名称(INSTRUCTION NAME) | 字节1(操作码,BYTE 1 (CODE)) | 字节2(BYTE 2) | 字节3(BYTE 3) | 字节4(BYTE 4) | 字节5(BYTE 5) | 字节6(BYTE 6) |
---|---|---|---|---|---|---|
写使能(Write Enable) | 06h | - | - | - | - | - |
写禁止(Write Disable) | 04h | - | - | - | - | - |
读状态寄存器1(Read Status Register-1) | 05h | (S7–S0)¹ | - | - | - | - |
读状态寄存器2(Read Status Register-2) | 35h | (S15–S8)¹ | - | - | - | - |
写状态寄存器(Write Status Register) | 01h | (S7–S0) | (S15–S8) | - | - | - |
页编程(Page Program) | 02h | A23–A16(地址高位) | A15–A8(地址中位) | A7–A0(地址低位) | (D7–D0)(数据字节) | - |
四通道页编程(Quad Page Program) | 32h | A23–A16 | A15–A8 | A7–A0 | (D7–D0...)²(四通道数据) | - |
块擦除(64KB,Block Erase (64KB)) | D8h | A23–A16 | A15–A8 | A7–A0 | - | - |
块擦除(32KB,Block Erase (32KB)) | 52h | A23–A16 | A15–A8 | A7–A0 | - | - |
扇区擦除(4KB,Sector Erase (4KB)) | 20h | A23–A16 | A15–A8 | A7–A0 | - | - |
整片擦除(Chip Erase) | C7h/60h | - | - | - | - | - |
擦除挂起(Erase Suspend) | 75h | - | - | - | - | - |
擦除恢复(Erase Resume) | 7Ah | - | - | - | - | - |
掉电模式(Power-down) | B9h | - | - | - | - | - |
高性能模式(High Performance Mode) | A3h | dummy(虚拟周期) | dummy | dummy | - | - |
连续读模式复位(Reset⁴) | FFh | FFh | - | - | - | - |
唤醒/读ID(Release Power down or HPM / Device ID⁵) | ABh | dummy | dummy | dummy | (ID7-ID0)(设备ID低8位) | - |
读制造商/设备ID(Manufacturer/ Device ID⁶) | 90h | dummy | dummy | 00h | (MF7-MF0)(制造商ID) | (ID7-ID0)(设备ID) |
读唯一ID(Read Unique ID⁷) | 4Bh | dummy | dummy | dummy | dummy | (ID63-ID0)(64位唯一ID) |
JEDEC ID(读JEDEC ID) | 9Fh | (MF7-MF0)(制造商ID) | (ID15-ID8)(设备ID高8位) | (ID7-ID0)(设备ID低8位) | - | - |
- 状态寄存器读取:
(S7–S0)
是状态寄存器低8位(S0为最低位),数据会持续从DO引脚输出,直到CS引脚拉低结束指令。 - 四通道编程:
(D7–D0...)
表示四通道并行写数据(IO0=D0、IO1=D1、IO2=D2、IO3=D3,同时传4位)。 - 复位指令:用于退出连续读模式(双/四通道),确保模式切换正确(细节看手册11.2.29节)。
- 唤醒/读ID:
dummy
是“空周期”(仅提供时钟,无实际数据),让芯片从掉电模式唤醒并准备ID数据。 - 唯一ID:需向华邦特殊订货支持,具体联系厂家。
【注】扇区擦除传的是3个字节的地址,发送扇区擦除指令,这个指定地址所在的扇区就会被整个擦除,这个地址是精确到某个字节的,
写使能,DO的时序处于高阻态,写数据指令,不需要回传数据,所以DO始终保持高阻态,Mode0和Mode3是指这个芯片可以兼容SPI的模式0和模式3,都是下降沿移除,上升沿移入,一般用模式0即可。
指令集表2(读指令)
指令名称(INSTRUCTION NAME) | 字节1(操作码,BYTE 1 (CODE)) | 字节2(BYTE 2) | 字节3(BYTE 3) | 字节4(BYTE 4) | 字节5(BYTE 5) | 字节6(BYTE 6) |
---|---|---|---|---|---|---|
读数据(Read Data) | 03h | A23–A16 | A15–A8 | A7–A0 | (D7–D0)(数据) | - |
快速读(Fast Read) | 0Bh | A23–A16 | A15–A8 | A7–A0 | dummy(虚拟周期) | (D7–D0)(数据) |
快速读双输出(Fast Read Dual Output) | 3Bh | A23–A16 | A15–A8 | A7–A0 | dummy | (D7–D0...)¹(双输出数据) |
快速读双IO(Fast Read Dual I/O) | BBh | A23–A9²(地址高位) | A7–A0, M7-M0³(地址+模式位) | (D7–D0...)¹ | - | - |
快速读四输出(Fast Read Quad Output) | BBh | A23–A16 | A15–A8 | A7–A0 | dummy | (D7–D0...)³(四输出数据) |
快速读四IO(Fast Read Quad I/O) | EBh | A23–A0, M7-M0⁴(地址+模式位) | (x.x.x.x D7-D0 ...)⁵(四通道数据) | (D7–D0 ...)³ | - | - |
八进制字读(Octal Word Read) | E3h | A23–A0, M7-M0⁴ | (D7-D0 ...)³ | - | - | - |
四通道IO读⁸(Quad I/O⁸) | E3h | A23–A0, M7-M0⁴ | (D7-D0 ...)³ | - | - | - |
这个ReadData没有页限制,想怎么读就怎么读
- 双/四输出数据:
- 双输出:IO0传D6、D4…(偶数位),IO1传D7、D5…(奇数位),同时出2位。
- 四输出:IO0=D4、D0…,IO1=D5、D1…,IO2=D6、D2…,IO3=D7、D3…,同时出4位。
- 双IO地址(A23–A9):地址拆分为双IO传输,IO0传偶数位(A22、A20…),IO1传奇数位(A23、A21…)。
- 模式位(M7-M0):配置芯片工作模式(如速度、协议),具体定义看手册。
- 四IO地址:地址通过4个IO口传输(IO0-IO3分别传不同位,例:IO0=A20、A16…)。
- 快速读四IO数据:数据前有4个“dummy位”(x表示无意义),之后四通道并行出数据。
- 地址限制:八进制/四IO模式下,地址最低4位(A0-A3)必须为0,否则指令无效。
- dummy周期:快速读里的dummy是芯片“内部准备数据的时间”,必须发够时钟才能正确读数据。
【注】关于4K对齐
要理解 4K 对齐,可以结合 W25Q64 闪存的擦除特性 来解释,核心是 “闪存的擦除/编程单位限制”,以下分步骤拆解:
先明确 W25Q64 的 擦除单位
从之前的指令表可知:W25Q64 的 扇区擦除(Sector Erase) 指令是
20h
,每次擦除 4KB(4096 字节) 的数据。也就是说:闪存里的“扇区”是 4KB 大小的块,擦除操作必须以“整个扇区”为单位(不能只擦 1 字节,也不能擦跨扇区的部分)。
什么是“4K 对齐”?
“4K 对齐”指:地址对齐:数据的起始地址必须是
4096(0x1000)
的整数倍(比如0x0000
、0x1000
、0x2000
…)。长度对齐:数据的总长度也建议是 4KB 的整数倍(避免跨扇区存储)。
类比理解:
把闪存想象成 “仓库”,每个“扇区”是一个 4096 格的箱子。4K 对齐 → 东西必须整箱存放(起始在箱子开头,长度刚好装满箱子)。
不对齐 → 东西跨两个箱子存放(比如从第 2 格开始放 4096 个东西,会占第 1 箱末尾和第 2 箱开头)。
为什么必须 4K 对齐?
如果数据 不对齐,会引发两个核心问题:(1)擦除效率极低
假设数据跨两个扇区(比如从0x0001
存 4KB):擦除时,必须同时擦除 前一个扇区(0x0000-0x0FFF) 和 后一个扇区(0x1000-0x1FFF),导致 擦除范围翻倍,浪费时间和闪存寿命(闪存擦写次数有限)。
(2)数据逻辑混乱
闪存的 编程(写) 可以按页(256 字节)操作,但 擦除必须按扇区。如果数据跨扇区:擦除后,跨扇区的部分会被意外清空,导致数据逻辑错误(比如文件系统里的文件被截断)。
结合 W25Q64 指令的实际表现
当执行 扇区擦除(20h) 时:芯片会强制检查操作地址是否是 4KB 对齐的(比如地址
0x0000
是合法的,0x0001
会被忽略或报错)。只有地址对齐,擦除指令才会生效,确保每次擦除刚好覆盖一个扇区,避免误操作。
简单总结:
4K 对齐是为了适配闪存“擦除必须按 4KB 扇区”的硬件限制,让数据存储和擦除更高效、更安全,避免跨扇区操作带来的性能和逻辑问题。
(类比:就像快递必须按“标准箱子”发货,不然仓库没法高效处理~)