痞子衡嵌入式:解鎖i.MXRTxxx上FlexSPI模塊自帶的地址重映射(Remap)功能


  你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們介紹的是i.MXRT三位數系列隱藏的FlexSPI Remap功能html

  前段時間痞子衡寫了一篇文章 《利用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功能呢?本文痞子衡將爲你解答。api

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設計是不同的。flex

3. FlexSPI Remap功能設計

  雖然i.MXRT500/600上的Remap控制嵌在FlexSPI模塊內部,但Remap設計依然是屬於系統架構層面的,只是在AHB總線層面作一個地址重定向。下面是Remap控制寄存器:ui

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對齊的)spa

  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主頁知乎主頁微信公衆號 平臺上。

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

相關文章
相關標籤/搜索