4. QSPI Flash 存储器结构:页、扇区、块的划分
做嵌入式这些年,我见过不少新手栽在 Flash 存储结构上。他们以为 Flash 就是个“大数组”,想写哪就写哪。结果呢?要么写错了地址,要么擦除把数据全弄丢了。你想想看,一个 NOR Flash 芯片动辄几十 MB,内部要是没个层次,管起来非得疯掉不可。
今天就聊聊 QSPI Flash 的内部架构。说白了,它就像一座仓库——最小的单元是“页”,然后“扇区”,再往上“块”,最后是整个芯片。每一层都有自己的一组规则。记住这些规则,你写驱动、做启动时就能少踩很多坑。
4.1 基础单元:页 (Page)
页是 Flash 编程(写入)的最小单位。你可以往一页里写数据,但不能只写一个字节——想写必须写一整页,或者页的一部分。常见的 QSPI Flash 页大小是 256 字节或 512 字节。
- 页写入时序:发送页编程命令(0x02),随后 3 字节地址、数据字节流。芯片内部会把数据锁存到页缓冲区,然后自动烧写。
- 页边界限制:一次编程不能跨页。比如你从地址 0x00FF 开始写 2 字节,第三字节就落到下一页。很多驱动没处理好这问题,结果数据错位。我早些年在 STM32H7 上做 QSPI 驱动时就掉过这个坑。
page_size - (addr % page_size) 算当前页剩余容量,特别实用。
4.2 擦除最小单元:扇区 (Sector)
页只能写,不能直接覆盖。想更新一页里的几个字节?得先把整个扇区擦除,再写回去。为什么这样?因为 Flash 物理特性决定了“写 1 变 0 容易,写 0 变 1 只能靠擦除”。
扇区(Sector)是擦除的最小单位。常见大小有 4 KB(小扇区)和 64 KB(大扇区)。拿 Winbond W25Q64 来说,它就有 4 KB 小扇区,刚好适配文件系统(如 FATFS)的簇大小,做日志存储特别方便。
| 扇区类型 | 典型大小 | 常见芯片 | 用途 |
|---|---|---|---|
| 小扇区 | 4 KB | W25Q64, MX25L6435 | 文件系统、配置参数 |
| 大扇区 | 64 KB | N25Q512, S25FL128 | 大块固件、启动镜像 |
擦除一个扇区大概需要几十到几百毫秒。使用时还得注意:擦除前必须确保该扇区没有正在执行的操作,否则状态寄存器会一直显示“忙碌”。
4.3 更大粒度:块 (Block)
把多个扇区组合,就成了块(Block)。块大小通常是 32 KB(8 个小扇区)或 64 KB(16 个小扇区)。很多 Flash 提供“块擦除”命令,能一次擦除整块,比逐个扇区擦快得多。
- 块擦除指令:命令码 0xD8(64KB 块)或 0x52(32KB 块)。
- 芯片擦除:命令 0xC7,擦除整个 Flash。耗时几秒,慎用。
嗯,这里要注意:不同厂商、不同型号的 Flash,块定义可能不一样。比如 Cypress S25FL系列里还有“参数块”和“主块”之分。拿到芯片后第一件事就是读 datasheet 里的 memory map 表,别想当然。
4.4 整芯片结构层次
把上面三层串起来,就是 Flash 的完整分级:
芯片 (Chip)
└─ 块 (Block) 64KB
└─ 扇区 (Sector) 4KB (16个扇区组成一个块)
└─ 页 (Page) 256B (16页组成一个扇区)
└─ 字节 (Byte)
还是拿 W25Q64 举例:总容量 8 MB,内有 128 个 64KB 的块,每个块又分 16 个 4KB 扇区,每个扇区 16 页。这样你算算:8 MB = 128 × 64 KB = 2048 × 4 KB = 32768 × 256 B。
4.5 划分背后的设计思想
为什么不直接用“字节擦除”呢?因为在 Flash 内部,擦除操作需要给整个字线(word line)加高电压,颗粒度越小,控制逻辑越复杂,芯片成本越高。折中下来,业界选了 4 KB 扇区作为最小擦除单元,既照顾了文件系统需求,又控制了 die 面积。
我记得做过一个产品,Bootloader 和应用程序分别放不同块,参数区用一个小扇区。升级时只需擦除应用程序所在块,Bootloader 不动,很安全。
- 写 → 以页为单位(页编程)
- 擦除 → 以扇区或块为单位(扇区/块擦除)
- 读 → 任意字节(无限制)
4.6 实际应用中的选择策略
做启动代码或存储方案时,怎么分配这些层级?我一般这么干:
- Bootloader:放在最前面 1~2 个块,用 64KB 块擦除,反正不常更新。
- 应用程序:按功能分区,每个模块放一个或几个连续块。
- 参数 / 配置数据:用 4KB 小扇区,每次更新擦除一个扇区。如果参数很小(比如几十字节),我会在驱动里做成“备份扇区”轮流使用,避免频繁擦写同一个扇区导致磨损——Flash 的擦写寿命大概 10 万次,别忽视。
- 日志 / 数据记录:用一整个块,按页追加写。写满后擦除整个块重新开始,效率最高。
总之,了解页、扇区、块的划分,不光是为了看懂 datasheet,更是为了写出高效、可靠的 Flash 驱动。下一级一级的擦写关系理顺了,你就能在项目里灵活地规划存储布局。嗯,这块内容就先到这里,后面用到具体操作时会反复提到这些基本概念。