4、NOR Flash 选型:XIP(片上执行)特性,Quad/Octal SPI 接口,容量与扇区大小选择
各位做嵌入式开发的朋友,咱们今天聊聊 NOR Flash 选型。说实话,这玩意儿看着简单,但坑是真不少。我这些年经手的项目,少说也有几十个,每次选 NOR Flash 都得打起十二分精神。
先说说我的核心建议:代码存储,首选 NOR Flash。为什么?因为它能 XIP(片上执行),说白了就是 CPU 可以直接在上面跑代码,不用先搬到 RAM 里。这个特性在嵌入式系统里太重要了。
XIP 特性:为什么代码存储离不开它?
XIP,全称是 Execute In Place。你想想看,系统上电后,CPU 要做的第一件事是什么?读第一条指令。如果代码存在 NOR Flash 里,CPU 可以直接通过地址总线访问它,就像访问内存一样。
我在项目中遇到过这样的情况:有个同事非要用 NAND Flash 存代码,结果每次启动都要先把代码搬到 RAM 里,不仅启动慢,还多占了一颗 RAM 芯片。后来我建议他换成 NOR Flash,启动时间从 2 秒降到了 0.3 秒。嗯,这就是 XIP 的魅力。
关键点:NOR Flash 的读时序和 SRAM 类似,CPU 可以直接通过地址线读取指令。而 NAND Flash 是块设备,必须通过控制器间接访问,没法 XIP。
Quad/Octal SPI 接口:速度与成本的平衡
早期的 NOR Flash 用 SPI 接口,一次只能传 1 位数据。后来有了 Quad SPI(四线),再后来是 Octal SPI(八线)。我个人习惯,根据系统对读速度的要求来选择:
- 标准 SPI:适合低速应用,比如存些配置参数。时钟跑 20MHz 就够用了。
- Quad SPI:目前最主流的选择。四线同时传输,速度能到 80MB/s 以上。我大部分项目都用这个。
- Octal SPI:追求极致速度时用。八线传输,速度能飙到 200MB/s 以上。但要注意,这种 Flash 通常更贵,而且 PCB 布线也更复杂。
我记得有个项目,客户要求系统启动时间小于 100ms。用 Quad SPI 的 NOR Flash,读速度勉强够。后来换成 Octal SPI,启动时间直接砍半。但代价是 BOM 成本涨了 30%。所以选型时一定要权衡。
我的建议:如果系统对启动速度要求不高,用 Quad SPI 就够了。别盲目追求 Octal,省下的钱可以买杯咖啡。
容量与扇区大小选择:别小看这个细节
NOR Flash 的容量从几 Mb 到几 Gb 都有。但选容量时,我建议你多留个心眼:
- 代码大小:先估算你的固件有多大。一般留 50% 的余量,方便后续升级。
- 扇区大小:这个特别容易踩坑。NOR Flash 的擦除操作是按扇区来的,扇区越大,擦除时间越长。
我曾经在一个项目里选了 64KB 扇区的 NOR Flash,结果每次 OTA 升级都要擦除整个扇区,哪怕只改了几个字节。后来换成 4KB 小扇区的型号,升级效率提升了好几倍。
| 扇区大小 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 4KB | 擦除粒度细,适合频繁小数据更新 | 管理复杂,需要更多元数据 | 参数存储、OTA 升级 |
| 64KB | 管理简单,擦除效率高 | 擦除粒度粗,浪费空间 | 代码存储、大块数据 |
| 256KB | 适合大容量存储 | 擦除时间长,不适合频繁更新 | 固件镜像、文件系统 |
避坑指南:我曾经选了一款 256KB 扇区的 NOR Flash 存配置文件,结果每次改一个参数都要擦除 256KB 的数据,写入时间长达 500ms。后来换成 4KB 扇区的型号,写入时间降到 30ms。所以,如果你的系统需要频繁更新小数据,一定要选小扇区的 Flash。
代码示例:如何配置 Quad SPI 读操作
下面是一个简单的 Quad SPI 读操作配置示例,基于 STM32 的 HAL 库:
// 配置 Quad SPI 读操作
void QSPI_Read_Config(void)
{
QSPI_CommandTypeDef sCommand;
// 设置读命令
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = 0xEB; // Quad Output Fast Read
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.DummyCycles = 6; // 需要 6 个 dummy cycle
sCommand.NbData = 256; // 读取 256 字节
// 发送命令
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT) != HAL_OK)
{
Error_Handler();
}
// 读取数据
uint8_t buffer[256];
if (HAL_QSPI_Receive(&hqspi, buffer, HAL_QSPI_TIMEOUT_DEFAULT) != HAL_OK)
{
Error_Handler();
}
}
这段代码里,我用了 Quad Output Fast Read 命令(0xEB),地址和数据都走四线。注意那个 DummyCycles,不同厂商的 Flash 可能不一样,一定要看数据手册。
总结一下我的选型思路
嗯,说了这么多,最后总结几点:
- 代码存储,首选 NOR Flash,因为 XIP 特性无可替代。
- 接口选 Quad SPI,性价比最高。除非你对速度有极致要求,再考虑 Octal。
- 容量留 50% 余量,别抠门。扇区大小根据你的更新频率来选。
- 多看数据手册,特别是时序参数和命令集。不同厂商的兼容性可能有问题。
我建议你选型时,先画个表格,把需求列清楚:代码大小、更新频率、启动时间要求、成本预算。然后拿着这个表去选 Flash,基本不会出大错。
好了,这一章就聊到这儿。下一章咱们讲讲 NAND Flash 选型,那个坑更多,到时候再细说。