痞子衡嵌入式:在i.MXRT启动头FDCB里使能串行NOR 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(回环)。

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

1.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子序列。

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

1.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周期的一半

1.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就是这么设计的)。

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

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

Flash工作模式RXCLKSRC = 0RXCLKSRC = 1RXCLKSRC = 3
SDRSCK最高60MHzSCK最高133MHzSCK最高166MHz
DDRSCK最高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时序规范。

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

  下面痞子衡给一个适用的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 = (1u << kFlexSpiMiscOffset_DdrModeEnable) | (1u << 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数是一样的。

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

  下面痞子衡给一个适用的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模式痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

痞子衡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值