• 痞子衡嵌入式:大话双核i.MXRT1170之单独在线调试从核工程的方法(IAR篇)



      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是i.MXRT1170下单独在线调试从核工程的方法(基于IAR)

      两年前痞子衡写过一篇《双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道》,那篇文章从离线启动的角度介绍了跑双核应用的基本方法,基本上把双核启动的细节都介绍到了。

      在应用开发的阶段,很多时候我们还是需要在线调试的,主核的调试没什么特别要注意的地方,从核的调试大家估计就有点陌生了,今天痞子衡就给大家介绍下 IAR 开发环境下调试从核工程的方法:

    一、测试准备

      首先需要准备好测试环境,包含必要的软件和硬件,痞子衡的环境如下:

    • 集成开发环境: IAR EW for Arm v9.10.2,点此下载
    • 软件开发包: 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主页知乎主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

  • 相关阅读:
    《剑指offer》【剑指 Offer 12. 矩阵中的路径】
    入行IC | 从小白助理级,到总监专家级,到底要经历怎样的成长阶段呢?
    随笔:想写一本数据结构的书
    while语句使用
    定制Centos7.9镜像
    使用 Presto 和 Alluxio 在 AWS 上搭建高性能平台来支持实时游戏服务
    红队打靶:Fowsniff打靶思路详解(vulnhub)
    厨卫电器行业B2B交易协同管理平台开发,优化企业库存结构
    基于Docker的深度学习环境NVIDIA和CUDA部署以及WSL和linux镜像问题
    k8s——pod控制器
  • 原文地址:https://www.cnblogs.com/henjay724/p/16114916.html