《APM32芯得》系列的内容是用户使用APM32系列产品的体验总结。均转载自21ic论坛集海半导体专区。全文未经过任何形式的修改,未经原作者授权禁止转载。
1.什么是QSPI XIP?
• QSPI(Quad SPI)与普通SPI的主要区别是:
数据线由原来的MOSI/MISO升级为IO0~IO3四线,速度暴涨。传统SPI通信与QSPI通信对比图:
控制器提供指令和地址阶段的自动管理以及内存映射模式,让其更“省心”。
• XIP(就地执行)是QSPI 内存映射的“王牌功能”。
传统SPI:读写外部Flash时,软件每次都必须发送指令并配置地址。打扰!
QSPI + XIP:将外部Flash直接映射到MCU地址空间,读取数据就像读取内存一样简单。
读取外部Flash时,使用不同形式的读取指令:
2.板载W25Q16JV外接闪光灯
APM32F427 Tiny板具有W25Q16JV(16Mbit容量),支持Quad I/O、Fast Read等读取指令。可以使用正确的脚本、地址模式和虚拟周期对其进行高速访问。
3.驱动QSPI XIP内存映射过程(代码示例)
以下部分源自APM32F4xx_DAL_SDK_V1.3.0中的示例工程,并在“QSPI_ReadWrite”例程的基础上进行修改,演示如何实现W25Q16JV的擦除、写入和读取,以及如何进入XIP内存映射模式。
3.1 基本读写操作
在使用XIP之前,我们先测试一下基本的擦写流程,确保对外部Flash的读写访问是OK的。只需几个步骤:
1. 擦除指定扇区。
2.写入测试数据。
3. 回读并比较。
4. 如果检查成功,则一切准备就绪。
示例代码片段如下:
/* 擦除扇区*/
FLASH_EraseSector(0);
LOG_Print('FLASH_EraseSector (扇区0 已擦除)。');
LOG_Print('通过QSPI从偏移0处读取数据。转储rxBuffer: ');
FLASH_ReadData(0, rxBuffer, BUFFER_SIZE);
PrintArray32((uint32_t *)rxBuffer, BUFFER_SIZE/sizeof(uint32_t));
/* 写入数据*/
FLASH_WriteData(0, txBuffer, BUFFER_SIZE);
LOG_Print('数据通过QSPI 写入偏移量0。转储txBuffer: ');
PrintArray32((uint32_t *)txBuffer, BUFFER_SIZE/sizeof(uint32_t));
/* 读取数据*/
FLASH_ReadData(0, rxBuffer, BUFFER_SIZE);
LOG_Print('通过QSPI从偏移0处读取数据。转储rxBuffer: ');
PrintArray32((uint32_t *)rxBuffer, BUFFER_SIZE/sizeof(uint32_t));
/* 比较数据*/
if (BufferCmp((uint8_t*)txBuffer, (uint8_t*)rxBuffer, BUFFER_SIZE) !=true)
{
BOARD_LED_On(LED3);
LOG_Print('数据比较失败!Error_Handler.');
Error_Handler();
}
LOG_Print('数据比较成功!');
3.2 一键切换XIP模式
基本读写都ok后,就可以开启XIP了。只需调用main.c 中的FLASH_EnterXIPMode() 函数即可,该函数的核心利用了QSPI 控制器的MemoryMapped 功能:
无效FLASH_EnterXIPMode(无效)
{
QSPI_XIPTypeDef xipConfig={0};
//1) 指令代码:0xEB(四路I/O快速读取)
xipConfig.指令=0xEB;
//2) WrapCode: 如果不使用换行,则设置为0
xipConfig.WrapCode=0x00;
//3) 地址大小: 24位,适合W25Q16JV
xipConfig.AddressSize=QSPI_XIP_ADDRESS_SIZE_24_BITS;
//4)InstructionMode:指令和地址如何传输
//例如QSPI_XIP_INSTRUCTION_STANDARD_INS_ADDR、QSPI_XIP_INSTRUCTION_FRF_INS_ADDR
xipConfig.InstructionMode=QSPI_XIP_INSTRUCTION_STANDARD_INS;
//5) 指令位长度
xipConfig.InstructionSize=QSPI_XIP_INSTRUCTION_SIZE_8_BITS;
//6) FrameFormat: 四元组
xipConfig.FrameFormat=QSPI_XIP_FRAME_FORMAT_QUAD;
//7) DummyCycles: 在W25Q16JV 中通常为0xEB 6~10 个周期
xipConfig.DummyCycles=6;
//8) Endianness: 小端
xipConfig.Endianness=QSPI_XIP_MEM_ACCESS_FORMAT_LITTLE_ENDIAN;
//9) 连续模式/预取模式
//为了获得更高的性能,可以根据需要启用它们
xipConfig.ContinouslyMode=启用;
xipConfig.PrefetchMode=启用;
//使能片选,然后调用库函数进入内存映射模式
FLASH_ChipSelect(启用);
if (DAL_QSPIEx_MemoryMapped(hqspi, xipConfig) !=DAL_OK)
{
Error_Handler();
}
}
代码中的配置点主要根据所连接的SPI flash参数来确定:
如图所示,我们需要使用的模式是
1.快速读取四路I/O:0xEB
2.地址为24Bit
该函数执行后,W25Q16JV“挂起”在地址0x90000000处。此后访问该地址会自动触发READ指令+地址+数据返回,无需编写更多的指令/地址逻辑。这可以这样验证:
FLASH_EnterXIPMode();
LOG_Print('XIP模式已启用。外部闪存映射到0x90000000。');
PrintArray32((uint32_t *)0x90000000, BUFFER_SIZE/sizeof(uint32_t));
只要打印出来的数据和之前写入的数据一样,就说明XIP成功了!
4、如何根据实验现象判断XIP是否成功
1、串口日志:read(0x90000000)与原来写入的数据完全一致,妥妥的XIP。
2.调试器内存窗口(如MDK、IAR):直接查看0x90000000区域,看到的内容与Flash中相同,没有任何不和谐感。
总结
APM32F427通过QSPI XIP极大改善了外部Flash的使用体验:
免去频繁发送命令和设置地址的麻烦;
连续读取速度快,代码逻辑简单。
当然,如果只是用来存储少量数据,XIP可能就没有必要了。但一旦你想就地执行代码(Execute In Place)或者需要快速读取远远超出内部容量的数据,XIP就可以让项目如虎添翼。
注:文章作者在原帖中提供了代码文件,有需要请至原文21ic论坛原文地址:https://bbs.21ic.com/icview-3496231-1-1.html?_dsign=206adb5a
或点击下方阅读原文跳转
标题:使用极海APM32F427驱动QSPI XIP内存映射流程
链接:https://yqqlyw.com/news/sypc/62872.html
版权:文章转载自网络,如有侵权,请联系删除!