一、FlexSPI的DQS信號作用
文章中沒有提及四線 QSPI Flash,因為一般的四線 QSPI Flash 芯片并沒有 DQS 信號引腳。FlexSPI 模塊的 DQS 信號當然可以用來連接 Octal Flash、Hyper Flash 上的 DQS 引腳,那么對于四線 QSPI Flash,這個 DQS 信號就沒有作用了嗎?其實不是的。
我們翻開 i.MXRT1170 的數據手冊(Data Sheet)找到 FlexSPI parameters 小節里的如下內容,就很清楚了。FlexSPIn_MCR0[RXCLKSRC] 位對應了三種 DQS 信號源設置:0x0 - Dummy read strobe looped back internally 設置即完全不用 DQS 引腳(可作它用),對應最高 60MHz SDR 訪問速度;0x1 - Dummy read strobe looped back through the DQS pad 設置即從 DQS 引腳上回環,因此 DQS 引腳需要懸空,對應最高 133MHz SDR 訪問速度;0x3 - Read strobe from memory device DQS pad 設置即接到存儲芯片 DQS 引腳上,對應最高 166MHz SDR 訪問速度;
? Dummy read strobe generated by FlexSPI controller and looped back internally (FlexSPIn_MCR0[RXCLKSRC] = 0x0)
? Dummy read strobe generated by FlexSPI controller and looped back through the DQS pad (FlexSPIn_MCR0[RXCLKSRC] = 0x1)
? Read strobe provided by memory device and input from DQS pad (FlexSPIn_MCR0[RXCLKSRC] = 0x3)
二、哪些FlexSPI引腳組不支持DQS?
目前恩智浦已量產的所有 i.MXRT 型號里(RT500/600/1010/1015/1020/1050/1060/1160/1170),大部分的 FlexSPI 引腳組合都是包含 DQS 信號設計的,只有如下兩個例外。沒有 DQS 信號的引腳組合連 Flash 時,應配置 FlexSPIn_MCR0[RXCLKSRC] 為 0x0 - looped back internally。
2.1 i.MXRT600 FlexSPI0 PortB
2.2 i.MXRT1160/1170 FlexSPI2 2nd PortA
三、使能沒有DQS的FlexSPI連接的Flash
對于不含 DQS 信號的 FlexSPI 引腳組合,使用恩智浦相關工具操作連接在其上的 NOR Flash 是需要做一些改動的,我們以 i.MXRT1170-Validation 板卡為例來介紹具體改動。
i.MXRT1170-Validation 板卡是專供恩智浦內部使用的,分為 CPU1/2/3/4 四款,每款的硬件連接不同,其中 CPU2 板卡在 FlexSPI2 2nd PortA 上連接了一顆鎂光的 MT25QL128:
3.1 SDK中FlexSPI擦寫Flash例程改動
我們現在打開 SDK 里的 FlexSPI 例程,這個例程是針對 MIMXRT1170-EVK 板卡寫的,在 EVK 上 NOR Flash 默認是連在 FlexSPI1 1st PortA 上的,因此我們需要對例程做一些改動。
例程路徑:\\SDK_2.x.x_MIMXRT1170-EVK\\boards\\evkmimxrt1170\\driver_examples\\flexspi\\nor\\polling_transfer\\cm7
首當其沖的改動當然是 pin_mux.c 文件里的 BOARD_InitPins() 函數,需要將 FlexSPI1 1st Pinmux 換成 FlexSPI2 2nd Pinmux:
void BOARD_InitPins(void)
{
CLOCK_EnableClock(kCLOCK_Iomuxc);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS, 1U);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B, 1U;
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK, 1U);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00, 1U);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01, 1U);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02, 1U);
//IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B2_11_FLEXSPI1_A_DATA03, 1U);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_05_FLEXSPI1_A_DQS, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_06_FLEXSPI1_A_SS0_B, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_07_FLEXSPI1_A_SCLK, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_08_FLEXSPI1_A_DATA00, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_09_FLEXSPI1_A_DATA01, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_10_FLEXSPI1_A_DATA02, 0x0AU);
//IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B2_11_FLEXSPI1_A_DATA03, 0x0AU);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_00_FLEXSPI2_A_SS0_B, 1U;
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_01_FLEXSPI2_A_SCLK, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_02_FLEXSPI2_A_DATA00, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_03_FLEXSPI2_A_DATA01, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_04_FLEXSPI2_A_DATA02, 1U);
IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_05_FLEXSPI2_A_DATA03, 1U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_00_FLEXSPI2_A_SS0_B, 0x0AU);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_01_FLEXSPI2_A_SCLK, 0x0AU);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_02_FLEXSPI2_A_DATA00, 0x0AU);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_03_FLEXSPI2_A_DATA01, 0x0AU);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_04_FLEXSPI2_A_DATA02, 0x0AU);
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_05_FLEXSPI2_A_DATA03, 0x0AU);
}
然后再改一下 app.h 文件里的宏定義,從 FlexSPI1 換到 FlexSPI2,并相應調整 Flash 屬性(EVK 上是 IS25WP128,Validation 板上是 MT25QL128),以及更新 flexspi_clock_init() 函數:
//#define EXAMPLE_FLEXSPI FLEXSPI1
//#define EXAMPLE_FLEXSPI_AMBA_BASE FlexSPI1_AMBA_BASE
//#define EXAMPLE_FLEXSPI_CLOCK kCLOCK_Flexspi1
#define EXAMPLE_FLEXSPI FLEXSPI2
#define EXAMPLE_FLEXSPI_AMBA_BASE FlexSPI2_AMBA_BASE
#define EXAMPLE_FLEXSPI_CLOCK kCLOCK_Flexspi2
static inline void flexspi_clock_init(void)
{
// 在 BOARD_BootClockRUN() 函數里給 FlexSPI 設置的時鐘源是 OSC_RC_48M_DIV2 / 2 即 12MHz
// 這里沒有再次分頻,因此 FlexSPI root clock 就是 12MHz
//CLOCK_SetRootClockDiv(kCLOCK_Root_Flexspi1, 2);
//CLOCK_SetRootClockMux(kCLOCK_Root_Flexspi1, 0);
CLOCK_SetRootClockDiv(kCLOCK_Root_Flexspi2, 2);
CLOCK_SetRootClockMux(kCLOCK_Root_Flexspi2, 0);
}
上面都是大家能意識到的改動,但其實最容易被忽略的改動是 flexspi_nor_flash_ops.c 文件里的 flexspi_nor_flash_init() 函數,config.rxSampleClock 設置必須要改成 kFLEXSPI_ReadSampleClkLoopbackInternally 才行。代碼全部改完之后下載運行就可以正常擦寫 Flash 了。
void flexspi_nor_flash_init(FLEXSPI_Type *base)
{
// 省略部分代碼 ...
flexspi_clock_init();
flexspi_config_t config;
FLEXSPI_GetDefaultConfig(&config);
config.ahbConfig.enableAHBPrefetch = true;
config.ahbConfig.enableAHBBufferable = true;
config.ahbConfig.enableReadAddressOpt = true;
config.ahbConfig.enableAHBCachable = true;
//config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad;
config.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;
FLEXSPI_Init(base, &config);
// 省略部分代碼 ...
}
3.2 SDK中Flashloader工程使用
現在我們再來用一下 SDK 里的 flashloader 工程,這個應用程序可以與恩智浦專用命令行上位機 blhost.exe 進行交互,工程需要用調試器下載進主芯片內部 RAM 運行
工程路徑:\\SDK_2.x.x_MIMXRT1170-EVK\\boards\\evkmimxrt1170\\bootloader_examples\\flashloader\\cm7
flashloader 運行起來之后,使用 blhost 工具按序執行下列命令,也一樣能對 Flash 進行擦寫:
blhost -u -- get-property 1
# 選中 FlexSPI2
blhost -u -- fill-memory 0x20000000 4 0xcf900002
blhost -u -- configure-memory 9 0x20000000
# 配置 NOR Flash(forced internal DQS)
blhost -u -- fill-memory 0x20000000 4 0xc1000053 # 其中bit[7:4]是關鍵設置!!!
blhost -u -- fill-memory 0x20000004 4 0x00110000
blhost -u -- configure-memory 9 0x20000000
blhost -u -- get-property 25 9
# 下載包含 IVT 頭的 App
blhost -u -- flash-erase-region 0x60000000 0x8000
blhost -u -- fill-memory 0x20000000 4 0xf000000f
blhost -u -- configure-memory 9 0x20000000
blhost -u -- write-memory 0x60001000 ivt_app.bin
上面命令序列里第二條 fill-memory 命令的參數 0xc1000053 是關鍵,從 flashloader 源代碼里看它其實是在設置 serial_nor_config_option_t.option0.B.misc_mode 為 kSerialNorEnhanceMode_InternalLoopback,這個設置對于四線 QSPI Flash 而言就是設 config->memConfig.readSampleClkSrc 為 kFlexSPIReadSampleClk_LoopbackInternally:
enum
{
kSerialNorEnhanceMode_Disabled = 0,
kSerialNorEnhanceMode_0_4_4_Mode = 1,
kSerialNorEnhanceMode_0_8_8_Mode = 2,
kSerialNorEnhanceMode_DataOrderSwapped = 3,
kSerialNorEnhanceMode_2ndPinMux = 4,
kSerialNorEnhanceMode_InternalLoopback = 5,
};
status_t parse_sfdp(uint32_t instance,
flexspi_nor_config_t *config,
jedec_info_table_t *tbl,
serial_nor_config_option_t *option)
{
status_t status = kStatus_InvalidArgument;
do
{
// 省略部分代碼...
uint8_t misc_mode = option- >option0.B.misc_mode;
if (misc_mode == kSerialNorEnhanceMode_Disabled)
{
// 省略部分代碼...
}
#if FLEXSPI_ENABLE_NO_CMD_MODE_SUPPORT
else if (misc_mode == kSerialNorEnhanceMode_0_4_4_Mode)
{
// 省略部分代碼...
}
#endif // FLEXSPI_ENABLE_NO_CMD_MODE_SUPPORT
else if (misc_mode == kSerialNorEnhanceMode_InternalLoopback)
{
config- >memConfig.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally;
}
else
{
// Do nothing
}
// 省略部分代碼...
} while (0);
return status;
}
3.3 下載工具MCUBootUtility配置
flashloader 的使用對一般客戶來說太復雜了,還是圖形化工具 MCUBootUtility 更方便,打開這個工具,按如下配置(主要就是圖中藍框圈起來的 Misc Mode 設置),也可以正常擦寫 Flash。熟悉這個工具原理的朋友應該知道它底層依賴得就是 3.2 節里的 flashloader 與 blhost。
3.4 SDK例程里的FDCB啟動頭改動
最后就是 SDK 里全部例程的 XIP build 都需要一個 FDCB 頭,這個頭定義在 evkmimxrt1170_flexspi_nor_config.c 文件里,這里也要改一下 readSampleClkSrc 和 serialClkFreq 配置才行。
const flexspi_nor_config_t qspiflash_config = {
.memConfig =
{
.tag = FLEXSPI_CFG_BLK_TAG,
.version = FLEXSPI_CFG_BLK_VERSION,
//.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad,
.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally,
.csHoldTime = 3u,
.csSetupTime = 3u,
.controllerMiscOption = 0x10,
.deviceType = kFlexSpiDeviceType_SerialNOR,
.sflashPadType = kSerialFlash_4Pads,
//.serialClkFreq = kFlexSpiSerialClk_133MHz,
.serialClkFreq = kFlexSpiSerialClk_60MHz,
.sflashA1Size = 16u * 1024u * 1024u,
.lookupTable =
{
// Read LUTs
FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18),
FLEXSPI_LUT_SEQ(MODE8_SDR, FLEXSPI_4PAD, 0x00, DUMMY_SDR, FLEXSPI_4PAD, 0x04),
FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_4PAD, 0x04, 0, 0, 0),
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
.ipcmdSerialClkFreq = 0x1,
.blockSize = 256u * 1024u,
.isUniformBlockSize = false,
};
-
RAM
+關注
關注
8文章
1368瀏覽量
114645 -
調試器
+關注
關注
1文章
303瀏覽量
23716 -
Flash存儲
+關注
關注
0文章
38瀏覽量
8288 -
QSPI接口
+關注
關注
0文章
14瀏覽量
3343
發布評論請先 登錄
相關推薦
評論