QSPI、OSPI与FSMC的区别与内存映射分析
基本概念与区别
1. FSMC (灵活静态存储控制器)
- 接口类型:并行接口,通常8/16位数据总线
- 总线标准:传统并行总线协议
- 速度:相对较低,通常最高约100MHz
- 应用场景:SRAM、NOR Flash、PSRAM、LCD等并行接口外设
2. QSPI (四线串行外设接口)
- 接口类型:串行接口,1/2/4线数据传输
- 总线标准:SPI协议的扩展
- 速度:中等,通常最高约108MHz,有效带宽达到50MBytes/s (4线x108MHz/8位)
- 应用场景:Serial NOR Flash、EEPROM等
3. OSPI (八线串行外设接口)
- 接口类型:串行接口,1/2/4/8线数据传输
- 总线标准:QSPI的扩展,兼容QSPI
- 速度:较高,通常最高约200MHz,有效带宽可达到200MBytes/s (8线x200MHz/8位)
- 应用场景:高速Serial NOR Flash、Hyperflash、Hyper RAM
内存映射功能对比
FSMC内存映射
- 直接映射:FSMC直接将外部存储设备映射到CPU的地址空间
- 访问方式:CPU直接通过地址访问,无需专用命令
- 优势:实现简单,无需特殊初始化序列
- 延迟:相对较低,通常1-2个时钟周期
- 地址范围:STM32上通常映射到0x6000 0000 - 0x6FFF FFFF
QSPI内存映射
- 间接映射:通过QSPI控制器将闪存内容映射到系统地址空间
- 访问流程:
- 控制器发送特定命令(通常是0x0B/0xEB)
- 发送地址
- 插入可选的虚拟周期
- 连续读取数据
- 映射机制:QSPI控制器自动处理命令序列
- 地址范围:典型映射到0x9000 0000 - 0x9FFF FFFF
OSPI内存映射
- 增强型映射:支持QSPI的所有功能,并增加了8线模式支持
- 访问流程:与QSPI相似,但可以使用8线传输
- 高级特性:
- 支持更复杂的命令序列
- 双闪存同时访问(STM32H7系列)
- 内存映射期间支持XIP缓存
- 地址范围:类似QSPI,但可能有所扩展
XIP (执行时位置)实现方式
FSMC-XIP实现
// FSMC配置NOR Flash映射
void FSMC_NOR_Init(void) {FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;FSMC_NORSRAMTimingInitTypeDef p;// 配置基本时序p.FSMC_AddressSetupTime = 0x06;p.FSMC_AddressHoldTime = 0x00;p.FSMC_DataSetupTime = 0x0B;// ...其他时序配置// 配置NOR控制器FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;// ...其他控制器配置FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);// 映射后可直接访问和执行,无需额外步骤
}// 代码执行示例
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
void ExecuteFromNOR(void) {// 直接跳转到NOR Flash中的代码Jump_To_Application = (pFunction)(0x60000000 + 0x1000); // 示例地址Jump_To_Application();
}
QSPI-XIP实现
// QSPI内存映射模式配置
void QSPI_MemoryMapped_Init(void) {QSPI_CommandTypeDef s_command;QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;// 配置读取命令s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; // 通常是0xEBs_command.AddressMode = QSPI_ADDRESS_4_LINES;s_command.AddressSize = QSPI_ADDRESS_24_BITS;s_command.DataMode = QSPI_DATA_4_LINES;// ...其他命令配置// 配置内存映射参数s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;// 启用内存映射模式HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg);// 此时Flash已映射到地址空间,可以执行代码
}// 代码执行示例
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
void ExecuteFromQSPI(void) {// 使能Cache以提高XIP性能SCB_EnableICache();SCB_EnableDCache();// 跳转到QSPI映射区域的代码Jump_To_Application = (pFunction)(0x90000000 + 0x1000); // 示例地址Jump_To_Application();
}
OSPI-XIP实现
// OSPI内存映射模式配置 (STM32H7系列示例)
void OSPI_MemoryMapped_Init(void) {OSPI_RegularCmdTypeDef sCommand;OSPI_MemoryMappedTypeDef sMemMappedCfg;// 配置读取命令 (8线模式)sCommand.OperationType = HAL_OSPI_OPTYPE_READ_CFG;sCommand.FlashId = HAL_OSPI_FLASH_ID_1;sCommand.Instruction = OCTO_READ_CMD; // 例如0x8B/0xECsCommand.InstructionMode = HAL_OSPI_INSTRUCTION_8_LINES;sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;sCommand.AddressMode = HAL_OSPI_ADDRESS_8_LINES;sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS;sCommand.DataMode = HAL_OSPI_DATA_8_LINES;// ...其他命令配置// 配置内存映射参数sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;// 启用OSPI内存映射模式HAL_OSPI_MemoryMapped(&hospi, &sCommand, &sMemMappedCfg);// 此时可以直接执行映射区域的代码
}// 代码执行示例
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
void ExecuteFromOSPI(void) {// 使能Cache以提高XIP性能SCB_EnableICache();SCB_EnableDCache();// 跳转到OSPI映射区域的代码Jump_To_Application = (pFunction)(0x90000000 + 0x1000); // 示例地址Jump_To_Application();
}
性能与应用对比
XIP性能对比
-
访问延迟:
- FSMC: 低延迟,但总体带宽受限
- QSPI: 首次访问延迟高,但连续读取性能好
- OSPI: 首次访问延迟较高,但连续读取性能最佳
-
缓存影响:
- 三种接口都受益于CPU缓存
- 对于QSPI/OSPI,缓存几乎是必需的
- STM32H7还为QSPI/OSPI提供了专用的ART加速器
-
代码执行速度:
- FSMC: ~15-30MB/s
- QSPI: ~30-50MB/s
- OSPI: ~80-200MB/s
适用场景
-
FSMC:
- 需要兼容旧设备
- 需要简单直接的访问方式
- 接口引脚数量不受限
-
QSPI:
- 需要节省PCB空间(较少引脚)
- 中等执行性能要求
- 大多数现代系统选择
-
OSPI:
- 高性能应用
- 运行复杂应用程序
- 需要支持大容量闪存
总结
FSMC、QSPI和OSPI代表了嵌入式系统外部存储接口的发展历程:从并行到串行,从单线到多线。在内存映射和XIP方面,三种接口都支持,但实现复杂度和性能各不相同。对于现代STM32应用,QSPI和OSPI因其更好的性能/空间比和灵活性而成为更流行的选择,特别是对于需要执行复杂代码的应用程序。