大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是在FDCB里使能串行NOR Flash的Continuous read模式。
前面关于串行Flash传输时序的文章 《Fast Read Quad I/O SDR模式》 与 《Fast Read Quad I/O DTR模式》, 痞子衡介绍的其实都属于经典SPI工作模式大类下的Non-Continuous read传输模式,即任何独立的Fast Read Quad I/O读数据时序(一次CS低有效期间),都必须由Command子序列(命令码0xEB/0xEC/0xED/0xEE)先行,且不管是SDR还是DTR模式,命令码都是要在8个SCK周期内由IO0信号进行传输(别小看这8个SCLK周期,对于小数据块读取时序,它在总传输时间里占比是不可忽视的)。
我们知道在XIP情况下CPU从Flash里取指令数据往往是非常随机且零碎无序的,这时候虽然有L1 Cache和和FlexSPI Prefetch Buffer加速,但如果还想再进一步提升访问性能,就只能从Flash底层传输序列里想办法了。Flash读时序里有五大子序列CMD + ADDR + MODE + DUMMY + READ,其中除了CMD和DUMMY子序列是固定的,其他子序列参数值都可能会变,会变的就不能被优化,所以只能想办法在CMD和DUMMY子序列里做文章。今天痞子衡要介绍的Continuous read模式就是拿CMD子序列开刀:
一、什么是Continuous read模式?
Continuous read顾名思义就是连续读。在串行Flash世界里,连续读的意思是读传输时序里除了第一次CS有效期必须传输Command子序列,其后的读传输时序里均省去Command子序列。下面痞子衡结合i.MXRT的FlexSPI外设来对比介绍Non-Continuous read与Continuous read模式的区别:
1.1 FlexSPI的XIP Enhanced Mode
我们知道NOR Flash因为支持主设备随机读取其任意地址处的数据,因此从原理上可以用作XIP设备。但因为是串行接口,所以不能直接XIP(没有独立并行地址线,CPU无法直接寻址),需要FlexSPI外设在底层完成AHB总线读访问的实时响应工作,这个实时响应工作就是FlexSPI的XIP特性。
FlexSPI的XIP特性可以支持任意串行NOR Flash,对Flash厂商设计没要求。为了提升XIP代码执行效率,FlexSPI中也集成了XIP Enhanced Mode特性(其实就是Continuous read模式),见下图,CS1是包含CMD子序列的读时序(即第一次CS),CS2/3(包括后续所有CS)相比CS1少了CMD子序列,这就是Continuous read访问时序。
FlexSPI的XIP Enhanced Mode特性并不能够用于任意串行NOR Flash,这对Flash厂商设计有要求,必须Flash本身支持Continuous read模式才行。
1.2 Fast Read Quad I/O Continuous read时序
了解了XIP Enhanced Mode,我们再来看LUT里Quad I/O Read SDR Continuous read传输序列,它由CMD_SDR + RADDR_SDR + MODE8_SDR + DUMMY_SDR + READ_SDR + JMP_ON_CS + STOP七个子序列组成,如下表所示。
这个Continuous read传输序列相比Non-Continuous read传输时序主要有两处区别:
1. 原MODE8_SDR子序列里参数值不同:这个参数值用于通知Flash器件当前传输类型(Non-Continuous read/Continuous read),具体数值由Flash厂商定义。下图是以Cypress S25FS-S系列Flash为例的,0xA0表明Flash需进入/保持Continuous read模式。
2. 新增了JMP_ON_CS子序列:该子序列是FlexSPI外设实现Continuous read的核心,第一次CS有效传输时序里CMD_SDR子序列命令码会被自动存在该子序列参数值里,这样后续传输FlexSPI就不用再发命令码了。
LUT中Quad I/O Read DDR Continuous read传输序列如下,差异与前面SDR下的分析一致,这里不予赘述。
二、不同Flash厂商关于Continuous read特性设计
现在跟着痞子衡去看几家主流Flash厂商关于Continuous read特性的设计(如果你想快速确认某一款型号Flash是否支持这个特性,找到其数据手册搜索"Continuous read"看有没有如下时序图):
2.1 赛普拉斯S25FS-S系列
MODE子序列里参数值M[7:4]通过包含/不包含Command子序列来控制下一次读传输时序的长度,M[7:4] = 0xA则进入/保持Continuous Read模式,否则不进入/退出。
2.2 Adesto AT25SL系列
MODE子序列里参数值M[7:4] = 0xA则进入/保持Continuous Read模式,否则不进入/退出。
2.3 芯成IS25WP系列
MODE子序列里参数值M[7:4] = 0xA则进入/保持AX Read模式(就是Continuous Read),否则不进入/退出。
2.4 华邦W25QxxJV-DTR系列
MODE子序列里参数值M[5:4] = 2'b10则进入/保持Continuous Read模式(有的型号上也叫Read Command Bypass Mode,比如W25QxxJW-DTR),否则不进入/退出。如果要退出Continuous Read模式,Flash数据手册里特别推荐下一次时序里命令码临时设为0xFF,以保证M4=1使得Flash彻底回到Non-Continuous Read模式。
Note: 华邦Flash型号丝印后缀为IQ,则不支持Continuous Read模式;为IM则支持。
2.5 兆易创新GD25Q系列
MODE子序列里参数值M[5:4] = 2'b10则进入/保持Continuous Read模式,否则不进入/退出。
三、在i.MXRT1170-EVK上实战(IS25WP128)
了解了上面关于Continuous read模式知识后,我们在恩智浦i.MXRT1170-EVK板子上实践一下。默认连接的Flash是IS25WP128,这款Flash是支持Continuous read模式的,我们随便在SDK包里找一个XIP例程,修改工程里 evkmimxrt1170_flexspi_nor_config.c 文件里的 FDCB 启动头如下(主要就是改LUT表),改完下载程序进Flash运行,代码执行效率应该会有所提升(等下一篇QPI模式文章写完,痞子衡会设计一个用例一起来实测下性能)。
const flexspi_nor_config_t qspiflash_config_100mhz_sdr_cont = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
.csHoldTime = 3u,
.csSetupTime = 3u,
// Enable Safe configuration
.controllerMiscOption = 0x10,
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_4Pads,
.serialClkFreq = kFlexSpiSerialClk_100MHz,
.sflashA1Size = 16u * 1024u * 1024u,
.lookupTable =
{
// Fast Read Quad I/O LUTs
[4*CMD_LUT_SEQ_IDX_READ + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
// MODE8_SDR里参数值填入0xA0
[4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(MODE8_SDR, FLEXSPI_4PAD, 0xA0, DUMMY_SDR, FLEXSPI_4PAD, 0x04),
// 增加JMP_ON_CS子序列
[4*CMD_LUT_SEQ_IDX_READ + 2] = FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_4PAD, 0x04, JMP_ON_CS, FLEXSPI_1PAD, 0x01),
[4*CMD_LUT_SEQ_IDX_READ + 3] = FLEXSPI_LUT_SEQ(STOP, FLEXSPI_1PAD, 0x00, 0, 0, 0),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.blockSize = 256u * 1024u,
.isUniformBlockSize = false,
};
至此,在FDCB里使能串行NOR Flash的Continuous read模式痞子衡便介绍完毕了,掌声在哪里~~~