1. 程式人生 > >mdk keil 指定變量、函數存儲位置,使用 Scatter-Loading Description File, __attribute__(("section“))

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

最大 type 內存分區 stdin script bsp attr 出現 name

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 機構體初始化。

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