痞子衡最近在深耕i.MXRT1170這顆劃時代的MCU,已經寫了不少篇相關技術文章,涉及整體特點、Raw NAND啟動、FlexRAM模塊、ECC特性等,文章寫得越多越發覺得i.MXRT1170是座寶礦,值得大家去仔細探索。話不多說,咱們繼續挖礦吧,今天痞子衡為大家介紹i.MXRT1170雙核間互相... ...
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是恩智浦i.MXRT1170上Cortex-M7與Cortex-M4內核互相激活的方法。
痞子衡最近在深耕i.MXRT1170這顆劃時代的MCU,已經寫了不少篇相關技術文章,涉及整體特點、Raw NAND啟動、FlexRAM模塊、ECC特性等,文章寫得越多越發覺得i.MXRT1170是座寶礦,值得大家去仔細探索。話不多說,咱們繼續挖礦吧,今天痞子衡為大家介紹i.MXRT1170雙核間互相激活的方法。
一、雙核功能簡介
雙核是i.MXRT1170除了1GHz主頻之外的第二個顯著特點,i.MX RT系列也是從RT1170開始首次引入了雙核架構。i.MXRT1170包含了一個Cortex-M7內核(1GHz)以及一個Cortex-M4內核(400MHz),超強的Cortex-M7內核專註於音視頻識別與處理、千兆乙太網通訊控制等複雜任務上;低功耗Cortex-M4內核則做一些相對簡單的鍵盤響應、感測器採集、電機控制等任務,即如下圖所示:
二、雙核激活方法
i.MXRT1170雖然是雙核(Cortex-M7與Cortex-M4),但這兩個核並沒有確定的主從關係,i.MXRT1170系統設計里每個核都既可以當主核也可以當從核(預設CM7是主核,CM4是從核),用戶設置了主從關係之後,晶元上電後先從主核啟動,然後由主核來激活從核啟動。
2.1 選定主核
主核是在eFuse中選定的,fusemap中0x960[13:12]對應的是BT_CORE_CTRL和BT_CORE_SEL bit,預設兩個bit都是0,即從CM7是主核,上電CM7啟動,如果需要更改主核為CM4,則需要燒寫eFuse。
這裡順便插一句,我們知道晶元上電都是先執行BootROM代碼,既然CM7和CM4都可以當主核,那麼這個BootROM代碼需要既可以在CM4下執行,也可以在CM7下執行。這裡藉助的是Cortex-M處理器向下相容、軟體二進位向上相容的特性,BootROM代碼使用Cortex-M4指令集去編譯即可。
2.2 載入從核App(可選)
選定了主核之後,主核App由BootROM載入執行,我們需要在主核App里添加代碼來啟動從核。啟動從核的第一步是載入從核App,App從載入執行位置上可分為兩種,一種是在Flash里原地執行,另一個是拷貝到RAM里執行,只有後者才需要先載入再執行。
關於從核App執行位置,這裡有必要好好聊一下,下麵是CM7和CM4下各自系統記憶體映射表,從表裡可以看到除了各自內核TCM空間僅對自己可見外,其餘地址空間對兩個核均是可見的(並且映射地址也是相同的)。如果載入的從核App是在TCM里執行的,主核需要將從核App載入到從核TCM對應的OCRAM空間(此種情況僅適用CM4當從核,其TCM對應的是OCRAM(M4)空間;CM7當從核時其TCM對應的空間CM4是無法訪問的);如果載入的從核App不是在TCM里執行的,那麼情況就比較簡單,直接載入到那個目標映射地址空間即可。
下麵是載入從核App示例代碼,appBuffer是從核App Image在外部Flash里存放的首地址,vectorAddr是載入的目標RAM首地址。為了防止Cache干擾後續從核取複位向量執行,主核在載入App前後最好均要清一下DCache。
void copy_app_image(uint8_t *appBuffer, uint32_t appLength, uint32_t vectorAddr)
{
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
SCB_CleanInvalidateDCache_by_Addr((void *)vectorAddr, appLength);
#endif
/* Copy app image to dest addrress. */
memcpy((void *)vectorAddr, appBuffer, appLength);
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
SCB_CleanInvalidateDCache_by_Addr((void *)vectorAddr, appLength);
#endif
}
2.3 指定從核初始中斷向量表地址
載入從核App完成之後,接下來便是設置從核啟動所需的中斷向量表位置,從核需要從中斷向量表裡取出初始棧地址(SP)和複位向量(PC)來執行。
CM7啟動初始向量表地址設置在IOMUXC_LPSR_GPR26里(對應SCB->VTOR[31:7]),CM4啟動初始向量表地址設置在IOMUXC_LPSR_GPR0/1里(對應SCB->VTOR[31:3])。
- Note: A0版本晶元CM7啟動初始向量表設置在IOMUXC_GPR19里;B0版本晶元CM7啟動初始向量表設置改到了IOMUXC_LPSR_GPR26里。
下麵是設置從核啟動初始中斷向量表地址的示例代碼:
void set_cm4_vector(uint32_t vectorAddr)
{
IOMUXC_LPSR_GPR->GPR0 = IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(vectorAddr);
IOMUXC_LPSR_GPR->GPR1 = IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(vectorAddr >> 16);
}
void set_cm7_vector(uint32_t vectorAddr)
{
IOMUXC_LPSR_GPR->GPR26 = IOMUXC_LPSR_GPR_GPR26_CM7_INIT_VTOR(vectorAddr);
}
2.4 激活從核
此時從核已經摩拳擦掌,等待來自主核的最後激活指令了。激活控制是在SRC->SCR寄存器里實現的,將BT_RELEASE_Mx位置1即可啟動CMx從核。這裡需要註意一點,如果是在調試,從核有可能已經被調試器的腳本激活過了,那麼此時僅需要reset一下從核即可。
下麵是激活從核啟動的示例代碼:
void launch_cm4_core(void)
{
/* If CM4 is already running (released by debugger), then reset the CM4.
If CM4 is not running, release it. */
if ((SRC->SCR & SRC_SCR_BT_RELEASE_M4_MASK) != 0)
{
SRC->CTRL_M4CORE |= SRC_SLICE_CTRL_SW_RESET_MASK;
while ((SRC->STAT_M4CORE & SRC_SLICE_STAT_UNDER_RST_MASK) != 0UL);
}
else
{
SRC->SCR |= SRC_SCR_BT_RELEASE_M4_MASK;
}
}
void launch_cm7_core(void)
{
/* If CM7 is already running (released by debugger), then reset the CM7.
If CM7 is not running, release it. */
if ((SRC->SCR & SRC_SCR_BT_RELEASE_M7_MASK) != 0)
{
SRC->CTRL_M7CORE |= SRC_SLICE_CTRL_SW_RESET_MASK;
while ((SRC->STAT_M7CORE & SRC_SLICE_STAT_UNDER_RST_MASK) != 0UL);
}
else
{
SRC->SCR |= SRC_SCR_BT_RELEASE_M7_MASK;
}
}
三、一個典型示例
最後給一個完整示例,主核是CM7,從核是CM4,從核App代碼存儲在0x60010000地址,App長度是32KB,從核APP是從ITCM起始地址(0x1FFE0000)開始鏈接的。CM7激活CM4完整代碼如下:
#define CM4_BUF_START 0x60010000U
#define CM4_BUF_LEN 0x8000U
#define CM4_CPY_START 0x20200000U
#define CM4_APP_START 0x1FFE0000U
int main(void)
{
copy_app_image(CM4_BUF_START, CM4_BUF_LEN, CM4_CPY_START);
set_cm4_vector(CM4_APP_START);
launch_cm4_core();
while (1)
{
}
}
至此,恩智浦i.MXRT1170上Cortex-M7與Cortex-M4內核互相激活的方法痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時發佈到我的 博客園主頁、CSDN主頁、微信公眾號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下麵二維碼,就可以在手機上第一時間看了哦。