痞子衡嵌入式:关于i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区

  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区

  关于串行四线NOR Flash,当其作为启动(XiP)设备时,我们最常配置的读模式应该是 Fast Read Quad I/O SDR (0xEB),这种模式在数据传输时会用上全部四根I/O线(IO0-3),并且SCK可达最高频率(通常133MHz),这种读模式下Flash性能相当高。但有时候某些设计里为了保证通用性(比如我们想要一个兼容所有类型Flash型号的启动头),我们也会尝试配置最基础的读模式 Normal Read (0x03),基础的读模式在数据传输时仅使用一根I/O线(IO1),并且SCK频率通常最高50MHz,这种模式其实更多是为了兼容SPI接口的EEPROM器件。

  Normal Read是任何串行NOR Flash都支持的读模式,也是最简单的一种模式,但在i.MXRT的FlexSPI外设里配置这种模式会存在关于Dummy Cycle设置的一个小误区,且听痞子衡道来:

一、在FDCB里使能Normal Read

  关于FDCB及lookupTable相关知识详见痞子衡旧文 《从头开始认识i.MXRT启动头FDCB里的lookupTable》。现在我们尝试准备一个使能Normal read的FDCB头,Flash器件就以华邦W25Q64JWS-IQ为例,查看其数据手册,找到如下Normal read时序图:

痞子衡嵌入式:关于i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区

  从Normal read时序图里可以看出,其仅包含命令序列、地址序列、读数据序列、停止序列共四个子序列,与Fast Read Quad I/O SDR时序相比少了模式序列和Dummy序列,因此示例FDCB如下。经i.MXRT1050-EVKB板子实测,这个示例FDCB是可以正常用于启动的。

const flexspi_nor_config_t qspiflash_config = { .memConfig = { .tag = FLEXSPI_CFG_BLK_TAG, .version = FLEXSPI_CFG_BLK_VERSION, // 低速情况下可以使用LoopbackInternally .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally, .csHoldTime = 3u, .csSetupTime = 3u, .controllerMiscOption = 0x10, .deviceType = kFlexSpiDeviceType_SerialNOR, // 实际上这里不管设置1Pad/2Pads/4Pads,在iomuxc里都会配置IO0-3 .sflashPadType = kSerialFlash_1Pad, // 配置SCK频率不要超过50MHz .serialClkFreq = kFlexSpiSerialClk_50MHz, .sflashA1Size = 8u * 1024u * 1024u, .lookupTable = { // Normal Read LUTs // 包含四个子序列,且全是通过 FLEXSPI_1PAD 传输 [4*CMD_LUT_SEQ_IDX_READ + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x03, RADDR_SDR, FLEXSPI_1PAD, 0x18), [4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x00), }, }, .pageSize = 256u, .sectorSize = 4u * 1024u, .blockSize = 64u * 1024u, .isUniformBlockSize = false, };

  按照文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)》 第二小节里的软硬件测试环境,我们测试无缓存下的 memcpy((void *)0x20200000, (void *)0x60002400, 8); 语句执行在Flash端时序如下(为便于捕捉Flash信号,实际测试时SCK频率降到了30MHz):

痞子衡嵌入式:关于i.MXRT中FlexSPI外设lookupTable里配置Normal read的一个小误区

二、关于Dummy Cycle的小误区是什么?

  在配置Fast Read Quad I/O SDR时序的lookupTable里,我们常常会根据不同的Flash器件特性在Dummy子序列里填入不同的Cycle数值。现在我们配置的是Normal read时序,有人可能会保留Dummy子序列,但是将其参数值设0(如下代码所示),根据字面理解,这样似乎也没问题,但在FlexSPI外设里,这样是不行的,这就是关于Dummy Cycle的误区。

#include "fsl_flexspi.h" #define NOR_CMD_LUT_SEQ_IDX_READ_NORMAL 0 uint32_t s_customLUT_wrong[4] = { /* Normal read mode -SDR */ [4*NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), // 保留kFLEXSPI_Command_DUMMY_SDR序列,但参数值填0 [4*NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x00, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), [4*NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 2] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00, 0, 0, 0), }; 三、Dummy Cycle设0的误区带来什么后果?

  使用第二小节里的 s_customLUT_wrong[] 去配置FlexSPI LUT到底会产生什么后果,我们继续在文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)》 第二小节里的软硬件测试环境下抓一下时序图。可先借助SDK里flexspi驱动如下两个函数来更新LUT,因为是在XiP环境下执行的ramfunc代码,所以无需再从头初始化FlexSPI模块。

#include "fsl_flexspi.h" /* Update LUT table. */ FLEXSPI_UpdateLUT(FLEXSPI, 0, s_customLUT_wrong, 4); /* Do software reset. */ FLEXSPI_SoftwareReset(FLEXSPI);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzfxdy.html