痞子衡嵌入式:大話雙核i.MXRT1170之單獨線上除錯從核工程的方法(IAR篇)

痞子衡發表於2022-04-07

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1170下單獨線上除錯從核工程的方法(基於IAR)

  兩年前痞子衡寫過一篇《雙核i.MXRT1170之Cortex-M7與Cortex-M4互相啟用之道》,那篇文章從離線啟動的角度介紹了跑雙核應用的基本方法,基本上把雙核啟動的細節都介紹到了。

  在應用開發的階段,很多時候我們還是需要線上除錯的,主核的除錯沒什麼特別要注意的地方,從核的除錯大家估計就有點陌生了,今天痞子衡就給大家介紹下 IAR 開發環境下除錯從核工程的方法:

一、測試準備

  首先需要準備好測試環境,包含必要的軟體和硬體,痞子衡的環境如下:

  • 整合開發環境: IAR EW for Arm v9.10.2,[點此下載](https://www.iar.com/products/architectures/
  • 軟體開發包: SDK_2.11.0_MIMXRT1170-EVK(Toolchain要包含IAR),點此下載
  • 軟體驅動: J-Link driver v7.56b,點此下載
  • 硬體工具: J-Link Plus偵錯程式
  • 硬體開發板: MIMXRT1170-EVK (Rev.C),含板載 DAP-Link 偵錯程式

  我們知道 i.MXRT1170 其實主從核是在 Fuse 裡可配的,我們就以預設配置(Cortex-M7 為主,Cortex-M4 為從)為例來介紹,選取的測試工程是 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\hello_world\cm4。

二、在IAR下除錯

  使用 IAR 開啟 hello_world_demo_cm4.eww 工程,切換到 debug build (就是在 RAM 中執行)。

2.1 工程選項處理器選 Cortex-M4 核除錯情況

  我們先來看一下工程選項裡處理器選擇 Cortex-M4,並且不使能任何額外指令碼時除錯情況。也就是說在明知主核 Cortex-M7 處於啟用狀態而 Cortex-M4 處於未啟用狀態時,IAR C-SPY 除錯元件能否工作。

  痞子衡分別測試了板載 DAP-Link 偵錯程式以及外接 J-Link 偵錯程式,測試結果均是不能直接除錯,DAP-Link 下提示 "Failed to connect to CPU",J-Link 下提示 "Select core is not same as the target core"。

2.2 工程選項處理器選 NXP MIMXRT1176xxxA_M4 除錯情況

  再來看一下工程選項裡處理器選擇 NXP MIMXRT1176xxxA_M4 時除錯情況(會呼叫相關指令碼,在 IAR/J-Link 裡已經做好)。也就是雖然 Cortex-M4 處於未啟用狀態,但是有配套指令碼會負責啟用工作。

  J-Link 下是可以直接除錯的,在 Debug Log 視窗,我們可以看到有 .jlinkscript 指令碼執行的痕跡,指令碼列印資訊裡顯示其識別到 Cortex-M4 未啟用,並且會做啟用相關工作。

  • Note: 這個跟 NXP MIMXRT1176xxxA_M4 選擇相關的 .jlinkscript 指令碼在 JLink 驅動安裝目錄下,由於 log 裡沒有直接顯示路徑,那大概率已經被打包進 DLL 檔案裡了,我們看不到具體指令碼程式碼實現。

  DAP-Link 下也是可以直接除錯的,在 Debug Log 視窗,我們可以看到 iMXRT_1170.dmac 指令碼被執行了,指令碼列印資訊裡顯示其識別到 Cortex-M4 未啟用,並且會做啟用相關工作。

  • Note: 這個跟 NXP MIMXRT1176xxxA_M4 選擇相關的 iMXRT_1170.dmac 指令碼在 IAR 安裝目錄下,具體路徑已經在 log 裡顯示出來了,我們可以看到其具體指令碼程式碼實現。

  如果你細心觀察,你會發現 DAP-Link 下必須要在工程選項 Debugger / Extra Options 里加 “--macro_param enable_core=1” 語句才能正常除錯,這是因為 iMXRT_1170.dmac 指令碼需要接受這個引數才能正常啟用從核 Cortex-M4。

2.3 自己實現用於從核除錯的指令碼

  現在我們知道了除錯從核 Cortex-M4 工程必須要有專門指令碼來負責啟用從核才行,雖然 IAR/J-Link 裡已經做好這個指令碼,但是兩者行為是否統一我們不清楚(畢竟看不見 J-Link 下指令碼原始碼),而且這個指令碼是隨著 IAR/J-Link 版本而變化的,具有一定的不可控性。

  為了完全掌控從核除錯的主動性與確定性,最好我們自己重新實現 IAR/J-Link 下的除錯指令碼,線上除錯時直接指定使用我們自己寫的指令碼,這樣即使工程選項裡處理器選擇 Cortex-M4 我們也能正常除錯。

  對於 DAP-Link,我們新建一個 mimxrt1170_connect_cm4_user.mac 檔案(具體內容見附錄一)放到工程目錄下,並且在 IAR 選項裡指定使用這個 mac 檔案。這個 mac 檔案語法詳見 《IAR內部C-SPY除錯元件配套巨集檔案(.mac)用法介紹》,其中最重要的是 execUserCoreConnect() 保留巨集函式裡要做啟用 Cortex-M4 工作。

  • Note: 如果希望除錯從核 Cortex-M4 時,主核 Cortex-M7 依然在跑,可以註釋掉 mimxrt1170_connect_cm4_user.mac 檔案裡的 execUserSetup() 函式。

  對於 J-Link,我們新建一個 mimxrt1170_connect_cm4_user.jlinkscript 檔案(具體內容見附錄二)放到工程目錄下,並且在 IAR 選項裡指定使用這個 jlinkscript 檔案。這個 jlinkscript 檔案語法詳見 《JLink Script檔案基礎及其在IAR下呼叫方法》,其中最重要的是 InitTarget() 使用者自定義動作函式裡要做啟用 Cortex-M4 工作。

  • Note: 如果希望除錯從核 Cortex-M4 時,主核 Cortex-M7 依然在跑,可以註釋掉 mimxrt1170_connect_cm4_user.jlinkscript 檔案裡的 AfterResetTarget() 函式。

prepare_core_spin_code(cmVersion)
{
    __var start;
    if (cmVersion == 7)
    {
        start = 0x2021FF00;
        __writeMemory32(start >> 7, 0x40c0c068,  "AP0_Memory");
    }
    if (cmVersion == 4)
    {
        start = 0x20200000;
        __writeMemory32(start & 0xFFFF, 0x40c0c000,  "AP0_Memory");
        __writeMemory32(start >> 16,    0x40c0c004,  "AP0_Memory");
    }
    __writeMemory32(start + 0x20, start, "AP0_Memory");
    __writeMemory32(0x223105, start + 0x4, "AP0_Memory");
}

release_core(cmVersion)
{
    if (cmVersion == 7)
    {
        __writeMemory32(0x2, 0x40c04000, "AP0_Memory");
    }
    if (cmVersion == 4)
    {
        __writeMemory32(0x1, 0x40c04000, "AP0_Memory");
    }
}

reset_core(cmVersion)
{
    __var reg;
    __var ctrlAddr;
    __var statAddr;
    if (cmVersion == 7)
    {
        ctrlAddr = 0x40c042a4;
        statAddr = 0x40c042b0;
    }
    if (cmVersion == 4)
    {
        ctrlAddr = 0x40c04284;
        statAddr = 0x40c04290;
    }
    __writeMemory32(0x1, ctrlAddr, "AP0_Memory");
    do
    {
        reg = __readMemory32(statAddr, "AP0_Memory");
        __delay(10);
    }while(reg & 0x1);
}

//_ExecDeviceCoreConnect()
execUserCoreConnect()
{
    __probeCmd("j.i swd /force");
    // dummy read
    __readAPReg(2);
    __delay(10);
    // Disable system reset caused by sysrstreq from each core
    __writeMemory32(0x3c00, 0x40C04004, "AP0_Memory");
    prepare_core_spin_code(4);
    release_core(4);
    // switch to AP1
    __writeDPReg(1<<24, 2);
}

execUserPreReset()
{
    reset_core(4);
    release_core(4);
    __writeDPReg(1<<24, 2);
}

execUserSetup()
{
    __var reg;
    reg = __readMemory32(0x40c04000, "AP0_Memory");
    if((reg & 0x2) == 0)
    {
        prepare_core_spin_code(7);
        reset_core(7);
    }
}
void prepare_core_spin_code(unsigned int cmVersion) 
{
    unsigned int start;
    if (cmVersion == 7)
    {
        start = 0x2021FF00;
        MEM_WriteU32(0x40c0c068,  start >> 7);
    }
    if (cmVersion == 4)
    {
        start = 0x20200000;
        MEM_WriteU32(0x40c0c000,  start & 0xFFFF);
        MEM_WriteU32(0x40C0c004,  start >> 16);
    }
    MEM_WriteU32(start,       start + 0x20);
    // BootROM go_fatal_mode()
    MEM_WriteU32(start + 0x4, 0x223105);
}

void release_core(unsigned int cmVersion)
{
    if (cmVersion == 7)
    {
        MEM_WriteU32(0x40C04000, 0x2);
    }
    if (cmVersion == 4)
    {
        MEM_WriteU32(0x40C04000, 0x1);
    }
}

void reset_core(unsigned int cmVersion)
{
    unsigned int reg;
    unsigned int ctrlAddr;
    unsigned int statAddr;

    if (cmVersion == 7)
    {
        ctrlAddr = 0x40c042a4;
        statAddr = 0x40c042b0;
    }
    if (cmVersion == 4)
    {
        ctrlAddr = 0x40c04284;
        statAddr = 0x40c04290;
    }

    MEM_WriteU32(ctrlAddr, 1);
    do
    {
        reg = MEM_ReadU32(statAddr);
        SYS_Sleep(10);
    }while (reg & 0x1);
}

void InitTarget(void) 
{
    CPU = CORTEX_M7;
    // Manually configure AP
    JLINK_CORESIGHT_AddAP(0, CORESIGHT_AHB_AP);
    JLINK_CORESIGHT_AddAP(1, CORESIGHT_AHB_AP);
    JLINK_CORESIGHT_AddAP(2, CORESIGHT_APB_AP);
    // Dummy read
    JLINK_CORESIGHT_ReadAP(JLINK_CORESIGHT_AP_REG_IDR);
    SYS_Sleep(10);
    // Disable system reset caused by sysrstreq from each core
    MEM_WriteU32(0x40C04004, 0x3c00);
    prepare_core_spin_code(4);
    release_core(4);
    // Switch to AP1
    CPU = CORTEX_M4;
    CORESIGHT_IndexAHBAPToUse = 1;
}

void ResetTarget(void)
{
    CORESIGHT_IndexAHBAPToUse = 0;
    reset_core(4);
    release_core(4);
    CORESIGHT_IndexAHBAPToUse = 1;
}

void AfterResetTarget(void)
{
    unsigned int reg;
    reg = MEM_ReadU32(0x40c04000);
    if((reg & 0x2) == 0)
    {
        prepare_core_spin_code(7);
        reset_core(7);
    }
}

  至此,i.MXRT1170下單獨線上除錯從核工程的方法痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時釋出到我的 部落格園主頁CSDN主頁知乎主頁微信公眾號 平臺上。

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

相關文章