查看: 111|回复: 0

[分享] 且看L-MEM ECC如何守护i.MXRT1170从核CM4

[复制链接]
  • TA的每日心情
    开心
    2020-12-18 12:56
  • 签到天数: 55 天

    [LV.5]常住居民I

    75

    主题

    225

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    1632
    最后登录
    2024-4-26
    发表于 2024-3-28 11:39:00 | 显示全部楼层 |阅读模式
    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M4内核的L-MEM ECC功能。
    本篇是 《简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响》 的姊妹篇,我们知道i.MXRT1170是双核MCU,主核Cortex-M7的TCM ECC由FlexRAM模块负责,那么从核Cortex-M4的TCM有没有ECC呢?如果有的话,是由哪个模块负责的呢?本篇给你解答。
    老规矩先来看一下Cortex-M4下的系统内存映射表,不同类型的存储由不同的ECC控制器来守护,从表中看,CM4的TCM也是有ECC功能的,ECC功能集成在了L-MEM控制器里,所以今天我们来聊一聊L-MEM的ECC功能。

    L-MEM的ECC功能

    L-MEM的ECC功能


    一、L-MEM ECC功能简介
    1.1 L-MEM特点
    我们先来看下i.MXRT1170的CM4内核系统框图,L-MEM是专门为CM4内核设计的,其管理的TCM空间仅能由CM4访问。在框图中,L-MEM中物理SRAM总大小是256KB,细心的你可能发现了上面那张系统内存映射表中还有个256KB OCRAM(M4),这个OCRAM与L-MEM是什么联系?其实它俩指向的是同一块物理SRAM,只不过CM4内核是从TCM地址空间直接访问SRAM,而从OCRAM(M4)地址空间去访问SRAM相当于多绕了一级(速度变慢,所以不建议CM4访问OCRAM(M4)空间,这个地址空间主要是给CM7访问的)。
    我们知道支持ECC功能,需要有额外空间来存储ECC校验值,那么L-MEM的ECC校验值是存在哪里的呢?关于这个细节在下一节里展开聊。

    L-MEM特点

    L-MEM特点
    1.2 关于ECC设计细节
    关于ECC基本概念,参看《简析i.MXRT1170 Cortex-M7 FlexRAM ECC功能特点、开启步骤、性能影响》 的 1.2节,这里不予赘述。
    1.2.1 ECC检验能力
    L-MEM中每4bytes数据就会计算出一个ECC校验值(7bits),ECC校验值都被放在了ECC RAM区域里。这里必须要特别介绍一下ECC RAM区域,不同于FlexRAM ECC会有专门的独立RAM空间用于存放ECC校验值,L-MEM的ECC校验值是紧跟着放在每个32bit数据后面的,用户访问到的L-MEM是32bit数据线,但其实芯片内部设计L-MEM是39bit数据线,其中高7bit就是专门用来存放ECC校验值的。

    其中高7bit就是专门用来存放ECC校验值的

    其中高7bit就是专门用来存放ECC校验值的
    1.2.2 ECC错误触发处理
    关于ECC错误处理,可根据如下MCM寄存器(不要怀疑,L-MEM ECC的控制就是在MCM里实现的)来操作,首先当然是在LMPECR寄存器中使能multi-bit ECC Error,当有2-bit及以上错误发生时,系统会触发NonMaskableInt_IRQn(中断号是-14),在中断处理程序里找到相应的发生ECC错误的地址,对这个地址重新写一次初始化数据(按ECC校验块长度一次性写入),最后清除LMPEIR寄存器里的相应状态位。
    需要注意的是,上述处理流程仅对L-MEM中存放的是普通业务数据且发生ECC错误时有效,如果ECC错误发生在关键代码段或变量段中,这个处理是不适用的,因为这种ECC错误可能会造成程序崩溃。

    因为这种ECC错误可能会造成程序崩溃

    因为这种ECC错误可能会造成程序崩溃


    二、开启L-MEM ECC的步骤
    L-MEM ECC需要按照标准步骤去开启,需要特别注意的是开启ECC操作的代码不能放在待开启ECC的L-MEM空间里,因此不管是XIP还是Non-XIP应用程序,最好是用一个二级loader(这个loader可以链接在固定OCRAM1/2空间里,或者XIP)来完成ECC开启操作然后再加载应用程序执行。痞子衡给了如下示例loader代码工程,代码里主要有四个步骤:
    参考代码:https://github.com/JayHeng/corte ... cm4_loader/loader.c
    2.1 激活L-MEM ECC特性
    芯片出厂,默认是没有激活L-MEM ECC特性的,如果需要开启L-MEM ECC,需要烧写efuse,fusemap中0x840[2]对应的是MECC_ENABLE bit,这个bit不仅控制MECC模块,也同时控制了L-MEM ECC特性,我们需要将这个bit烧写成1,才能激活L-MEM ECC特性。

    激活L-MEM ECC特性

    激活L-MEM ECC特性
    2.2 使能L-MEM的ECC
    现在需要使能L-MEM ECC,在i.MXRT1170参考手册里的MCM章节可以找到LMDR0/1寄存器定义,其中bit3就是用来分别控制TCRAML(对应ITCM)和TCRAMU(对应DTCM)的ECC开关。特别注意,这里的MCM模块寄存器仅能在CM4下被访问。

    使能L-MEM的ECC

    使能L-MEM的ECC
    操作函数代码如下:
    void enable_lmem_tcm_ecc(void)
    {
        // Check eFuse 0x840[2] - MECC_ENABLE bit
        while (!(OCOTP->HW_OCOTP_FUSE004 & 0x4));


        // MCM->LMPECR[9,1] - Enable TCRAM ECC 1-bit/Multi-bit IRQ
        *(uint32_t *)0xE0080480 |= 0x303;


        // MCM->LMDR0[3] - Enable TCRAML ECC
        *(uint32_t *)0xE0080400 |= 0x0B;        /* Enable CM4 TCRAM_L ECC */
        // MCM->LMDR1[3] - Enable TCRAMU ECC
        *(uint32_t *)0xE0080404 |= 0x0B;        /* Enable CM4 TCRAM_U ECC */
    }
    2.3 初始化L-MEM的ECC值
    L-MEM ECC开启了之后,此时还不能随机访问L-MEM,因为初始ECC校验值还没有填充,如果这时候去读L-MEM会产生错误。我们首先需要将会用到的L-MEM空间全部初始化一遍(就是以ECC校验数据块大小对齐方式从头到尾写入一遍,写入内容不限,正常用全0)。
    操作函数代码如下:
    #define ITCM_START   0x1FFE0000
    #define ITCM_SIZE    (128*1024U)
    #define DTCM_START   0x20000000
    #define DTCM_SIZE    (128*1024U)
    void init_lmem_itcm_ecc(void)
    {
        for (uint32_t i = 0; i < ITCM_SIZE; i += sizeof(uint32_t))
        {
            *(uint32_t *)(ITCM_START + i) = 0;
        }
    }
    void init_lmem_dtcm_ecc(void)
    {
        for (uint32_t i = 0; i < DTCM_SIZE; i += sizeof(uint32_t))
        {
            *(uint32_t *)(DTCM_START + i) = 0;
        }
    }
    2.4 加载应用程序执行
    当L-MEM初始ECC校验值已经被填充之后,此时便可以正常随机读写L-MEM了。如果此时加载的是一个在ITCM里执行并且data段在DTCM里的应用程序,可以参考痞子衡前面给出的示例loader工程。
    这是loader工程完整主函数代码,其中memcpy那一句代码里的cm4_app_code是应用程序binary数组(用Python脚本将应用程序工程生成的.bin文件转换成C语言数组放到loader工程源文件里)。
    #define APP_START 0x1FFE0000U
    int main(void)
    {
        enable_lmem_tcm_ecc();
        init_lmem_itcm_ecc();
        init_lmem_dtcm_ecc();
        // Copy image to RAM.
        memcpy((void *)APP_START, cm4_app_code, APP_LEN);
        uint32_t appStack = *(uint32_t *)(APP_START);
        uint32_t appEntry = *(uint32_t *)(APP_START + 4);
        // Turn off interrupts.
        __disable_irq();
        // Set the VTOR to default.
        SCB->VTOR = APP_START;
        // Memory barriers for good measure.
        __ISB();
        __DSB();
        // Set main stack pointer and process stack pointer.
        __set_MSP(appStack);
        __set_PSP(appStack);
        // Jump to app entry point, does not return.
        void (*entry)(void) = (void (*)(void))appEntry;
        entry();
    }


    三、ECC对内存访问性能的影响
    L-MEM开了ECC后,访问性能会有一定降低,毕竟数据访问中插入了额外的ECC校验工作,不过据说影响非常小。我们来做个测试,痞子衡就用经典的benchmark程序(Coremark)来测试ECC对L-MEM的影响,测试工程如下:
    Coremark工程:https://github.com/JayHeng/corte ... uild7804_cm4_loader
    需要特别提醒的是,我们知道i.MXRT1170 CM4内核最高可以配置到480MHz,但是开了L-MEM ECC后,为了保证访问可靠性,此时CM4内核最好是工作在360MHz,下面的coremark结果也是在360MHz主频下得到的:

    类型

    类型
    从benchmark结果来看,ECC是否开启对性能影响特别小,可以忽略,当然benchmark测试并不是特别精确地反映了性能影响,底下有空痞子衡会再专门用memcpy函数来测试性能影响。
    至此,恩智浦i.MXRT1170上Cortex-M4内核的L-MEM ECC功能痞子衡便介绍完毕了,掌声在哪里~~~

    签到
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-27 17:39 , Processed in 0.117912 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表