IMXRT 分散加载文件 修改OCRAM,DTCM、ITCM大小
阅读原文时间:2021年04月23日阅读:4

分散加载
MXRT1052/1064芯片的RAM空间分为四种类型:ITCM,DTCM,OCRAM以及外部SDRAM,其中前面三个属于芯片内部RAM,RT1052有512KB,RT1064为1MB,支持用户静态分配,SDRAM属于外置RAM,最大支持到1.5G扩展空间。ITCM和DTCM是直接挂在芯片内核总线,速度可以达到与内核同频的600M,OCRAM挂在Sys AXI 64位总线,速度只能到达133M,外部SDRAM速度则可达到166M,而同时RT1050/1064内又有各32K的指令cache和数据cache,用于提高代码在外部Nor Flash中XIP执行的效率。从速度的角度看,将所有的用户代码分配ITCM/DTCM,能够发挥到最大性能,从存储空间大小的角度看,代码存放在SDRAM或者外部Flash最简单,而从USB/DMA使用的角度来看,RAM空间分配在OCRAM空间最为方便。所以这些不同RAM类型速度/大小的差异和cache的存在,就决定了要想让IMXRT性能发挥到最大,就需要用户根据客户实际应用手动修改内部RAM空间中ITCM/DTCM/OCRAM的大小分配,并定位关键代码和数据到指定RAM空间中运行。
1.如何将关键代码和数据到指定RAM中运行?
① IAR中首先找到使用的对应分散加载文件,用记事本打开;

② 确定自己的内存分配,如下是默认的一种分配方式。

/* 中断向量表 */
define symbol m_interrupts_start       = 0x70002000;
define symbol m_interrupts_end         = 0x700023FF;

// 代码存放位置 
define symbol m_text_start             = 0x70002400;
define symbol m_text_end               = 0x703FFFFF;

// DTCRAM 128K
define symbol dtcram_start             = 0x20000000;
define symbol dtcram_end               = 0x2001FFFF;

// OCRAM 768K
define symbol ocram_start              = 0x20200000;
define symbol ocram_end                = 0x202BFFFF;

// itcram 128K 注意不要从0x00000000开始
define symbol itcram_start             = 0x00000004;
define symbol itcram_end               = 0x0001FFFF;

/* FLASH配置和ivt等信息 */
define exported symbol m_boot_hdr_conf_start = 0x70000000;
define symbol m_boot_hdr_ivt_start           = 0x70001000;
define symbol m_boot_hdr_boot_data_start     = 0x70001020;
define symbol m_boot_hdr_dcd_data_start      = 0x70001030;

③ 规定堆栈区域大小,根据自己的实际情况分配,堆一般是用malloc函数动态分配内存区域,栈是程序的局部变量存储空间,可以适当分配大一点。

// 栈大小 局部变量
if (isdefinedsymbol(__stack_size__)) {
  define symbol __size_cstack__        = __stack_size__;
} else {
  define symbol __size_cstack__        = 0x4000;
}

// 堆大小 动态分配malloc分配的空间
if (isdefinedsymbol(__heap_size__)) {
  define symbol __size_heap__          = __heap_size__;
} else {
  define symbol __size_heap__          = 0x8000;
}

// RAM中的中断向量表 这里没有使用 
define exported symbol __VECTOR_TABLE  = m_interrupts_start;
define exported symbol __VECTOR_RAM    = m_interrupts_start;
define exported symbol __RAM_VECTOR_TABLE_SIZE = 0x0;
define memory mem with size = 4G;

④ 定义一些储存区域和地址块

// 定义存储地址区域(region) 
define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end]
                          | mem:[from m_text_start to m_text_end];

define region DTCRAM_region = mem:[from dtcram_start to dtcram_end - __size_cstack__];
define region ITCRAM_region = mem:[from itcram_start to itcram_end];
define region OCRAM_region  = mem:[from ocram_start  to ocram_end];

// 栈段 栈最好分配在DTCRAM中 
define region CSTACK_region = mem:[from dtcram_end - __size_cstack__+1 to dtcram_end];

// 定义地址块 
define block CSTACK    with alignment = 8, size = __size_cstack__   { };
define block HEAP      with alignment = 8, size = __size_heap__     { };
define block RW        { readwrite };
define block ZI        { zi };
define block NCACHE_VAR  { section NonCacheable , section NonCacheable.init };
define block ITCRAM    with alignment = 8{ section ITCRAMAccess};
define block DTCRAM    with alignment = 8{ section DTCRAMAccess};
define block OTCRAM    with alignment = 8{ section OTCRAMAccess};

⑤ 添加IAR自动初始化区域

// 初始化sections 
initialize by copy { readwrite, section .textrw};
initialize by copy { section ITCRAMAccess, section DTCRAMAccess,
                     section OCRAMAccess};
do not initialize  { section .noinit };
//IAR的ICF文件中宏导出给程序使用
place at address mem: m_interrupts_start    { readonly section .intvec };
place at address mem:m_boot_hdr_conf_start  { section .boot_hdr.conf };
place at address mem:m_boot_hdr_ivt_start   { section .boot_hdr.ivt };
place at address mem:m_boot_hdr_boot_data_start { readonly section .boot_hdr.boot_data };
place at address mem:m_boot_hdr_dcd_data_start  { readonly section .boot_hdr.dcd_data };

keep{ section .boot_hdr.conf, section .boot_hdr.ivt, section .boot_hdr.boot_data, section .boot_hdr.dcd_data };

⑥ 将步骤4中定义的储存区域和地址块关联起来

// 把一系列sections和blocks放置在某个region中。sections和blocks将按任意顺序放置。
place in TEXT_region                        { readonly };                 //代码存放区域
place in DTCRAM_region                      { block RW };                 //RW段存放区域(全局或静态不为0变量)
place in DTCRAM_region                      { block ZI };                 //ZI段存放区域(全局或静态为0变量)
place in OCRAM_region                       { last block HEAP };          //malloc 动态申请内存区域
place in DTCRAM_region                      { block NCACHE_VAR };         //NCACHE区域 需要配合MPU使用
place in CSTACK_region                      { block CSTACK };             //站区域 局部变量

place in ITCRAM_region                      { block ITCRAM };             //ITCRAM区域
place in DTCRAM_region                      { block DTCRAM };             //DTCRAM区域
place in OCRAM_region                       { block OCRAM };              //OCRAM区域

⑦ 我们上面在步骤4中定义了地址块ITCRAMAccess、 DTCRAMAccess、OCRAMAccess,如何在IAR中将变量放到对应地址块呢? ⑧ 打开fsl_common.h,仿照官方AT_NONCACHEABLE_SECTION宏定义添加如下宏定义。

#if (defined(__ICCARM__))
#define AT_ITCRAM_SECTION(func) func @"ITCRAMAccess"
#define AT_DTCRAM_SECTION(func) func @"DTCRAMAccess" 
#define AT_OCRAM_SECTION(func)  func @"OCRAMAccess"
#elif(defined(__ARMCC_VERSION))
#define AT_ITCRAM_SECTION(func) __attribute__((section("ITCRAMAccess"))) func
#define AT_DTCRAM_SECTION(func) __attribute__((section("DTCRAMAccess"))) func
#define AT_OCRAM_SECTION(func)  __attribute__((section("OCRAMAccess")))  func
#elif(defined(__GNUC__))
#define AT_ITCRAM_SECTION(func) __attribute__((section("ITCRAMAccess"))) func
#define AT_DTCRAM_SECTION(func) __attribute__((section("DTCRAMAccess"))) func
#define AT_OCRAM_SECTION(func)  __attribute__((section("OCRAMAccess")))  func
#endif 


⑨ 打开BOARD_ConfigMPU(); 函数修改MPU配置,验证对应的数据分配到了指定位置。

使用宏定义修饰函数或者变量,将函数和变量存放到指定位置。

AT_ITCRAM_SECTION(void delayms(uint16_t ms))
{
    volatile uint32_t i = 0;
    while(ms--) 
    {
        for (i = 0; i < 30000; ++i)
        {
            __asm("NOP"); /* delay */
        }
    }    
} 

AT_DTCRAM_SECTION(uint8_t dcrambuf[100][1024]);
AT_OCRAM_SECTION(uint8_t orambuf[100][1024]);

⑩ MDK中类似IAR,打开分散加载文件,在里面添加块ITCRAMAccess、 DTCRAMAccess、OCRAMAccess。通过步骤8中的宏定义可以将关键代码和变量存放到指定位置。


/* FLASH配置和ivt等信息 */
#define m_flash_config_start           0x70000000
#define m_flash_config_size            0x00001000

#define m_ivt_start                    0x70001000
#define m_ivt_size                     0x00001000

/* 中断向量表 */
#define m_interrupts_start             0x70002000
#define m_interrupts_size              0x00000400

// 代码存放位置 
#define m_text_start                   0x70002400
#define m_text_size                    0x003FDC00

// DTCRAM 128K
#define dtcram_start                   0x20000000
#define dtcram_size                    0x00020000

// OCRAM 768K
#define ocram_start                    0x20200000
#define ocram_size                     0x000C0000

// itcram 128K 注意从0x00000004开始
#define itcram_start                   0x00000004
#define itcram_size                    0x00020000                  

// 栈大小 局部变量
#if (defined(__stack_size__))
  #define Stack_Size                   __stack_size__
#else
  #define Stack_Size                   0x4000
#endif

// 堆大小 动态分配malloc分配的空间
#if (defined(__heap_size__))
  #define Heap_Size                    __heap_size__
#else
  #define Heap_Size                    0x8000
#endif

#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
LR_m_text m_flash_config_start m_text_start+m_text_size-m_flash_config_start {   ; load region size_region
  RW_m_config_text m_flash_config_start FIXED m_flash_config_size { ; load address = execution address
    * (.boot_hdr.conf, +FIRST)
  }

  RW_m_ivt_text m_ivt_start FIXED m_ivt_size { ; load address = execution address
    * (.boot_hdr.ivt, +FIRST)
    * (.boot_hdr.boot_data)
    * (.boot_hdr.dcd_data)
  }
#else
LR_m_text m_interrupts_start m_text_start+m_text_size-m_interrupts_start {   ; load region size_region
#endif
  /* 中断向量表存放位置 */
  VECTOR_ROM m_interrupts_start FIXED m_interrupts_size { ; load address = execution address
    * (RESET,+FIRST)
  }

  /* 代码段存放位置 */
  TEXT_region m_text_start FIXED m_text_size { ; load address = execution address
    * (InRoot$$Sections)
    .ANY (+RO)
  }

  /* DTCRAM段 */
  DTCRAM_region dtcram_start dtcram_size-Stack_Size{ ; RW data
    .ANY (+RW)
    .ANY (+ZI)
    * (DTCRAMAccess)
    * (NonCacheable.init)
    * (NonCacheable)
  }

  /* ITCRAM段 */
  ITCRAM_region itcram_start itcram_size{ ; RW data
    * (ITCRAMAccess)
  }

  /* OCRAM段 */
  OCRAM_region ocram_start ocram_size{ ; 
    * (OCRAMAccess)
  }

  /* 堆区域  */
  ARM_LIB_HEAP +0 EMPTY Heap_Size {    ; Heap region growing up
  }
  /* 栈区域 栈是向下生长的 */
  ARM_LIB_STACK dtcram_start+dtcram_size EMPTY -Stack_Size { ; Stack region growing down
  }
}

动态修改FlexRAM,修改TCRAM大小

RT1052片内的512KB RAM,可以自由分配为ITCRAM、DTCRAM和OCRAM(OCRAM最少32KB)。RT1064相比RT1052,多了512KB的OCRAM,另外的512KB RAM和RT1052一样,可以自由分配为ITCRAM、DTCRAM和OCRAM。
IMXRT的片内RAM可以根据用户需求动态分配,512KB的RAM分成16个BANK,每个BANK 由32位寄存器IOMUXC_GPR->GPR17(0x400AC044)中的两位来确定类型。
• 00b—bank is not used.
• 01b—bank is configured for OCRAM.
• 10b—bank is configured for DTCM.
• 11b—bank is configured for ITCM.
注意ITCRAM、DTCRAM应该为2的幂(32、64、128、256、512)

下图就是一个简单的例子,配置DTCRAM 128K、ITCRAM 256K、OCRAM 128K。

配置完IOMUXC_GPR->GPR17(0x400AC044)寄存器,确定每个BANK的类型后,修改寄存器IOMUXC_GPR->GPR14(0x400AC038)确定对应TCM的空间大小,并设置IOMUXC_GPR->GPR16(0x400AC040)开启动态分配的内存空间。
下面是一个DTCRAM 256K、ITCRAM 128K、OCRAM 128K的分配例子。

/* RT1052/1064 内部SRAM一共分为16个blank 每个blank 都可以选择类型 
     * A bank size of 512 kB / 16 = 32 kB
     * IOMUXC_GPR_GPR17寄存器一共32位, 每两位控制一个blank的类型
     * 00b—bank is not used.
     * 01b—bank is configured for OCRAM.
     * 10b—bank is configured for DTCM.
     * 11b—bank is configured for ITCM.
     */
IOMUXC_GPR->GPR17 = IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG(0x55AAAAFF); 

    /*! CM7_CFGITCMSZ
     *  0b0000..0 KB (No ITCM)
     *  0b0011..4 KB
     *  0b0100..8 KB
     *  0b0101..16 KB
     *  0b0110..32 KB
     *  0b0111..64 KB
     *  0b1000..128 KB
     *  0b1001..256 KB
     *  0b1010..512 KB
     */
    IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_MASK;
    IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGITCMSZ(8);
    IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_ITCM_EN(1);

    /*! CM7_CFGDTCMSZ
     *  0b0000..0 KB (No DTCM)
     *  0b0011..4 KB
     *  0b0100..8 KB
     *  0b0101..16 KB
     *  0b0110..32 KB
     *  0b0111..64 KB
     *  0b1000..128 KB
     *  0b1001..256 KB
     *  0b1010..512 KB
     */
    IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_MASK;
    IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ(9);
    IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_DTCM_EN(1);

    /* 使能配置 */
    IOMUXC_GPR->GPR16 &= ~IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK;
    IOMUXC_GPR->GPR16 |=  IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL(1);

动态内存分配最好在堆栈初始化之前,因此我们需要将上面的代码转换为对应的RAM汇编代码,放在复位中断服务函数堆栈初始化前面,打开启动文件startup_MIMXRT10XX.s文件,找到Reset_Handler的汇编函数,添加对应汇编代码。

FLEXRAM_BANK_CFG    EQU 0x55AAAAFF 
ITCRAM_SIZE         EQU 0x8;128KB 0: 0KB    6: 32KB  7: 64KB  8: 128KB  9: 256KB  10: 512KB
DTCRAM_SIZE         EQU 0x9;256KB 0: 0KB    6: 32KB  7: 64KB  8: 128KB  9: 256KB  10: 512KB

Reset_Handler
        CPSID   I               ; Mask interrupts

        ;IOMUXC_GPR->GPR17 = IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG(0x55AAAAFF); 
        LDR R0, = 0x400AC044          ; 将IOMUXC_GPR->GPR17的地址放到 寄存器R0中
        LDR R1, = FLEXRAM_BANK_CFG    ; 将BANK划分结果放到 寄存器R1中
        STR R1, [R0]                  ; 将R1 存放到IOMUXC_GPR->GPR17中

        ;IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_MASK;
        ;IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_MASK;
        LDR R0, = 0x400AC038          ; 将IOMUXC_GPR->GPR14的地址放到 寄存器R0中
        LDR R2, [R0]
        LDR R3, = 0x00FFFF
        AND R1,  R2, R3               ; R1 = IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_MASK中
        STR R1, [R0]                  ; 将R1 存放到IOMUXC_GPR->GPR14中

        ;IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGITCMSZ(ITCRAM_SIZE);
        ;IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ(DTCRAM_SIZE);
        LDR R1, = ITCRAM_SIZE
        MOV  R2, R1,LSL#16

        LDR R1, = DTCRAM_SIZE
        MOV  R3, R1,LSL#20
        ORR R1, R2, R3
        LDR R2, [R0]
        ORR R1, R1, R2
        STR R1, [R0]  

        ;IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_ITCM_EN(1);
        ;IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_DTCM_EN(1);
        ;IOMUXC_GPR->GPR16 |=  IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL(1);
        LDR R0, = 0x400AC040
        LDR R1, [R0]
        ORR R1, R1, #0x7
        STR R1, [R0]  


        LDR     R0, =0xE000ED08
        LDR     R1, =__vector_table
        STR     R1, [R0]
        LDR     R2, [R1]
        MSR     MSP, R2
        LDR     R0, =SystemInit
        BLX     R0
        CPSIE   I               ; Unmask interrupts
        LDR     R0, =__iar_program_start
        BX      R0

最后修改分散加载文件中地址空间分配、修改MPU配置

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器