痞子衡嵌入式:在i.MXRT1170上啟動含DQS的Octal Flash可不嚴格設Dummy Cycle (以MT35XU512為例)
- 2021 年 12 月 10 日
- 筆記
- D2.單片機i.MXRT-CM7
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是Octal或Hyper Flash上DQS信號與Dummy Cycle聯繫。
關於在 i.MXRT 上啟動 NOR Flash 時如何設置正確的 Dummy Cycle 值,痞子衡一共寫過四篇文章:《IS25WP系列Dummy Cycle設置》、《IS25LP系列Dummy Cycle設置》、《Dummy Cycle設置為0的誤區》、《DTR模式下Dummy Cycle設置》, 這四篇文章都是針對普通 QuadSPI 型 Flash 而言的(一般沒有 DQS 信號)。而如果在 i.MXRT 上啟動的是包含 DQS 信號的 Octal Flash 或者 Hyper Flash,此時 Dummy Cycle 設置有什麼不同之處呢?今天痞子衡就和大家聊聊這個話題:
一、Flash讀時序中DQS與Dummy Cycle作用
我們知道對於普通 QuadSPI 型 Flash,在 FlexSPI 模塊 LUT 里配置讀時序時,其中 Dummy Cycle 子序列中填的值必須要與 Flash 端的 Dummy Cycle 嚴格一致,否則會發生時序錯亂(如下圖 Extended 時序所示,圖中是單線模式,四線模式類似)。
Flash 里一般都會開放寄存器給用戶去配置 Dummy Cycle 值,Flash 工作頻率越高,所需的最小 Dummy Cycle 也越大(可以理解為 Flash 存儲體從接收到讀命令開始到輸出有效數據這一段時間間隔是恆定的,而我們衡量時間的基準是連接到 Flash 的 SCK,SCK 頻率越高,相同間隔內所需 SCK 周期數就越多)。
- Note1: 簡單來說,Dummy Cycle 就是 Flash 響應主機每一次讀時序所需要的準備時間,在 NOR Flash 上這個時間是固定且可設的,跟訪問地址無關。
- Note2: 一個確定的 Dummy Cycle 值決定了 Flash 上限工作頻率,但此時 Flash 並不是只能在這個上限頻率下工作,低於這個上限頻率均可以。
DQS 信號正常是為 OctalSPI / HyperBus 型 Flash 工作在八線 DTR 模式下同步 DQ[7:0] 線輸出而生的(見上圖 Octal DRR 時序),關於其基本概念詳見痞子衡舊文 《DQS信號簡介》。
- Note: 在 Hyper Flash 上負責 DQS 功能的信號是 RWDS。
當 OctalSPI / HyperBus 型 Flash 工作在 Octal DDR 模式下時,DQS/RWDS 信號會向主設備(這裡指 i.MXRT)提示 DQ[7:0] 何時有效,所以這時候 DQS 信號其實也兼備了 Dummy Cycle 的作用。不過考慮到有時候主設備端不一定會使能 DQS 信號,Dummy Cycle 的存在仍然是有必要的。
二、FlexSPI外設里DQS和Dummy Cycle聯繫
在 《FlexSPI外設的LUT機制》 和 《DTR模式下Dummy Cycle設置》 兩篇文章里有詳細的關於 FlexSPI 外設中 Dummy Cycle 設置方法和 DQS 引腳功能配置方法介紹,但是這兩者是怎樣的聯繫關係呢?
我們在 i.MXRT 參考手冊 FlexSPI 章節可以找到如下 Hyper Bus 讀時序示意圖(對於 Octal Flash 也基本適用,僅微小區別),這張圖很清晰地闡述了 RWDS 信號與 Latency Count 的聯繫,FlexSPI 外設在發起實際讀時序時一定會輸出 DUMMY_DDR 子序列里實際配置的延時周期,但如果配置的延時周期結束後,RWDS 有效信號還沒有到來,FlexSPI 會自動插入足夠的延時周期(即圖中所謂的 Additional Latency count)直到 RWDS 信號有效。
- Note: 在 Hyper Flash 上不用 Dummy Cycle 術語,其術語是 Latency Count。
基於這樣的設計,當在 FlexSPI 里啟動外部 DQS 信號時,我們在 DUMMY_DDR 子序列里只要象徵性地填一個比 Flash 里 Latency Count 稍小的值就行了,在一些 i.MXRT 型號上理想情況下甚至可以去除 DUMMY_DRR 子序列(即 Latency count 配 0),但切記這個值不應配得比 Flash 里 Latency Count 大。
三、在i.MXRT1170上實測MT35XU512
最近恩智浦 SE 團隊做了一個基於 i.MXRT1170 的 Auto Development Platform 原型板,在 FlexSPI1 上掛的是來自 Micron 的 Octal Flash – MT35XU512,這顆 Flash 作為代碼存儲與啟動設備。我們就在這個原型板上測試一下 FlexSPI 外設的 DQS 與 Dummy Cycle 不同配置能否去正常啟動 Flash。
3.1 MT35XU512基本情況
首先看一下這顆 Octal Flash 的基本情況,主要關注 DQS 和 Dummy Cycle 方面。Flash 內部有 256 個 8bit 的配置寄存器(address 從 0 – 255),其中 address 0 配置寄存器用於設置 Flash 工作模式(我們需要設為 0xE7,開啟 Octal DDR 且需要 DQS),address 1 配置寄存器用於設置 Dummy Cycle(可保持初值 0x00 不變,即使用默認 Dummy Cycle 值)。
再來看一下這顆 Octal Flash 所支持的讀命令,根據工作模式不同一共有 10 種命令,我們選用最後一條命令 4-byte DDR Octal I/O Fast Read(命令值 0xFD),這條讀命令可訪問全部 Flash 空間且性能最高,其對應的默認 Dummy Cycle 是 16。
默認 16 的 Dummy Cycle 能支持多高的 Flash 工作頻率呢,在下表裡可找到答案,前面我們選擇的是 DDR Octal I/O Fast Read 命令,所以對應最高工作頻率可達 171MHz。雖然 Flash 本身可跑 200MHz DDR,但是 i.MXRT1170 FlexSPI 外設最大支持到 166MHz DDR,這就是在前面保持 Flash 中 address 1 配置寄存器值為默認 Dummy Cycle 的原因,默認 Dummy Cycle 配置已經夠用了。
3.2 測試啟動頭FDCB
基於上面對 Octal Flash 的認識,我們很容易給出如下可用於啟動的 FDCB 頭,這個頭裡使能了 FlexSPI 端的外部 DQS 使用(octalflash_config.memConfig.readSampleClkSrc),開啟了 Flash 端的 Octal DDR 模式(octalflash_config.memConfig.deviceModeArg),LUT 里第一條時序配置的是 0xFD 讀命令,並且 DUMMY_DDR 子序列等效配置的是 3 個 Dummy Cycle,低於 Flash 里實際 16 個 Dummy Cycle,一切都符合上文的分析,這個啟動頭在板子上實測是可以工作的。
const flexspi_nor_config_t octalflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
.readSampleClkSrc = kFlexSPIReadSampleClk_ExternalInputFromDqsPad,
.csHoldTime = 3,
.csSetupTime = 3,
.deviceModeCfgEnable = 1,
.deviceModeType = kDeviceConfigCmdType_Spi2Xpi,
.waitTimeCfgCommands = 1,
.deviceModeSeq =
{
.seqNum = 1,
.seqId = 6,
.reserved = 0,
},
.deviceModeArg = 0xE7, /* Enable octal DDR mode */
.controllerMiscOption =
(1u << kFlexSpiMiscOffset_SafeConfigFreqEnable) | (1u << kFlexSpiMiscOffset_DdrModeEnable),
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_8Pads,
.serialClkFreq = kFlexSpiSerialClk_166MHz,
.sflashA1Size = 64ul * 1024u * 1024u,
.busyOffset = 0u,
.busyBitPolarity = 0u,
.lookupTable =
{
/* 4-BYTE DDR OCTAL I/O FAST READ */
[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_8PAD, 0xFD, RADDR_DDR, FLEXSPI_8PAD, 0x20),
// 這裡 DUMMY_DDR 里填入的值是 0x6,對應 3 個 SCK 周期的 dummy
[1] = FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_8PAD, 0x6, READ_DDR, FLEXSPI_8PAD, 0x04),
/* Read Status */
[4 * 1 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04),
/* Write Enable */
[4 * 3 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP_EXE, FLEXSPI_1PAD, 0x00),
/* Enable Octal DDR mode */
[4 * 6 + 0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x81, CMD_SDR, FLEXSPI_1PAD, 0x00),
[4 * 6 + 1] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x00, CMD_SDR, FLEXSPI_1PAD, 0x00),
[4 * 6 + 2] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x01, STOP_EXE, FLEXSPI_1PAD, 0x00),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.serialNorType = 0x2,
.blockSize = 128u * 1024u,
.isUniformBlockSize = false,
};
現在我們做多一些實驗,修改上述啟動頭裡的 readSampleClkSrc、serialClkFreq 和 DUMMY_DDR 子序列值,其餘配置保持不變,測試結果如下。這個結果基本是符合第二小節里關於DQS和Dummy Cycle聯繫關係的總結的。
readSampleClkSrc | serialClkFreq | lookupTable[1]中DUMMY_DDR數值 註:DDR下2N值對應Flash里N個dummy cycle |
Flash啟動情況 |
---|---|---|---|
LoopbackFromDqsPad | 30MHz – 100MHz | 0x20 | 正常啟動 |
30MHz – 100MHz | 非 0x20 | 無法啟動 | |
大於 100MHz | 0x20 | 無法啟動 | |
ExternalInputFromDqsPad | 30MHz | 無,0x1 – 0x23 | 正常啟動 |
30MHz | 大於 0x23 | 無法啟動 | |
166MHz | 0x2 – 0x25 | 正常啟動 | |
166MHz | 無,0x1,大於 0x25 | 無法啟動 |
至此,Octal或Hyper Flash上DQS信號與Dummy Cycle聯繫痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時發佈到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平台上。
微信搜索”痞子衡嵌入式“或者掃描下面二維碼,就可以在手機上第一時間看了哦。