Skip to content

一、基本概况

  • 型号:W25Q128JV(常见版本)
  • 厂家:华邦(Winbond)
  • 存储容量:128 Mbit = 16 MB
  • 接口类型:SPI(支持标准 SPI、Dual SPI、Quad SPI,甚至 Octal SPI)
  • 工作电压:2.7V ~ 3.6V(常见 3.3V)
  • 封装:SOIC-8、WSON-8、BGA 等

这颗 Flash 在 STM32、ESP32、FPGA、单片机外部存储扩展 中非常常见,常用于:

  • 存放程序(BootLoader、固件更新)
  • 存放图片、字体、资源(UI、音频)
  • 数据记录(黑匣子、日志)

二、存储结构

W25Q128 的存储组织方式(层级关系):

  • 容量:128 Mbit(16 MB)
  • 扇区(Sector):4096 字节 (4 KB)
  • 块(Block):64 KB = 16 个扇区
  • 页(Page):256 字节
  • 总页数:16 MB ÷ 256B = 65536 页

📌 访问和擦除的最小单位:

  • 写入最小单位:1 字节(但一次操作最大写 256 字节 / 页写入)
  • 擦除最小单位:4 KB(Sector Erase)

三、SPI 通信

常用引脚

  • CS#:片选(低有效)
  • CLK:时钟
  • MOSI:主机输出数据
  • MISO:主机输入数据 (在 Quad SPI 模式下会扩展到 4 条数据线 IO0~IO3)

常用指令(Opcode)

  • 0x06:写使能(Write Enable)
  • 0x04:写禁止(Write Disable)
  • 0x05:读状态寄存器 1
  • 0x02:页编程(Page Program,最多 256B)
  • 0x20:扇区擦除(4 KB)
  • 0xD8:块擦除(64 KB)
  • 0xC7/0x60:整片擦除
  • 0x03:读取数据(低速)
  • 0x0B:快速读取(Fast Read)
  • 0x9F:读取 JEDEC ID(常用于设备识别,W25Q128 → 0xEF 0x40 0x18)

四、工作流程举例

1. 读 JEDEC ID

  1. CS 拉低
  2. 发送 0x9F
  3. 返回 3 字节 ID → EF 40 18

2. 写数据(页编程)

  1. 发送 0x06(写使能)
  2. 发送 0x02(Page Program)+ 24 位地址
  3. 连续写入最多 256 字节
  4. 等待 BUSY 清零(状态寄存器 bit0 = 0)

3. 擦除数据

  • 擦除前必须 写使能
  • 发送 0x20(扇区擦除,4 KB),地址指定扇区起始地址
  • 等待擦除完成(几 ms)

五、优点 & 特点

  • 容量大(16 MB)
  • 速度高(SPI 时钟可达 104 MHz,Quad SPI 更快)
  • 低功耗(待机电流 < 1 μA)
  • 支持掉电指令(节能)
  • 使用广泛,资料丰富,成本低

六、容量对比

参数W25Q64W25Q128
容量xxxxxxxxxx #include "stm32f10x.h"#include "MyI2C.h"#include "AT24C02.h"#include "usart.h"#include <stdio.h>#include "Delay.h"int main(void){    USART2_Init(115200);    MyI2C_Init();​    uint16_t i;    uint8_t data[256];    for (i = 0; i < 256; i++)   {        AT24C02_WriteByte(i, i);        Delay_ms(5);   }    AT24C02_ReadBuffer(0, data, 256);    for (int i = 0; i < 256; i++)   {        printf("Data[%d] = %d\n", i, data[i]);   }}c128 Mbit = 16 MB
页 (Page)256 B256 B
页数32768 页65536 页
扇区 (Sector)4 KB4 KB
扇区数20484096
块 (Block)64 KB64 KB
块数128256

七、页 (Page)、扇区 (Sector)、块 (Block) 的概念和层级顺序

一页有256个字节,一个扇区有16页(16*256Byte=4096Byte)

所以第0页的地址是0-255,第一页的地址是256-511

扇区的地址怎么计算?

因为十进制4096=十六进制0x1000,所以下一个扇区的起始地址 = 当前地址 + 0x1000

第0个扇区的地址是0x000000

存储组织层次

SPI Flash 的存储是分级组织的(小 → 大):

字节 (Byte)  →  页 (Page)  →  扇区 (Sector)  →  块 (Block)  →  整片 (Chip)

可以类比成一本书:

  • 字节 = 一个字
  • 页 = 一页纸
  • 扇区 = 一小章(几页组成)
  • 块 = 一大章(很多小章组成)
  • 整片 = 整本书

具体定义(以 W25Q128 为例)

  1. 页 (Page)
    • 大小:256 字节
    • 最小的编程(写入)单位
    • 一次最多写满一页,写超过会回绕到页头覆盖
  2. 扇区 (Sector)
    • 大小:4 KB = 16 页
    • 最小的擦除单位(擦除会清零,变成全 0xFF
    • 写之前必须先擦除所在的扇区
  3. 块 (Block)
    • 大小:64 KB = 16 扇区
    • 可以整块擦除,速度比逐个扇区快
  4. 整片 (Chip Erase)
    • 擦除整个 Flash(全部清零为 0xFF

八、stm32测试代码

传地址的注意事项

c
W25Q128_PageProgram(256,     data, 256);  // 十进制
W25Q128_PageProgram(0x100,   data, 256);  // 十六进制
W25Q128_PageProgram(0b100000000, data, 256); // 二进制(C语言可能不支持直接写)
c
#include "stm32f10x.h"
#include "MyI2C.h"
#include "AT24C02.h"
#include "usart.h" // 用于打印结果,可自行实现
#include <stdio.h>
#include "Delay.h"
#include "MySPI.h"
#include "W25Q128.h"
uint8_t wdata[256];
uint8_t rdata[256];
int main(void)
{
    USART2_Init(921600);
	W25Q128_Init();
    uint16_t i,j;
    // 擦除前两个扇区(共 8KB,足够 32 页)0-31页面
    W25Q128_SectorErase(0x000000);  // 4KB
    W25Q128_SectorErase(0x001000);  // 另 4KB

    Delay_ms(10);

    // 写入前 32 页(每页 256 字节,共 8KB)
    printf("Writing 32 pages...\r\n");
    for (i = 0; i < 32; i++) {
        uint32_t addr = i * 256;

        // 构造数据:第 i 页全填 i
        for (j = 0; j < 256; j++) {
            wdata[j] = i;
        }

        W25Q128_PageProgram(addr, wdata, 256);
        printf("Page %d written at 0x%06X\r\n", i, addr);
    }

    // 读取验证
    printf("Reading back...\r\n");
    for (i = 0; i < 32; i++) {
        uint32_t addr = i * 256;
        W25Q128_ReadData(addr, rdata, 256);

        for (j = 0; j < 256; j++) {
            // if (rdata[j] != i) {
            //     printf("ERROR: Page=%d, Offset=%d, Expected=%d, Got=%d\r\n", i, j, i, rdata[j]);
            // }
            printf("Page=%d, Offset=%d, Expected=%d, Got=%d\r\n", i, j, i, rdata[j]);
        }
    }
    
}