mdk keil 指定变量、函数存储位置,使用 Scatter-Loading Description File, __attribute__(("section“))

0. 数据类型说明

主要包括4类:

  1. Code (inc. data) ,属于RO,也就是写的函数代码(包括代码中的变量)
  2. RO Data , 属于RO,使用const修饰的变量。
  3. RW Data, 属于RW,变量。
  4. 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 机构体初始化

 

posted @ 2018-05-11 19:44  QIYUEXIN  阅读(13140)  评论(2编辑  收藏  举报