IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> i.MX RT1064学习记录-1 使用Keil MDK IDE分配RAM空间 -> 正文阅读

[嵌入式]i.MX RT1064学习记录-1 使用Keil MDK IDE分配RAM空间

引言

为什么要分配RAM?

??从速度的角度看,将所有的用户代码分配 ITCM/DTCM,能够发挥到最大性能,从存储空间大小的角度看,代码存放在 SDRAM 或者外部 Flash 最简单,而从 USB/DMA 使用的角度来看, RAM 空间分配在 OCRAM 空间最为方便。所以这些不同 RAM 类型速度/大小的差异和 cache 的存在,就决定了要想让 IMXRT 性能发挥到最大,就需要用户根据客户实际应用手动修改内部 RAM 空间中ITCM/DTCM/OCRAM 的大小分配,并定位关键代码和数据到指定 RAM 空间中运行。

1 RT1064 内存分布

1.1 RAM

??RT1064共有1MB片内SRAM,其中512KB为固定OCRAM,其余512K为ITCM、DTCM、OCRAM自由分配。

  1. ITCM:指令紧耦合缓存(Instruction Tightly-Coupled Memory),直接挂在芯片内核总线,速度可达与内核同频的600M,总线宽度为64位,默认大小为128KB,用于缓存需要高速执行的指令,基地址为:0x0000 0000
  2. DTCM:数据紧耦合缓存(Data Tightly-Coupled Memory),与ITCM一样挂在芯片内核总线,速度可达600M,总线宽度为两个32位,默认大小为128KB,用于缓存需要高速访问的数据,基地址为:0x2000 0000
  3. OCRAM:片上RAM(On-Chip RAM), 挂在 Sys AXI 64 位总线,速度只能到达133M,默认大小为256+512KB,总线宽度为32位,用于缓存数据,基地址为:0x2020 0000

1.2 Flash

??RT1064芯片内部自带4MB的Flash,用于存储代码,它连接至RT1064的FlexSPI2外设的A1端口,支持XIP,基地址为:0x7000 0000

1.3 扩展片外空间

??RT1064可提供多样的外部内存拓展接口,包括SDRAM,RAW,NAND FLASH, NOR FLASH, SD/eMMC, QuadSPI.

2 基础环境配置

??打开Options for Target ,在Target栏中编译器选择ARM Compiler 6(AC5编译器太慢了,ARM已停止维护),关于AC5向AC6的移植可以去ARM官网查看相应文档。
在这里插入图片描述

2.1 C/C++配置

在这里插入图片描述

  1. 添加以下全局宏
XIP_EXTERNAL_FLASH=1,  //! USB1 PLL保持不变
CPU_MIMXRT1064DVL6A,
DEBUG, 
SKIP_SYSCLK_INIT,     //! system PLL保持不变
XIP_BOOT_HEADER_DCD_ENABLE=1,
XIP_BOOT_HEADER_ENABLE =1,
PRINTF_FLOAT_ENABLE=1,
SCANF_FLOAT_ENABLE=1, 
PRINTF_ADVANCED_ENABLE=1, 
SCANF_ADVANCED_ENABLE=1,
FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ=0,
  1. 选择AC5-like Warnings
    警告级别与AC5编译器一样,会提示相对比较严重的警告,对于一些不太重要的警告不会提示。AC6编译器比较严格可能会出现许多警告。
  2. 选择C99标准
    Pack NXP.MIMXRT1064_DFP.13.1.0: Required C 99
  3. 添加以下GCC编译选项(Misc Controls)
-fno-common     // 避免出现弱符号(未初始化的变量)与强符号(函数和已初始化的变量)同名、多个弱符号同名时的不确定性。
-fdata-sections // 移除未使用的数据,减少最终可执行程序大小
-ffreestanding  // C编译器只需提供基本的库函数,基础的printf是不能使用的。
-fno-builtin    // 不接受没有 __builtin_ 前缀的函数作为内建函数,主要作用是防止自定义的函数可以与C库内建函数同名
-mthumb         // 生成的目标文件是Thumb

参考文献:gcc -fno-commongcc -fdata-sectionsgcc -ffreestanding

2.2 Asm配置

在这里插入图片描述

  1. 指定汇报条件
__STARTUP_INITIALIZE_NONCACHEDATA // 确保不可缓存的section变量将在系统启动时初始化
  1. 编译器选择
    选择armasm工具,编译ARM汇编代码(不能编译GNU汇编代码。

3 RT1064 RAM 分配寄存器

3.1 IOMUXC_GPR->GPR17(0x400AC044)

i.MX RT系列的片内512K可分配RAM 分成16个BANK,每个BANK由 32 位寄存器IOMUXC_GPR->GPR17中的两位来确定类型。

00b—bank is not used.
01b—bank is configured for OCRAM
10b—bank is configured for DTCM.
11b—bank is configured for ITCM.

共有16种可分配情况:
在这里插入图片描述
O - OCRAM D - DTCM I - ITCM
注意OCRAM最少需要分配64KB,这是因为ROM代码要求至少64KBRAM才能执行。

3.2 IOMUXC_GPR->GPR14(0x400AC038)

配置完IOMUXC_GPR->GPR17寄存器,确定每个BANK的类型后,修改寄存器IOMUXC_GPR->GPR14确定对应TCM(DTCM + ITCM)的空间大小。我们只需关心23~2019~16bits。

  • DTCM(23~20 bits)分配:
0000 0KB
0011 4KB
0100 8KB
0101 16KB
0110 32KB
0111 64KB
1000 128KB
1001 256KB
1010 512KB
other reserved
  • ITCM(19~16 bits)分配与DTCM位操作一致。

3.3 IOMUXC_GPR->GPR16(0x400AC040)

IOMUXC_GPR->GPR16可以控制是否使能开启分配的内存空间,我们主要关心其第0~2bits。

  • 使能ITCM:对此寄存器第0位操作,写0 - disable,写1 - enable。
  • 使能DTCM: 对此寄存器第1位操作,写0 - disable,写1 - enable。
  • 使能RAM BANK分配功能: 对此寄存器第2位操作,写0 - 用fuse参数配置,写1 - 用FLEXRAM块配置。

4 启动文件嵌入RAM分配寄存器汇编代码

??动态内存分配最好在堆栈初始化之前,因此我们需要将RAM分配寄存器C代码转换为对应的RAM汇编代码,放在复位中断服务函数堆栈初始化前,打开启动文件startup_MIMXRT10XX.s文件,找到Reset_Handler的汇编函数,添加对应汇编代码。
下面以ITCM = 128KBDTCM = 256 KBOCRAM = 128 + 512 = 640KB为例:

4.1 RAM分配寄存器C代码

//使能FLEXRAM BANK分配配置
IOMUXC_GPR->GPR16 &= ~IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_MASK;
IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL(1);
// 分配RAM BANK
IOMUXC_GPR->GPR17 = IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG(0x55AAAAFF);
// 使能与分配ITCM
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);
// 使能与分配DTCM
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);

4.2 汇编部分代码

转换后的汇编代码:

FLEXRAM_BANK_CFG    EQU 0x55AAAAFF
ITCRAM_SIZE         EQU 0x8 ;128KB 00KB    632KB  764KB  8128KB  9256KB  10: 512KB
DTCRAM_SIZE         EQU 0x9 ;256KB 00KB    632KB  764KB  8128KB  9256KB  10: 512KB
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  SystemInit
                IMPORT  __main

                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, =__Vectors
        STR     R1, [R0]
        LDR     R2, [R1]
        MSR     MSP, R2
        LDR     R0, =SystemInit
        BLX     R0
        CPSIE   i               ; Unmask interrupts
        LDR     R0, =__main
        BX      R0
        ENDP

在官方board.c中修改相应宏:

    /* Region 4 setting: Memory with Normal type, not shareable, outer/inner write back */
    MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB);  //! ITCRAM

    /* Region 5 setting: Memory with Normal type, not shareable, outer/inner write back */
    MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB); //! DTCRAM

    /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */
    MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U);
    MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); //! OCRAM

5 使用分散加载文件将关键代码和数据到指定RAM中运行

在这里插入图片描述

  1. 取消勾选使用MDK在Target配置信息自动生成的分散加载文件。
    注意:此时Target中ROM与RAM的配置不起任何作用。
    在这里插入图片描述
  2. 为防止编译器优化掉没有被显示调用的模块,在Misc controls添加以下代码:
--remove 
--keep=*(.boot_hdr.ivt) 
--keep=*(.boot_hdr.boot_data) 
--keep=*(.boot_hdr.conf) 
--predefine="-DXIP_BOOT_HEADER_ENABLE=1"

不添加会报以下错误:

//分散加载文件中的text段没有使能
Error: L6218E: Undefined symbol Image$$RW_m_config_text$$Base (referred from fsl_flexspi_nor_boot.o).
Not enough information to list load addresses in the image map.
  1. 点击Edit开始编写分散加载文件
#!armclang --target=arm-arm-none-eabi -mcpu=cortex-m7 -E -x c

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

#define m_ivt_start                    0x70001000
#define m_ivt_size                     0x00001000

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

/* ITCRAM 中断向量表 */
#define itcram_interrupts_start        0x00000000
#define itcram_interrupts_size         0x00000400

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

// DTCRAM 256K
#define dtcram_start                   0x20000000
#define dtcram_size                    0x00040000

// OCRAM 640K 512K固定RAM + 128K分配RAM
#define ocram_start                    0x20200000
#define ocram_size                     0x000A0000

// IACRAM 128K 不能从0x00000000开始
#define itcram_start                   0x00000400
#define itcram_size                    0x0001FC00 


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

// 堆大小 动态分配malloc分配的空间 1K
#if (defined(__heap_size__))
  #define Heap_Size                    __heap_size__
#else
  #define Heap_Size                    0x0400
#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)
    startup_mimxrt1064_ram.o(+RO)
	system_mimxrt1064.o(+RO)
  }
  
  /* ITCRAM 中断向量表 >EMPTY表示这段空间留空,防止其它应用占用或编译提示warning */
  VECTOR_RAM itcram_interrupts_start EMPTY itcram_interrupts_size { ;execution address

  }
  
  /* ITCRAM段 */
  ER_m_ram_text itcram_start itcram_size{ ; RW data
	.ANY (+RO)
	* (ITCM_NonCacheable.init)
    * (*ITCM_NonCacheable)
  }
  
  /* DTCRAM段 */
  DTCRAM_region dtcram_start dtcram_size-Stack_Size{ ; RW data
    .ANY (+RW)
	.ANY (+ZI)
	* (NonCacheable.init)
    * (*NonCacheable)  // .bss.xx
  } 
  
  /* OCRAM段 */
  OCRAM_region ocram_start ocram_size{ ; 
	* (OCRAM_CACHE.init)
    * (*OCRAM_CACHE) // .bss.xx
  }
  
  /* 堆区域  */
  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
  }  
}

注意:AC6编译器分散加载文件第一行为:#!armclang --target=arm-arm-none-eabi -mcpu=cortex-m7 -E -x c,AC5编译器为:#! armcc -E。还有此语句后面不能添加注释,否则会报错。
RAM与Flash各段内存分配说明:

加载域执行域输入节区
域名:LR_m_text
起始地址:m_flash_config_start(0x70000000)
最大容量:m_text_start+m_text_size-m_flash_config_start=0x70400000
域名:RW_m_config_text
起始地址:0x70000000
最大容量(固定):0x00001000
将QSPI FLASH 参数存放至该执行域的第一个地址
域名:RW_m_ivt_text
起始地址:0x70001000
最大容量:0x00001000
加载域 = 执行域存放ivt、 boot_data、dcd_data,并将ivt存放至该执行域的第一个地址
域名:VECTOR_ROM
起始地址:0x70002000
最大容量:0x00000400
加载域 = 执行域存放中断向量表,RESET程序从此地址开始加载
域名:TEXT_region
起始地址:0x70002400
最大容量(固定):0x003FDC00
加载域 = 执行域存放代码,即code
域名:VECTOR_RAM
起始地址:0x00000000
最大容量:0x00000400
加载域 = 执行域为将Flash中的中断向量表存放到ITCRAM而开辟空间,EMPTY表示将执行域中保留一个给定长度的空白内存块,防止其它应用占用或编译提示warning
域名:ER_m_ram_text
起始地址:0x00000400
最大容量:0x0001FC00
加载域 = 执行域ITCRAM段:存放RO段和在程序中指定存放至此区域的数据。注意:起始地址不能从0x00000000开始
域名:DTCRAM_region
起始地址:0x20000000
最大容量:dtcram_size - Stack_Size
加载域 = 执行域DTCRAM段:存放RW段、ZI段和在程序中指定存放至此区域的数据,其中ZI段包括未初始化的堆栈空间
域名:OCRAM_region
起始地址:0x20200000
最大容量:0x000A0000
加载域 = 执行域OCRAM段:存放在程序中指定存放至此区域的数据
域名:ARM_LIB_HEAP
起始地址:前一个加载域OCRAM_region的尾地址
最大容量:0x0400
加载域 = 执行域存放堆区数据
域名:ARM_LIB_STACK
起始地址:dtcram_start+dtcram_size
最大容量:-0x1000
加载域 = 执行域存放栈区数据,注意:栈是从起始地址开始向下增长的

从上述分析中可看出,我将RO段、RW段、ZI段全部分配到了TCM中,使系统性能达到最大化。
4. 将Flash中的中断向量表复制到 ITCRAM 中,并重定位向量表。在system_MIMXRT1064.c中填下如下代码:

	uint32_t * VECTOR_RAM ;  //获取在RAM(ITCRAM)中的中断向量表起始地址
    uint32_t * VECTOR_TABLE; //获取在FLASH中的中断向量表起始地址
    uint32_t RAM_VECTOR_TABLE_SIZE = 0x400;

	VECTOR_RAM = (uint32_t *)0x00000000;
	VECTOR_TABLE = (uint32_t *)0x70002000; 
	
    uint32_t vector_size = ((uint32_t)RAM_VECTOR_TABLE_SIZE)/4;//获取中断向量表大小
    
    while(vector_size--)
    {
        VECTOR_RAM[vector_size] = VECTOR_TABLE[vector_size];
    }
    
    SCB->VTOR = (uint32_t)VECTOR_RAM;

6 在程序中将数据分配到指定内存

fsl_common.h中(/* __FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE */后面)添加以下代码:

#if (defined(__ICCARM__))
	//定义将代码放在ITCM的方式
    #define AT_ITCM_SECTION_ALIGN(var, alignbytes) \
			__attribute__((section(".bss.ITCM_NonCacheable"))) __attribute__((aligned(alignbytes))) var
	//定义将代码或者变量放在DTCM的方式
	#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
        #define AT_DTCM_SECTION(var) var @"NonCacheable"
        #define AT_DTCM_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable"
        #define AT_DTCM_SECTION_INIT(var) var @"NonCacheable.init"
        #define AT_DTCM_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"NonCacheable.init"
    #endif 
	//定义将代码或者变量放在OCRAM的方式
	#define AT_OCRAM_SECTION(var) var @"OCRAM_CACHE"
    #define AT_OCRAM_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"OCRAM_CACHE"
    #define AT_OCRAM_SECTION_INIT(var) var @"OCRAM_CACHE.init"
    #define AT_OCRAM_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"OCRAM_CACHE.init"
	//定义将代码或者变量放在SDRAM的方式
	#define AT_SDRAM_SECTION(var) var @"SDRAM_CACHE"
    #define AT_SDRAM_SECTION_ALIGN(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"SDRAM_CACHE"
    #define AT_SDRAM_SECTION_INIT(var) var @"SDRAM_CACHE.init"
    #define AT_SDRAM_SECTION_ALIGN_INIT(var, alignbytes) SDK_PRAGMA(data_alignment = alignbytes) var @"SDRAM_CACHE.init"

#elif(defined(__CC_ARM) || defined(__ARMCC_VERSION))
	//定义将代码放在ITCM的方式
    #define AT_ITCM_SECTION_ALIGN(var, alignbytes) \
		__attribute__((section(".bss.ITCM_NonCacheable"))) __attribute__((aligned(alignbytes))) var
	#define AT_ITCM_SECTION_ALIGN_INIT(var, alignbytes) \
		__attribute__((section("ITCM_NonCacheable.init"))) __attribute__((aligned(alignbytes))) var
	//定义将代码或者变量放在DTCM的方式
	#if ((!(defined(FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION) && FSL_FEATURE_HAS_NO_NONCACHEABLE_SECTION)) && defined(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE))
        #if(defined(__CC_ARM))
			#define AT_DTCM_SECTION(var) __attribute__((section("NonCacheable"), zero_init)) var
			#define AT_DTCM_SECTION_ALIGN(var, alignbytes) \
				__attribute__((section("NonCacheable"), zero_init)) __attribute__((aligned(alignbytes))) var
		#else
			#define AT_DTCM_SECTION(var) __attribute__((section(".bss.NonCacheable"))) var
			#define AT_DTCM_SECTION_ALIGN(var, alignbytes) \
				__attribute__((section(".bss.NonCacheable"))) __attribute__((aligned(alignbytes))) var
		#endif

        #define AT_DTCM_SECTION_INIT(var) __attribute__((section("NonCacheable.init"))) var
        #define AT_DTCM_SECTION_ALIGN_INIT(var, alignbytes) \
            __attribute__((section("NonCacheable.init"))) __attribute__((aligned(alignbytes))) var
    #endif
	
	//定义将代码或者变量放在OCRAM的方式
    #if(defined(__CC_ARM))
		#define AT_OCRAM_SECTION(var) __attribute__((section("OCRAM_CACHE"), zero_init)) var
		#define AT_OCRAM_SECTION_ALIGN(var, alignbytes) \
			__attribute__((section("OCRAM_CACHE"), zero_init)) __attribute__((aligned(alignbytes))) var
	#else
		#define AT_OCRAM_SECTION(var) __attribute__((section(".bss.OCRAM_CACHE"))) var
		#define AT_OCRAM_SECTION_ALIGN(var, alignbytes) \
			__attribute__((section(".bss.OCRAM_CACHE"))) __attribute__((aligned(alignbytes))) var
	#endif

    #define AT_OCRAM_SECTION_INIT(var) __attribute__((section("OCRAM_CACHE.init"))) var
    #define AT_OCRAM_SECTION_ALIGN_INIT(var, alignbytes) \
        __attribute__((section("OCRAM_CACHE.init"))) __attribute__((aligned(alignbytes))) var  
#endif  

使用方式如下:

AT_DTCM_SECTION_ALIGN(数据类型 数据结构, 字节对齐数);

示例

AT_ITCM_SECTION_ALIGN(uint8_t itram, 8); //至少8字节对齐
AT_DTCM_SECTION_ALIGN(uint8_t dtram, 64);
AT_OCRAM_SECTION_ALIGN(uint8_t ocram[100][50], 16);
AT_OCRAM_SECTION_ALIGN_INIT(uint8_t ocramx, 32);

map文件中查看分配的内存起始地址、类型、大小等信息:

Exec Addr    Load Addr    Size         Type   Attr      Idx    E Section Name        Object
// itram
0x00015218        -       0x00000001   Zero   RW         5811    .bss.ITCM_NonCacheable  ips_display.o
// dtram
0x20000080        -       0x00000001   Zero   RW         5811    .bss.NonCacheable   ips_display.o
// ocram[100][50]
0x20200010        -       0x00001388   Zero   RW         5812    .bss.OCRAM_CACHE    ips_display.o
// ocramx
0x20200000   0x700177c0   0x00000001   Data   RW         5813    OCRAM_CACHE.init    ips_display.o

不建议将变量存放在ITCM,因为程序是从此区域启动加载的。

END

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-04 13:00:11  更:2021-10-04 13:00:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:42:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码