mdk keil 指定变量、函数存储位置,使用 Scatter-Loading Description File, __attribute__(("section“))
0. 数据类型说明
主要包括4类:
- Code (inc. data) ,属于RO,也就是写的函数代码(包括代码中的变量)
- RO Data , 属于RO,使用const修饰的变量。
- RW Data, 属于RW,变量。
- ZI Data, 属于RW,没有初始化的变量。
1. mdk 设置Scatter 文件
默认情况下,片内会有两大存储块IROM(只读存储器RO,用来存常量、代码等),IRAM(读写存储器RW,用来存变量,包括被默认初始化为0的变量),如下图 "Target"选项卡。
来看“Linker”选项卡,下面介绍操作:
1. 默认的选项是使用的“Target”的内存分区,需要把这个勾去掉。
2. 去掉勾后会出现一个“.sct"文件,点击Edit就可以修改了,对文件做了注释说明如下:
LR_IROM1 0x08000000 0x00080000 { ; load region size_region, 装载区域 ; LR_IROM1, 这是一个名字,随便起。可以理解为一块存储器的名字。 ; 0x08000000,这是起始地址。 ; 0x00080000,代表size,也就是存储器的最大空间。 ER_IROM1 0x08000000 0x00080000 { ; load address = execution address, 执行区域 *.o (RESET, +First) ; *.o, 是说对于任意的".o"文件 ; RESET 是说含有“RESET”的section名称的 ; +First 是说最先匹配 ; 合起来就是在所有的“.o”文件中找到含有“RESET”字段的内容放到“ER_IROM1"这块存储区域内 *(InRoot$$Sections) .ANY (+RO) ; '.ANY' 可以理解成 '*' ,是说把剩下的RO类型的数据(常量和代码)放到这里。 } RW_IRAM1 0x20000000 0x00010000 { ; RW data .ANY (+RW +ZI) ; 是说把剩下的RW,ZI类型的数据(常量和代码)放到这里。 } }
从上面可以看到这里只做了两个区分,大体上就是RO和RW的区别,下面说明自定义区域。
3. 这里我们定义两个区域,一个用来存放函数,一个用来存放数据:
LR_IROM1 0x08000000 0x00080000 { ; load region size_region ER_IROM1 0x08000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } MY_FUN 0x20000000 0x00000080 { ; 自定义函数存储位置,地址及大小仅作说明。 .ANY (pg_fun) } MY_DATA 0x20000080 0x00000080 { ; 自定义数据存储位置,地址及大小仅作说明。 .ANY (pg_data) } RW_IRAM2 0x20000100 0x0000FF00 { .ANY (+RW +ZI) ; RW data } }
4. 在“inc.h"头文件中:
#define PG_FUN_ATTRIBUTES __attribute__ ((section("pg_fun"))) #define PG_DATA_ATTRIBUTES __attribute__ ((section("pg_data"))) void test1 (void);
5. 在”test.c"文件中:
#include "inc.h" typedef struct tt{ // 自定义结构体 int a; double b; }tt_t; // 变量定义,分配到定义的数据区域内 static tt_t t0 PG_DATA_ATTRIBUTES = { .a = 1, .b = 2, }; static char t1[10] PG_DATA_ATTRIBUTES; // 函数定义,分配到定义的函数区域内 void test1 PG_FUN_ATTRIBUTES() { t0.a = 1; }
6. 在“main.c"文件中:
#include "stm32f10x.h" #include <stdint.h> #include "inc.h" #include <stdio.h> static char tc2[5] PG_DATA_ATTRIBUTES; void foo PG_FUN_ATTRIBUTES() { tc2[0] = 2; } int main() { foo(); test1(); return 0; }
7. 文件“test.map" 查看结果:
Execution Region MY_FUN (Base: 0x20000000, Size: 0x00000018, Max: 0x00000080, ABSOLUTE) Base Addr Size Type Attr Idx E Section Name Object 0x20000000 0x0000000c Code RO 5 pg_fun main.o 0x2000000c 0x0000000c Code RO 150 pg_fun test.o Execution Region MY_DATA (Base: 0x20000080, Size: 0x0000002c, Max: 0x00000080, ABSOLUTE) Base Addr Size Type Attr Idx E Section Name Object 0x20000080 0x00000005 Data RW 6 pg_data main.o 0x20000085 0x00000003 PAD 0x20000088 0x00000022 Data RW 151 pg_data test.o
可以看到,函数和代码都以如愿以偿。
结构体编译出错,参考这篇文章:MDK KEIL 机构体初始化。