[APM32F4] 给外部 Flash 安个家!——APM32F427 QSPI XIP 内存映射轻松就搞定!

[复制链接]
202|4
kai迪皮 发表于 2025-11-18 14:43 | 显示全部楼层 |阅读模式
flash, spi, , , ,
[i=s] 本帖最后由 kai迪皮 于 2025-11-19 14:11 编辑 [/i]

还记得我们之前APM32F427,我为什么要选你??提到过 APM32F427 支持 QSPI XIP 吗?这次,我们就来看看它究竟怎样把外部 Flash“搬”进 MCU 地址空间,一起玩转 XIP 吧!

1. QSPI XIP 是个啥??

• QSPI(Quad SPI)和普通 SPI 的主要区别在于:

– 数据线从原本的 MOSI/MISO 升级为 IO0~IO3 四线,速度噌噌往上飙。传统SPI通信与QSPI通信对比图:
image-20251118133129088.png

– 控制器提供指令、地址阶段的自动管理以及内存映射模式,更加“省心”。

• XIP (eXecute In Place) 就是 QSPI 内存映射的“王牌功能”。

– 传统 SPI:读写外部 Flash 时,每次都要软件发送指令、配置地址。烦!

– QSPI + XIP:把外部 Flash 直接映射到 MCU 地址空间,读数据就像读内存一样简单。
读取外部flash时,使用不同形式读取示意:

image-20251118134322974.png


2. 板载 W25Q16JV 外部 Flash

APM32F427 Tiny 板子上放了 W25Q16JV (16Mbit 容量),支持 Quad I/O、Fast Read 等多种读指令。只要采用正确的指令码、地址模式和 Dummy Cycle,就能高速访问它。


3. 驱动QSPI XIP内存映射流程(代码示例)

下面这部分源自APM32F4xx_DAL_SDK_V1.3.0中的示例工程,并基于“QSPI_ReadWrite”例程进行修改,演示如何实现W25Q16JV的擦除、写入、读取,以及如何进入XIP内存映射模式。

3.1 基础读写操作

还没上 XIP,就先测试基本的擦写流程,保证外部 Flash 的读写通路 OK。大致就几步:

  1. 擦除指定扇区。
  2. 写入测试数据。
  3. 再回读来对比。
  4. Check 成功则万事俱备。
    示例代码片段如下:
/* Erase sector */
FLASH_EraseSector(0);
LOG_Print("FLASH_EraseSector (Sector 0 erased).\r\n");
LOG_Print("Data read from offset 0 via QSPI. Dump rxBuffer:\r\n");
FLASH_ReadData(0, rxBuffer, BUFFER_SIZE);
PrintArray32((uint32_t *)rxBuffer, BUFFER_SIZE / sizeof(uint32_t));

/* Write data */
FLASH_WriteData(0, txBuffer, BUFFER_SIZE);
LOG_Print("Data written to offset 0 via QSPI. Dump txBuffer:\r\n");
PrintArray32((uint32_t *)txBuffer, BUFFER_SIZE / sizeof(uint32_t));

/* Read data */
FLASH_ReadData(0, rxBuffer, BUFFER_SIZE);
LOG_Print("Data read from offset 0 via QSPI. Dump rxBuffer:\r\n");
PrintArray32((uint32_t *)rxBuffer, BUFFER_SIZE / sizeof(uint32_t));

/* Compare data */
if (BufferCmp((uint8_t*)txBuffer, (uint8_t*)rxBuffer, BUFFER_SIZE) != true)
{
    BOARD_LED_On(LED3);
    LOG_Print("Data compare failed! Error_Handler.\r\n");
    Error_Handler();
}

LOG_Print("Data compare success!\r\n");

以上操作顺利完成,说明擦写过程完全没得问题。

3.2 一键切换 XIP 模式

基础读写没问题后,就可以开启 XIP。只需在 main.c 调用一个 FLASH_EnterXIPMode() 函数,它的核心是利用 QSPI 控制器的 MemoryMapped 功能:

void FLASH_EnterXIPMode(void)
{
    QSPI_XIPTypeDef xipConfig = {0};

    // 1) Instruction code: 0xEB (Quad I/O Fast Read)
    xipConfig.Instruction = 0xEB; 

    // 2) WrapCode: if not using wrap, set 0
    xipConfig.WrapCode = 0x00;

    // 3) Address size: 24 bits, suitable for W25Q16JV
    xipConfig.AddressSize = QSPI_XIP_ADDRESS_SIZE_24_BITS;

    // 4) InstructionMode: how instruction and address are transmitted
    //    e.g. QSPI_XIP_INSTRUCTION_STANDARD_INS_ADDR, QSPI_XIP_INSTRUCTION_FRF_INS_ADDR
    xipConfig.InstructionMode = QSPI_XIP_INSTRUCTION_STANDARD_INS;

    // 5) Instruction bit length
    xipConfig.InstructionSize = QSPI_XIP_INSTRUCTION_SIZE_8_BITS;

    // 6) FrameFormat: QUAD
    xipConfig.FrameFormat = QSPI_XIP_FRAME_FORMAT_QUAD;

    // 7) DummyCycles: typically 6~10 cycles for 0xEB in W25Q16JV
    xipConfig.DummyCycles = 6;

    // 8) Endianness: little-endian
    xipConfig.Endianness = QSPI_XIP_MEM_ACCESS_FORMAT_LITTLE_ENDIAN;

    // 9) ContinuousMode / PrefetchMode
    //    For higher performance, can enable them if needed
    xipConfig.ContinuousMode = ENABLE;
    xipConfig.PrefetchMode   = ENABLE;

    // Enable chip select, then call the library function to enter memory-mapped mode
    FLASH_ChipSelect(ENABLE);
    if (DAL_QSPIEx_MemoryMapped(&hqspi, &xipConfig) != DAL_OK)
    {
        Error_Handler();
    }
}

代码中的配置要点主要是根据连接的SPI flash参数所决定的:

image-20251118141544665.png

如图所示我们需要使用的模式是

  1. Fast Read Quad I/O:0xEB
  2. 地址是24Bit

等这个函数执行完,W25Q16JV 就“挂”在了地址 0x90000000 。此后,对该地址的访问会自动触发 READ 指令+地址+数据返回,无需编写更多指令/地址逻辑。可以像这样验证::

FLASH_EnterXIPMode();
LOG_Print("XIP mode enabled. External flash is mapped at 0x90000000.\r\n");
PrintArray32((uint32_t *)0x90000000, BUFFER_SIZE / sizeof(uint32_t));

只要打印出的数据和之前写进去的一样,就说明 XIP 成功啦!


4. 如何根据实验现象判断 XIP 是否成功

  1. 串口日志:read(0x90000000) 与原始写入数据完全吻合,妥妥的 XIP。

image-20251118141003265.png

  1. 调试器内存窗口(如 MDK、IAR):直接查看 0x90000000 区域,看到和 Flash 中相同的内容,毫无违和感。

image-20251118141157095.png


总结

APM32F427 通过 QSPI XIP,让外部 Flash 使用体验大幅提升:

– 免去频繁发送指令、设置地址的烦恼;
– 连续读速度快,代码逻辑简单。

当然,如果仅用于小数据量存储,XIP 可能不是必需。但一旦想实现就地执行代码(Execute In Place)或需要快速读取远超内部容量的数据,XIP 就能让项目如虎添翼。

这里是示例代码:upload 附件:QSPI_ReadXIP.zip,请放在APM32F4xx_DAL_SDK_V1.3.0\Examples\Board_APM32F427_Tiny\QSPI 目录下食用哦

 楼主| kai迪皮 发表于 2025-11-18 14:43 | 显示全部楼层
#申请原创#  @21小跑堂
作业粉碎机 发表于 2025-11-19 20:04 | 显示全部楼层
学习了,原来QSPI XIP可以直接把外部Flash映射到MCU地址空间,这样读写数据就像操作内存一样简单,赞!
尹小舟 发表于 2025-11-19 13:41 | 显示全部楼层
写的非常好,能否联系原厂提供下外部闪存的下载算法
Gfan 发表于 2025-11-19 17:45 | 显示全部楼层
尹小舟 发表于 2025-11-19 13:41
写的非常好,能否联系原厂提供下外部闪存的下载算法

哈喽~可以戳下方链接哈,会安排业务经理与您联系


>> 如果您有咨询需求,欢迎点击登记,极海会与您联系~


如遇技术问题,可前往 极海半导体开发者论坛


您需要登录后才可以回帖 登录 | 注册

本版积分规则

45

主题

300

帖子

11

粉丝
快速回复 在线客服 返回列表 返回顶部