痞子衡嵌入式:藉助i.MXRT10xx系列INIT_VTOR功能可以縮短程序熱重啓時間


  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是藉助i.MXRT10xx系列INIT_VTOR功能可以縮短程序熱重啓時間

  最近痞子衡寫了篇文章 《i.MXRT從Serial NAND啓動時間測量》,這篇文章詳細測試了不同長度的 Non-XIP 程序在不同 NAND 訪問速度下由 BootROM 加載啓動所需要的時間,比如 240KB 的程序在 60MHz NAND 的訪問速度下啓動時間接近 30ms,這個啓動時間對於有些響應時間敏感的應用(比如汽車電子)來說還是比較長的。

  對於 Non-XIP 程序,經過冷啓動後,其程序體本身已經被加載進芯片內部 SRAM 了,除非發生 POR,否則 SRAM 中的程序會一直保持着。假設程序在惡劣的電磁環境中運行,代碼裏雖然包含異常復位的處理,但是每次程序復位啓動時間還是和冷啓動時間一樣長(每次都需要 BootROM 搬移加載),有點難以接受。那麼對於這種熱啓動的情況,程序啓動時間能夠縮短嗎?答案是可以的,今天痞子衡就介紹下 i.MXRT 上的 INIT_VTOR 特性:

  • 備註1:本文主角是i.MXRT1050,但內容也基本適用其它i.MXRT10xx系列。
  • 備註2:同樣的測試在i.MXRT1160/1170下無效,因爲CM7_INIT_VTOR所在的IOMUXC_LPSR_GPR->GPR26在軟復位下不能保持。

一、INIT_VTOR功能簡介

  在介紹 INIT_VTOR 功能之前,大家首先要對 ARM Cortex-M 內核的中斷向量表偏移寄存器 SCB->VTOR 功能有所瞭解,具體可以看痞子衡的舊文 《Cortex-M中斷向量表原理及其重定向方法》

  簡單來說,芯片上電啓動後內核都是從 SCB->VTOR 指向的地址處獲取程序中斷向量表裏的第二個向量即所謂的復位函數 Reset_Handler。有了復位函數,就找到了程序入口。

; 摘取自 startup_MIMXRT1052.s

__vector_table
        DCD     sfe(CSTACK)
        DCD     Reset_Handler

        DCD     NMI_Handler
        DCD     HardFault_Handler
        DCD     MemManage_Handler
        DCD     BusFault_Handler
        DCD     UsageFault_Handler
        ...

  對於 i.MXRT1050,我們知道芯片上電覆位都是執行 BootROM 代碼,BootROM 中斷向量表固定放在了 0x0020_0000 地址處。那麼這個 0x0020_0000 地址是怎麼被賦給 SCB->VTOR 寄存器的呢?這就引出了本文主角 IOMUXC_GPR->GPR16[32:7] - CM7_INIT_VTOR 位,這 25bits 的 CM7_INIT_VTOR 值每次復位都會被芯片系統自動加載進 SCB->VTOR[32:7] 中,其默認值即對應 BootROM 中斷向量表地址。

  正如痞子衡舊文 《妙用i.MXRT1xxx裏SystemReset不復位的GPR寄存器》 提及的那樣,IOMUXC_GPR 寄存器僅在 POR 復位或者整體重新上電時纔會被重置,這就意味着我們在應用程序中只需要設置一次 CM7_INIT_VTOR 值,其後不管發生多少次類似 NVIC_SystemReset() 的復位,CM7_INIT_VTOR 值都不會改變。

二、使用INIT_VTOR加速程序熱重啓

  有了上一節的理論基礎,我們來做個實驗。痞子衡找了一塊 MIMXRT1050-EVK12(Rev.A)板卡,將其啓動設備換成串行 NAND 啓動(電阻切換到使能 U33,並將 U33 替換成華邦 W25N01GV)。

  然後按照串行 NAND 啓動時間測試方法那樣修改 \SDK_2_13_0_EVKB-IMXRT1050\boards\evkbimxrt1050\demo_apps\led_blinky\iar 例程(debug build,即代碼在 ITCM 運行,注意修改鏈接文件中的 m_interrupts_start = 0x00002000),並在 SystemInit() 函數裏調用如下測試函數,根據是否設置 IOMUXC_GPR->GPR16 寄存器編譯出兩個不同鏡像文件(直接編輯 bin 文件將其均填充至 120KB)。

void set_led_gpio(void)
{
  CLOCK_EnableClock(kCLOCK_Iomuxc);
  gpio_pin_config_t USER_LED_config = {
      .direction = kGPIO_DigitalOutput,
      .outputLogic = 0U,
      .interruptMode = kGPIO_NoIntmode
  };
  GPIO_PinInit(GPIO1, 9U, &USER_LED_config);
  IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09, 0U); 
  IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09, 0x10B0U); 

  SystemCoreClockUpdate();
  GPIO_PinWrite(GPIO1, 9U, 0U);
  SDK_DelayAtLeastUs(5000, SystemCoreClock);
  // 根據是否設置 CM7_INIT_VTOR 分別編譯兩個不同鏡像文件
  // 設置 CM7_INIT_VTOR 指向地址 0x00002000,即用戶應用程序中斷向量表
  IOMUXC_GPR->GPR16 = (IOMUXC_GPR->GPR16 & (~IOMUXC_GPR_GPR16_CM7_INIT_VTOR_MASK)) | IOMUXC_GPR_GPR16_CM7_INIT_VTOR(0x2000 >> 7);
  NVIC_SystemReset();
  while (1);
}

  然後藉助 MCUBootUtility 工具將這兩個不同鏡像文件下載進串行 NAND flash,並測試相應啓動時間。這裏 Flash 運行速度就選擇 60MHz:

  下面是不設置 IOMUXC_GPR->GPR16 的程序啓動時間測試結果,無論是一開始的 POR 冷啓動還是後面 NVIC_SystemReset() 引起的熱啓動,啓動時間都需要約 18.66ms:

  下面是設置了 IOMUXC_GPR->GPR16 指向 0x2000 之後的程序啓動時間測試結果,只有一開始的 POR 冷啓動時間是 18.66ms,後面 NVIC_SystemReset() 引起的熱啓動時間僅需要約 5.26ms。

  上述實驗結果證明,設置 IOMUXC_GPR->GPR16 指向應用程序中斷向量表之後確實能縮短程序熱啓動時間。有朋友可能會疑問,設置了從 ITCM 直接熱啓動後爲何還是有 5.26ms 的啓動時間?這其實主要是從進入應用程序 Reset_Handler 到執行到測試 GPIO 拉低時的代碼所消耗的時間,並且需要注意的是由 BootROM 加載執行的程序默認是在 ROM 配置後的 396MHz 主頻下執行的(主頻夠快,測試代碼消耗時間可以忽略不計),而直接復位從 ITCM 裏執行的程序是在默認主頻 12MHz 下執行的(主頻較慢,測試代碼消耗時間不得不計)。

  最後再提一下,除了直接在應用程序裏設置 IOMUXC_GPR->GPR16 之外,也可以藉助 BootROM 的 DCD 功能來設置,同樣可以藉助 MCUBootUtility 直接完成(詳細步驟可參考 《利用i.MXRT1xxx系列ROM集成的DCD功能可輕鬆配置指定外設》),痞子衡實測是有效的。

  翻看 RT1050 參考手冊 System Boot 章節,IOMUXC_GPR 寄存器地址空間也確實在有效的 DCD 設置範圍。

  至此,藉助i.MXRT10xx系列INIT_VTOR功能可以縮短程序熱重啓時間痞子衡便介紹完畢了,掌聲在哪裏~~~

歡迎訂閱

文章會同時發佈到我的 博客園主頁CSDN主頁知乎主頁微信公衆號 平臺上。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章