QSPI(Quad SPI)作为SPI接口的增强版本,已经成为嵌入式系统中连接外部Flash存储器的首选方案。我第一次接触QSPI是在开发智能家居主控板时,需要同时满足快速启动和低成本存储的需求。当时在NOR Flash和NAND Flash之间的选择就让我纠结了很久。
NOR Flash和NAND Flash这对"兄弟"虽然都姓Flash,但性格迥异。NOR就像个严谨的图书馆管理员,允许随机访问且数据可靠性高,但存储空间有限(常见16Mb-1Gb),适合存放启动代码这类"珍贵资料"。我经手的一个工业控制器项目就使用了256Mb的NOR Flash,系统启动时间控制在200ms以内。NAND则像个大仓库,容量大(通常1Gb起跳)且性价比高,但需要整块擦写,适合存储日志、媒体文件这类"大宗货物"。
在接口选择上,CFI Flash虽然速度快,但引脚需求多(约40个),而QSPI仅需6个引脚(CLK, CS, IO0-IO3)就能实现四线通信。这个优势在PCB空间受限的智能手表项目中体现得淋漓尽致——我们通过QSPI连接1Gb NAND Flash,省下的布线空间足够再放个心率传感器。
传统模式是QSPI兼容普通SPI的"基础形态",所有通信都通过单线(DQ0)完成。去年调试一个传感器模块时,我就用这个模式读取Flash ID作为硬件检测的第一步。具体操作就像和老朋友对话:
c复制// 读取Flash ID的典型代码
uint8_t cmd = 0x9F; // JEDEC ID命令
HAL_QSPI_Command(&hqspi, &cmd, 100);
HAL_QSPI_Receive(&hqspi, id_buffer, 100);
这个模式下,每个时钟周期传输1bit数据,实测速度约50Mbps。虽然比四线模式慢,但胜在兼容性强。有次客户的老款MCU只支持标准SPI,就是靠这个模式救的场。需要注意的是,在初始化阶段,即使支持高速模式的Flash也会默认进入单线状态,需要先发送命令(如0x35)启用四线功能。
STIG模式就像给Flash装了个语音助手——发送特定指令就能触发预设操作。在开发物联网网关时,我通过0xEB指令(四线快速读取)将读取速度提升到104MHz。这个模式的精髓在于命令序列配置:
c复制QSPI_CommandTypeDef cmd;
cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
cmd.Instruction = 0xEB; // 四线读取指令
cmd.AddressMode = QSPI_ADDRESS_4_LINES;
cmd.DataMode = QSPI_DATA_4_LINES;
HAL_QSPI_Command(&hqspi, &cmd, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
实际应用中要注意三点:1) 不同厂商的指令集可能有差异(比如Winbond的0xEB对应Micron的0xEC);2) 发送多字节地址时要考虑端序问题;3) 模式切换后需要适当的延时(通常10us以上)。有次批量读取异常,最后发现是没等Flash就绪就发送下个命令。
DAC模式实现了内存映射的魔法,让Flash像SRAM一样直接访问。在汽车HMI项目中,我们将UI资源库映射到0x90000000地址,渲染引擎直接读取就像访问本地内存。配置关键步骤:
c复制*(volatile uint32_t*)0x90000000; // 直接读取Flash内容
但要注意两个坑:1) 访问未对齐地址可能触发硬件错误;2) 连续访问需要插入等待周期。有次系统卡死就是因为DMA直接读取映射区域时没配置等待状态。建议首次使用时先用逻辑分析仪抓取CLK波形,确认时序是否符合Flash规格书要求。
INDCA模式像是个聪明的邮差——先把快递(数据)放在中转站(SRAM),再按需配送。在音频播放器项目中,我们用它实现双缓冲机制:当DAC播放SRAM1中的数据时,QSPI正将下一段音频数据写入SRAM2。典型配置流程:
c复制// 配置间接访问控制器
hqspi.Init.FifoThreshold = 16;
hqspi.Init.ClockPrescaler = 2;
// 设置传输参数
QSPI_Data_TypeDef cfg;
cfg.Address = 0x000000;
cfg.DataSize = 512;
HAL_QSPI_Indirect_Write(&hqspi, &cfg, pData);
这种模式特别适合处理大数据块,但要注意SRAM大小限制。有次移植代码到新平台时没注意SRAM只有32KB,导致传输超过16KB就溢出。建议在初始化时动态检测可用SRAM空间。
轮询模式把工程师从重复劳动中解放出来。在智能电表项目中,我们设置每5秒自动读取Flash状态寄存器,检测写操作是否完成:
c复制QSPI_AutoPollingTypeDef cfg;
cfg.Match = 0x00; // 等待BUSY位清零
cfg.Mask = 0x01; // 只监控bit0
cfg.Interval = 0x10; // 轮询间隔
HAL_QSPI_AutoPolling(&hqspi, &cfg, 100);
而XIP模式则是启动加速的利器。通过将0x08000000映射到外部Flash,我们的工业控制器实现了150ms冷启动。关键配置点包括:
有次客户抱怨启动慢,最后发现是忘记在链接脚本中将关键函数放在XIP区域。建议使用__attribute__((section(".xip")))显式指定关键函数位置。
四线模式(QIO)虽快但布线要求高。在四层板设计中,我习惯将DQ信号走带状线,保持等长(±50ps)。双线模式(DIO)则是性价比之选,某消费电子项目通过它节省了20%布线面积。选择建议:
实测数据显示,在104MHz时钟下:
最后提醒:切换模式前务必确认Flash支持该功能。有次硬件改版后Flash无法识别,最终发现是新批次芯片默认禁用四线模式,需要先发送0x35命令解锁。建议在初始化流程中加入完整的特性检测步骤。