痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

痞子衡 發表於 2021-04-20

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是在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(迴環)。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  再來看FlexSPI的輸出時序圖(FlexSPI給Flash傳送地址,模式等)。左邊是SDR模式,Flash器件應在SCK的上沿去鎖存DATA (SIO)上的資料。右邊是DDR模式,Flash器件需要在SCK的上沿和下沿都去鎖存DATA (SIO)上的資料。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

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

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  從引腳訊號上來看,完整Quad I/O Read DDR傳輸時序如下圖所示。下圖是以兩片四線S25FS512S組parallel mode(八線)來示例的。如果是常見的individual mode,我們僅關注PCSA1相關的訊號時序即可。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

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週期的一半

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

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就是這麼設計的)。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  具體SCK能配到多高的頻率跟FlexSPI模組一個暫存器的配置值有關,即FlexSPI->MCR0[RXCLKSRC],RXCLKSRC配置的是DQS訊號的來源,DQS訊號一共有三種來源:無DQS自迴環(支援的SCK頻率最低),有DQS自迴環(支援的SCK頻率升高),來自外部Flash器件的DQS引腳(支援的SCK頻率最高)

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  那麼RXCLKSRC三種配置下,SCK分別能達到多高頻率呢?這需要檢視i.MXRT晶片的datasheet,在 FlexSPI input/read timing 小節裡有詳細介紹,痞子衡整理如下:

Flash工作模式 RXCLKSRC = 0 RXCLKSRC = 1 RXCLKSRC = 3
SDR SCK最高60MHz SCK最高133MHz SCK最高166MHz
DDR SCK最高30MHz SCK最高66MHz SCK最高166MHz

二、在客戶問題中實戰

  瞭解了上面DTR模式基礎知識後,我們去恩智浦官方論壇找兩個相關問題實踐一下。

2.1 Flash型號IS25LP064A

  先來看第一個問題 《i.MX RT1021 + IS25LP064A XIP flash in DDR mode settings》,這個客戶使用的Flash型號是IS25LP064A,客戶已經修改了FDCB頭,但是他犯了一個比較嚴重的錯誤,他使用了CMD_DDR來傳送命令而不是CMD_SDR,這顯然不符合Flash時序規範。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  此外,該款Flash在DTR模式下最高能支援到66MHz,客戶在FDCB裡配置SCK頻率為 kFlexSpiSerialClk_60MHz 是沒問題的,這個速度下DTR模式需要4個SCK週期做Dummy Cycle,Flash器件裡的預設值3按說不符合要求,但實測啟動也沒問題。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  下面痞子衡給一個適用的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數是一樣的。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  IS25WP064D預設6個Dummy Cycle下對應最高DTR工作頻率是69MHz,這已經達FlexSPI外設最高支援的DTR頻率上限了,因此不需更改Flash裡的Dummy Cycle設定了。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式

  下面痞子衡給一個適用的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主頁知乎主頁微信公眾號 平臺上。

微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

痞子衡嵌入式:在i.MXRT啟動頭FDCB裡使能序列NOR Flash的DTR模式