凡亿教育-雅敏
凡事用心,一起进步
打开APP
公司名片
凡亿专栏 | Flash的DTR模式藏着什么玄机?
Flash的DTR模式藏着什么玄机?

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是在FDCB里使能串行NOR Flash的DTR模式

前两篇文章 《IS25WP系列Dummy Cycle设置》《IS25LP系列Dummy Cycle设置》, 痞子衡均是设置Flash的Fast Read Quad I/O SDR模式去启动的,但最近在恩智浦官方论坛上,有不止一个客户需要使能Flash的DTR模式去启动,他们似乎都遇到了小问题,难道DTR模式藏着什么玄机?走,跟痞子衡去瞧瞧:

一、什么是DTR模式?

DTR是Dual Transfer Rate的缩写,即在时钟信号SCK的双边沿均触发数据传输。DTR有时候跟另一个名词DDR会混用,DDR是Double Data Rate的缩写,反正这两个名词均表示双边沿触发的意思,跟SDR单边沿触发相比快了一倍(同等SCK频率下而言)。下面痞子衡结合i.MXRT的FlexSPI外设来对比介绍SDR模块与DDR模式的区别:

1.1 FlexSPI的DTR输入输出

下图是FlexSPI的输入时序图(FlexSPI从Flash读取存储数据)。左边是SDR模式,可以看到FlexSPI是在DQS的下沿才会去锁存一次SIO上的数据。右边是DDR模式,FlexSPI外设在DQS的上沿和下沿都会去锁存一次SIO上的数据。注意不管是SDR模块还是DDR模式,DQS信号都是与SCK同频的。

Note: 关于DQS信号的意义,可以去看痞子衡的旧文 《串行NOR Flash的DQS信号功能简介》,FlexSPI外设的DQS信号既可以来自真实的Flash器件输出,也可以从i.MXRT的DQS引脚loopback(回环)。

962d4b35ddcede29d03880cbb0eac6.png

再来看FlexSPI的输出时序图(FlexSPI给Flash发送地址,模式等)。左边是SDR模式,Flash器件应在SCK的上沿去锁存DATA (SIO)上的数据。右边是DDR模式,Flash器件需要在SCK的上沿和下沿都去锁存DATA (SIO)上的数据。

697ec6828c8798045d3701b90a6355.png1.2 Fast Read Quad I/O DTR时序

了解了SDR与DDR模式区别,我们再来看LUT里Quad I/O Read DDR传输序列,它由CMD_SDR + RADDR_DDR + MODE8_DDR + DUMMY_DDR + LEARN_DDR(可选) + READ_DDR + STOP七个子序列组成,如下表所示。

Note: 特别注意,虽然存在CMD_DDR子序列,但Quad I/O Read DDR传输下发送命令规定使用CMD_SDR子序列。

75cba2d1856b12fd83d6f714cc6d14.png

从引脚信号上来看,完整Quad I/O Read DDR传输时序如下图所示。下图是以两片四线S25FS512S组parallel mode(八线)来示例的。如果是常见的individual mode,我们仅关注PCSA1相关的信号时序即可。

461bfd2ec718c8e8bbef77f3bdc19c.png1.3 DTR下实际Dummy Cycle输出与LUT中设定值关系

从Flash器件端来看,实际Dummy Cycle输出数是跟SCK信号周期数一一对应的。在SDR模式下,在Dummy Cycle序列时间内,有多少个SCK周期,即是有多少个Dummy Cycle数,填进LUT的Dummy Cycle也是这个值,这个没有疑义。那么在DDR模式,填入LUT的Dummy Cycle值与SCK周期数是什么关系呢?翻看FlexSPI章节,在LUT指令集表格里有答案,此时Dummy Cycle值应该是实际SCK周期数的2倍(可能有+/-1,需要看Flash手册),这是因为LUT中Dummy Cycle值是与FlexSPI外设端的Serial Root Clk数一一对应的:在SDR模式下,Serial Root Clk周期等于SCK周期;而在DDR模式下,Serial Root Clk周期只有SCK周期的一半

b77c09fb6c3c07ed665da0bbd6320b.png1.4 DTR下支持的最高SCK频率

上面在讲Dummy Cycle值的时候提到了Serial Root Clk概念,这个其实就是FlexSPI模块本身的工作时钟,目前已量产的i.MXRT型号(包括i.MXRT1010/1020/1050/1060/1170),其FLEXSPI_CLK_ROOT最高频率均是332MHz(下表来自i.MXRT1050系列手册)。

在332MHz FLEXSPI_CLK_ROOT频率下,DTR模式SCK频率理论上最高可以到166MHz,这个没有疑义。但是SDR模式SCK频率理论上最高也是166MHz,因为SDR模式下,只保证了在166MHz FLEXSPI_CLK_ROOT频率下时序可靠(别问,问就是FlexSPI就是这么设计的)。

ebf70d410fd32f16a7586a8257bf33.png

具体SCK能配到多高的频率跟FlexSPI模块一个寄存器的配置值有关,即FlexSPI->MCR0[RXCLKSRC],RXCLKSRC配置的是DQS信号的来源,DQS信号一共有三种来源:无DQS自回环(支持的SCK频率最低),有DQS自回环(支持的SCK频率升高),来自外部Flash器件的DQS引脚(支持的SCK频率最高)

72cd3696463d4f21234e8a88e15740.png

那么RXCLKSRC三种配置下,SCK分别能达到多高频率呢?这需要查看i.MXRT芯片的datasheet,在 FlexSPI input/read timing 小节里有详细介绍,痞子衡整理如下:

Flash工作模式RXCLKSRC = 0RXCLKSRC = 1RXCLKSRC = 3SDRSCK最高60MHzSCK最高133MHzSCK最高166MHzDDRSCK最高30MHzSCK最高66MHzSCK最高166MHz二、在客户问题中实战

了解了上面DTR模式基础知识后,我们去恩智浦官方论坛找两个相关问题实践一下。

2.1 Flash型号IS25LP064A

先来看第一个问题 《i.MX RT1021 + IS25LP064A XIP flash in DDR mode settings》,这个客户使用的Flash型号是IS25LP064A,客户已经修改了FDCB头,但是他犯了一个比较严重的错误,他使用了CMD_DDR来发送命令而不是CMD_SDR,这显然不符合Flash时序规范。

905f23a0a05c49cba7758ddba841e2.png

此外,该款Flash在DTR模式下最高能支持到66MHz,客户在FDCB里配置SCK频率为 kFlexSpiSerialClk_60MHz 是没问题的,这个速度下DTR模式需要4个SCK周期做Dummy Cycle,Flash器件里的默认值3按说不符合要求,但实测启动也没问题。

db3afed1d1f4a792953bca5791ba19.png

下面痞子衡给一个适用的FDCB头(50MHz SCK,DTR模式,LUT里等效Dummy Cycle值是0x2 + 0x4,即6个Dummy Cycle)。想同步修改Flash器件里的Dummy Cycle值去规范地调高SCK频率到60MHz,请参考 《IS25LP系列Dummy Cycle设置》

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {
            .tag              = FLEXSPI_CFG_BLK_TAG,
            .version          = FLEXSPI_CFG_BLK_VERSION,
            // 设置 FlexSPI->MCR0[RXCLKSRC] 为 1
            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
            .csHoldTime       = 3u,
            .csSetupTime      = 3u,
            // 使能 DDR 模式
            .controllerMiscOption = kFlexSpiMiscOffset_DdrModeEnable | kFlexSpiMiscOffset_SafeConfigFreqEnable,
            .sflashPadType    = kSerialFlash_4Pads,
            // 设置 DDR 模式下工作频率
            .serialClkFreq    = kFlexSpiSerialClk_50MHz,
            .sflashA1Size     = 8u * 1024u * 1024u,
            .lookupTable =
                {
                    // Read LUTs
                    [4*CMD_LUT_SEQ_IDX_READ]     = FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_1PAD, 0xED, RADDR_DDR, FLEXSPI_4PAD, 0x18),
                    // MODE8_DDR子序列等效2个cycle,DUMMY_DDR子序列里还需设置4个cycle,总计3个SCK周期
                    [4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(MODE8_DDR, FLEXSPI_4PAD, 0x00, DUMMY_DDR, FLEXSPI_4PAD, 0x04),
                    [4*CMD_LUT_SEQ_IDX_READ + 2] = FLEXSPI_LUT_SEQ(READ_DDR,  FLEXSPI_4PAD, 0x04, STOP,      FLEXSPI_1PAD, 0x00),
                },
        },
    .pageSize           = 256u,
    .sectorSize         = 4u * 1024u,
    .blockSize          = 64u * 1024u,
    .isUniformBlockSize = false,
};
2.2 Flash型号IS25WP064D

再来看第二个问题 《i.MX RT106x + IS25WP064D QSPI DDR mode》,这个客户使用的Flash型号是IS25WP064D,客户也修改好了FDCB头,由于Flash器件本身最高能支持80MHz DTR模式,于是这个客户就想在FDCB里将SCK频率设为 kFlexSpiSerialClk_80MHz,但是Flash本身没有DQS信号,FlexSPI端仅能从DQS引脚loopback,这种情况下FlexSPI最高仅能支持66MHz DTR,这显然不符合FlexSPI规范。

痞子衡特别注意到,这款IS25WP064D与上一个客户用的IS25LP064A在时序上尤其是Dummy Cycle上有明显的区别。同样SCK频率下,IS25LP064A下SDR与DDR模式的Dummy Cycle是两倍关系,但是IS25WP064D下SDR与DDR模式的Dummy Cycle数是一样的。

76687dc9846456c8de821df01f99fc.png

IS25WP064D默认6个Dummy Cycle下对应最高DTR工作频率是69MHz,这已经达FlexSPI外设最高支持的DTR频率上限了,因此不需更改Flash里的Dummy Cycle设置了。

9cbcada2b895031a024ea1c2b8c8b6.png

下面痞子衡给一个适用的FDCB头(60MHz SCK,DTR模式,LUT里等效Dummy Cycle值是0x2 + 0xa,即12个Dummy Cycle)。

const flexspi_nor_config_t qspiflash_config = {
    .memConfig =
        {
            .tag              = FLEXSPI_CFG_BLK_TAG,
            .version          = FLEXSPI_CFG_BLK_VERSION,
            // 设置 FlexSPI->MCR0[RXCLKSRC] 为 1
            .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
            .csHoldTime       = 3u,
            .csSetupTime      = 3u,
            // 使能 DDR 模式
            .controllerMiscOption = kFlexSpiMiscOffset_DdrModeEnable | kFlexSpiMiscOffset_SafeConfigFreqEnable,
            .sflashPadType    = kSerialFlash_4Pads,
            // 设置 DDR 模式下工作频率
            .serialClkFreq    = kFlexSpiSerialClk_60MHz,
            .sflashA1Size     = 8u * 1024u * 1024u,
            .lookupTable =
                {
                    // Read LUTs
                    [4*CMD_LUT_SEQ_IDX_READ]     = FLEXSPI_LUT_SEQ(CMD_SDR,   FLEXSPI_1PAD, 0xED, RADDR_DDR, FLEXSPI_4PAD, 0x18),
                    // MODE8_DDR子序列等效2个cycle,DUMMY_DDR子序列里还需设置10个cycle,总计6个SCK周期
                    [4*CMD_LUT_SEQ_IDX_READ + 1] = FLEXSPI_LUT_SEQ(MODE8_DDR, FLEXSPI_4PAD, 0x00, DUMMY_DDR, FLEXSPI_4PAD, 0x0a),
                    [4*CMD_LUT_SEQ_IDX_READ + 2] = FLEXSPI_LUT_SEQ(READ_DDR,  FLEXSPI_4PAD, 0x04, STOP,      FLEXSPI_1PAD, 0x00),
                },
        },
    .pageSize           = 256u,
    .sectorSize         = 4u * 1024u,
    .blockSize          = 64u * 1024u,
    .isUniformBlockSize = false,
};

至此,在FDCB里使能串行NOR Flash的DTR模式痞子衡便介绍完毕了,掌声在哪里~~~


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表凡亿课堂立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。
相关阅读
进入分区查看更多精彩内容>
精彩评论

暂无评论