文章目录
- 1 前言
- 2 实现方法
- 3 例子
1 前言
编译过程中,指定数据绝对存储地址在实际项目中会经常使用到或者必须用到,这样使得项目实现某些功能可以非常灵活,常用的场景有:
-
IAP升级时候,中断向量表存储
IAP升级,STM32F0系列Cortex-M0内核芯片,192字节中断向量表需存储在RAM起始地址(0x20000000)中 -
在指定flash地址存储固件信息,用于查询固件信息,或者升级过程对固件进行校验
—项目名称
—项目唯一id号
—版本号
—编译时间
—编译器版本
2 实现方法
指定数据绝对存储地址,实现方法与编译器相关,不同编译器实现方式不一样;常用的有Keil、IAR、Gcc,Keil AC5和AC6版本编译器实现方法也不同。
例如,定义一个u32变量data,存储起始地址在0x20010000上,不同编译器下实现如下。
- Keil AC5编译器:
uint32_t data __attribute__((at(0x20010000)));
- Keil AC6编译器:
uint32_t data _attribute__ ((section(".ARM.__at_0x20010000")));
- IAR编译器:
#pragma location = 0x20010000
__no_init uint32_t data;
__root __no_init uint32_t data @0x20010000
__root:强制函数或者变量不被编译器优化;函数或者变量没有被任何函数引用的情况下,编译器可能会将其优化掉。
__no_init 强制不执行内存初始化动作;正常情况下,应用程序启动时,IAR将全部全局和静态变量初始化为0,__no_init声明的变量不会执行初始化。
“@”是IAR中的地址操作符,通过“@”或“#program location ”指令来把全局变量/静态变量/代码Text 存放到绝对存储地址空间上;即是“#pragma location = address” 等价于 “@ address”
3 例子
以STM32为例,指定flash地址空间存储固件信息。
/* 固件信息 */
typedef struct __attribute__ ((packed)) project_info
{char name[20]; /* 项目名称 */char id; /* 项目ID */char ver_major; /* 主版本号 */char ver_minor; /* 次版本号 */char ver_revision; /* 修订版本号 */char build_date[12]; /* 编译日期 */char build_time[10]; /* 编译时间 *//* todo : other info */
} project_info_t;/* 声明指定存储地址 */
#define PROJECT_INFO_ADDR 0x08024000U#if defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil */
#if defined ( __CC_ARM ) /* AC5 */#define __AT(__ADDR) __attribute__ ((at(__ADDR), used))
#elif defined ( __ARMCC_VERSION ) /* AC6 */#define __AT(__ADDR) __attribute__ ((section(".ARM.__at_" #__ADDR)))
#endif /* __CC_ARM */
#define AT_ADDR(__ADDR) __AT(__ADDR)
const project_info_t project_info AT_ADDR(PROJECT_INFO_ADDR) =
#elif defined(__ICCARM__) /* IAR */
#define AT_ADDR(__ADDR) __AT(__ADDR)
#pragma location = PROJECT_INFO_ADDR
__root const project_info_t project_info @PROJECT_INFO_ADDR =
#else
#error Not select compiler.
#endif /* __CC_ARM || __ARMCC_VERSION */
{.name = "xxx",.id = 0xAA,.ver_major = 1,.ver_minor = 0,.ver_revision = 0,.build_date = __DATE__, .build_time = __TIME__,
};