大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT三位數系列隱藏的FlexSPI Remap功能。
前段時間痞子衡寫了一篇文章 《利用i.MXRT1060,1010上新增的FlexSPI地址重對映(Remap)功能可安全OTA》,介紹了Remap功能在OTA設計中的重要性。如果你對比過i.MXRT三位數(RT500/600)和四位數(RT1xxx)的FlexSPI模組,你會發現它們是一樣的,暫存器定義幾乎完全一致。但是我們知道這兩個系列又分別是來自不同平臺(LPC/i.MX),i.MXRT三位數可沒有i.MXRT四位數上用於存放Remap控制的IOMUXC_GPR模組,那麼在i.MXRT500/600上到底有沒有Remap功能呢?本文痞子衡將為你解答。
1. FlexSPI NOR系統對映地址
老規矩還是先看一下FlexSPI在i.MXRT三位數上的系統對映空間。因為核心架構的差異,分配的對映地址與i.MXRT1xxx上完全不同。
i.MXRT500中分配給FlexSPI的系統對映空間如下,兩個FlexSPI各分配了128MB。
i.MXRT600中分配給FlexSPI的系統對映空間如下,一個FlexSPI分配了128MB。
2. FlexSPI Remap控制在哪裡?
目前我們已經可以從恩智浦官網下載到i.MXRT600的SDK軟體包和參考手冊,i.MXRT500的資料暫時還沒有公佈。對於i.MXRT600,無論是在SDK軟體包中的標頭檔案還是在參考手冊中搜尋“Remap”關鍵字,都搜不到任何資訊,莫非是沒有Remap功能?
好了,痞子衡就不賣關子了,其實Remap功能是支援的,而且直接做到了FlexSPI模組裡,控制暫存器也在FlexSPI裡,就在FLEXSPI BASE地址偏移0x420的地方(模組有更新,但文件暫時沒有同步更新):
typedef struct
{
__IO uint32_t HADDRSTART;
__IO uint32_t HADDREND;
__IO uint32_t HADDROFFSET;
} FLEXSPI_REMAP_Type;
#define FLEXSPI_REMAP ((FLEXSPI_REMAP_Type *)(FLEXSPI_BASE + 0x420u));
因為Remap控制嵌在FlexSPI模組暫存器裡,所以對於有兩個FlexSPI模組的i.MXRT500,Remap控制也有兩組,相互獨立,這點跟同樣有兩個FlexSPI模組的i.MXRT1060上Remap設計是不一樣的。
3. FlexSPI Remap功能設計
雖然i.MXRT500/600上的Remap控制嵌在FlexSPI模組內部,但Remap設計依然是屬於系統架構層面的,只是在AHB匯流排層面做一個地址重定向。下面是Remap控制暫存器:
Remap功能 | 對應控制暫存器 | |
---|---|---|
暫存器名 | 暫存器地址 | |
ADDR_START | HADDRSTART | FLEXSPI_BASE + 0x420 |
ADDR_END | HADDREND | FLEXSPI_BASE + 0x424 |
ADDR_OFFSET | HADDROFFSET | FLEXSPI_BASE + 0x428 |
Remap設計很簡單,就是地址(addr)落在[ADDR_START, ADDR_END]裡的AHB讀訪問,其實際訪問到的是addr + ADDR_OFFSET位置處的資料。(注意ADDR_START, ADDR_END, ADDR_OFFSET都是4KB對齊的)
Remap功能及暫存器定義上基本跟i.MX1xxx保持一致,但有一個小區別,就是HADDRSTART暫存器的bit0同時也承擔了Remap功能開關控制。
4. Remap對擦寫Flash的影響
啟用Remap功能後,呼叫FlexSPI NOR驅動函式去擦寫Flash不會受影響,擦寫Flash操作正常走的是FlexSPI IPG命令方式,資料沒有經過AHB bus。
下面這段測試程式碼是在MIMXRT500-EVK上跑的,用ROM API驅動擦寫0x08100000地址,擦寫操作前加了一段Remap設定干擾,實測下來Remap設定對擦寫沒有任何影響,復位後去讀Flash,操作的還是原0x08100000地址。
#define FLEXSPI0_REMAP ((FLEXSPI_REMAP_Type *)(FLEXSPI0_BASE + 0x420u));
flexspi_nor_config_t flashConfig;
serial_nor_config_option_t configOption;
configOption.option0.U = 0xc0403004;
uint32_t programBuffer[64];
for (uint32_t i = 0; i < sizeof(programBuffer); i++)
{
*((uint8_t *)programBuffer + i) = (uint8_t)(i & 0xFF);
}
g_bootloaderTree->flexspiNorDriver->get_config(1, &flashConfig, &configOption);
g_bootloaderTree->flexspiNorDriver->init(1, &flashConfig);
FLEXSPI0_REMAP->HADDRSTART = 0x08100000 | 0x01;
FLEXSPI0_REMAP->HADDREND = 0x08200000;
FLEXSPI0_REMAP->HADDROFFSET = 0x100000;
g_bootloaderTree->flexspiNorDriver->erase(1, &flashConfig, 0x100000, 0x100);
g_bootloaderTree->flexspiNorDriver->page_program(1, &flashConfig, 0x100000, programBuffer);
Remap暫存器因為在FlexSPI模組中,因此Remap設定程式碼要在FlexSPI模組初始化之後,僅有模組時鐘被開啟,模組暫存器才能正常賦值,否則不生效(實測時鐘不開啟,讀寫Remap暫存器永遠是0,並且不產生HardFault)。
5. 關於ROM API傳參的疑惑解釋
最後再簡單說一下第4節示例程式碼裡一點讓人疑惑的地方,我們是在MIMXRT500-EVK上做的測試,i.MXRT500有兩個FlexSPI(0/1),Flash是連在FlexSPI0上,但是ROM API裡的instance傳參竟然需要是1(i.MXRT1060 ROM API的FLEXSPI0傳參就是0),這是怎麼回事?
下面是i.MXRT500 BootROM中根據instance獲取FLEXSPI模組基址的函式程式碼,其是根據i.MXRT500標頭檔案中FLEXSPI_BASE_PTRS定義來獲取基址值的。
static FLEXSPI_Type *const g_flexSpiInstances[] = FLEXSPI_BASE_PTRS;
static FLEXSPI_Type *flexspi_get_module_base(uint32_t instance)
{
FLEXSPI_Type *baseAddr = NULL;
baseAddr = g_flexSpiInstances[instance];
return baseAddr;
}
而BootROM中用的i.MXRT500標頭檔案中FLEXSPI_BASE_PTRS定義如下所示,有點奇怪,跟正式SDK裡的定義不一致。其實也可以理解,BootROM是晶片設計階段的產物,那時候標頭檔案是初版,後期有變化也正常。
/** Array initializer of FLEXSPI peripheral base pointers */
#define FLEXSPI_BASE_PTRS \
{ \
(FLEXSPI_Type *)0u, FLEXSPI1, FLEXSPI2 \
}
至此,i.MXRT三位數系列隱藏的FlexSPI Remap功能痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。