AURIX™ TC3xx MCAL中Link文件解析以及代碼變量定位方法詳解

作者:英飛凌AURIX™技術專家 張馳

一 TC3xx系列MCAL中TASKING Link文件解析以及代碼變量定位方法


1 TASKING Link文件解析

1.1 DSRAM中的數據存放:

在AURIX™ 2G中(以TC387為例),每個CPU都有自己的PSRAM (又稱PSPR)和DSRAM (又稱DSPR),它們都是RAM,只不過PSRAM是掛在指令總線上,而DSRAM是掛在數據總線上,因此如果在PSRAM運行代碼,DSRAM存放數據,可以達到0 cycle等待。但是PSRAM上也是可能存放數據的,只不過效率低一點。

DSRAM的起始地址如下: 

CPU0 DSRAM

0x70000000

CPU1 DSRAM

0x60000000

CPU2 DSRAM

0x50000000

CPU3 DSRAM

0x40000000

 

在MCAL的TASKING link文件中,對於數據的存放如下圖所示:

  

CSA: 

CSA是用來在函數調用或者進出中斷時用來保存通用寄存器的區域,具體可到英飛凌官網(www.infineon.com)查看“AURIX™ TC3xx Architecture”用戶手冊。它的大小由LCF_CSAx_SIZE決定。

 

ISTACK: 

在中斷服務程序中使用的棧,它的大小由LCF_ISTACKx_SIZE決定。

 

USTACK: 

在用戶程序中使用的棧,它的大小由LCF_USTACKx_SIZE決定。

 

Heap: 

程序中使用的堆,它的大小由LCF_HEAP_SIZE決定。

 

Predefine Data/Data: 

Data區域是用來存放帶初始化值的全局變量,在link文件中,這個區域有兩種類型,預先定義的區域和默認區域。 

預先定義的Data區域,例如.data.Ifx_Ssw_Tc1和.data.Cpu1_Main.*,在cpu1_main.c中如果定義了一個帶初始化值的變量,則它會放在DSRAM1中的.data.Cpu1_Main.*段中。 

 

group (orderedattributes=rw, run_addr=mem:dsramx)

        {

          select".data.Ifx_Ssw_Tcx.*";

          select".data.Cpux_Main.*";

          …

}

 

 

而如果在一個其他.c文件(例如demo.c)中定義了一個帶初始化值的變量,則它會放在DSRAM0中data區域(即默認區域),這個由Link文件中下面語句決定: 

 

#    if LCF_DEFAULT_HOST == LCF_CPU0

    group (orderedcontiguousalign = 4, attributes=rw, run_addr = mem:dsram0)

#    endif

    {

      group data(attributes=rw)

      {

        select".data.*";

        select".data.farDsprInit.cpu0.32bit";

        select".data.farDsprInit.cpu0.16bit";

        select".data.farDsprInit.cpu0.8bit";

      }

      …

}

 

 

Predefine BSS/BSS: 

BSS區域是用來存放沒有初始值的全局變量,在link文件中,這個區域有兩種類型,預先定義的區域和默認區域, 預先定義的BSS區域,例如.bss.Ifx_Ssw_Tc1和.bss.Cpu1_Main.*,在cpu1_main.c中如果定義了一個帶初始化值的變量,則它會放在DSRAM1中的.bss.Cpu1_Main.*段中。 

 

group (orderedattributes=rw, run_addr=mem:dsramx)

        {

          select".bss.Ifx_Ssw_Tcx.*";

          select".bss.Cpux_Main.*";

          …

}

 

 

而如果在一個其他.c文件(例如demo.c)中定義了一個不帶初始化值的變量,則它會放在DSRAM0中BSS區域(即默認區域),這由Link文件中下面語句決定: 

 

#    if LCF_DEFAULT_HOST == LCF_CPU0

    group (orderedcontiguousalign = 4, attributes=rw, run_addr = mem:dsram0)

#    endif

    {

      group bss(attributes=rw)

      {

        select".bss.*";

        select".bss.farDsprClearOnInit.cpu0.32bit";

        select".bss.farDsprClearOnInit.cpu0.16bit";

        select".bss.farDsprClearOnInit.cpu0.8bit";

      }      

 …

}

 

 

1.2 PFlash中的代碼存放 

TC3xx的Flash是以3MB或者1MB作為一個Bank,不用Cache的地址從0xA0000000開始,用Cache的地址從0x80000000開始。

 

 在MCAL的Link文件中,常量和代碼的存放如下圖所示:

  

Predefined text/text: 

Text段用來存放代碼,它分為兩種:一種是預先定義好的text段,另外一種默認的text段。 

預先定義好的text段,例如.text.Cpu1_Main.*,  在Cpu1_Main.c中的代碼會放在這個段內。 

 

group (orderedalign = 4, run_addr=mem:pflsx)

        {

          select".text.Ifx_Ssw_Tcx.*";

          select".text.Cpux_Main.*";

          select".text.text_cpux*";

          select"*Code.Cpux";

          select"*Code.Fast.Cpux";

        }

 

 

但是如果是其他.c文件(例如demo.c),則會放在默認的text段中,這個是由Link文件中下面語句決定的: 

 

#    if LCF_DEFAULT_HOST == LCF_CPU0

    group (orderedrun_addr=mem:pfls0)

#    endif

    {

      select".text.*";

      select".text.fast.pfls.cpu0";

      select".text.slow.pfls.cpu0";

      select".text.5ms.pfls.cpu0";

      select".text.10ms.pfls.cpu0";

      select".text.callout.pfls.cpu0";

     }

 

 

Predefined rodata/rodata: 

rodata段用來存放代碼,它分為兩種:一種是預先定義好的rodata段,另外一種默認的rodata段。 

預先定義好的rodata段,例如.rodata.Cpu1_Main.*,在Cpu1_Main.c中的常量會放在這個段內。 

 

group (orderedalign = 4, run_addr=mem:pflsx)

      {

        select".rodata.Ifx_Ssw_Tcx.*";

        select".rodata.Cpux_Main.*";

}

 

 

但是如果是其他.c文件(例如demo.c),則會放在默認的rodata段中,這個由Link文件中下面語句決定: 

 

#    if LCF_DEFAULT_HOST == LCF_CPU0

    group (orderedalign = 4, run_addr=mem:pfls0)

#    endif

    {

      select".rodata.*";

      select".rodata.farConst.cpu0.32bit";

      select".rodata.farConst.cpu0.16bit";

      select".rodata.farConst.cpu0.8bit";

    }

   }

 

 

1.3 (d)LMU 

LMU分為各個CPU私有的dLMU和共用的LMU兩部分,在MCAL中的Link文件中只是定義了LMU的幾個段,在工程中並沒有用到這個區域,關於怎麼把變量放到LMU中,請看第2.2和2.3章。

 

1.4 PSRAM 

每個CPU都有自己的PSRAM區域,這個區域可以運行程序,也可以存放數據,在Link中只是定義了幾個段,在工程中並沒有用到這個區域,關於怎麼在這個區域運行程序,請看第2.4章。

 

1.5 UCB 

UCB是配置MCU參數的一塊區域,關於怎麼在程序中配置UCB區域,請看第2.7章。

 

2 代碼和變量定位


2.1 把變量放在DSRAM 

2.1.1 把變量放在固定位置

如果需要把變量放在固定位置,則需要在Link文件中,首先定義一個data段,從0x7001000開始,一個bss段,從0x70004000開始。 

 

/*Far Data / Far Const Sections, selectable with  patterns and user defined sections*/

  section_layout :vtc:linear

  {

    /*Far Data Sections, selectable with patterns and  user defined sections*/

    group

    {

        …

     

        group (orderedattributes=rw, run_addr=0x70001000)

        {

          select".bss.user_test_bss";

        }

       

        group (orderedattributes=rw, run_addr=0x70004000)

        {

          select".data.user_test_data";

        }

}

}

 

 

在程序中定義如下,則run_cnt1和run_cnt2, 則run_cnt1就會放在0x70001000, run_cnt2放在0x70004000。 

 

#pragma  section farbss "user_test_bss"

volatileuint32 run_cnt1;

#pragma  section farbss restore

 

#pragma  section fardata "user_test_data"

volatileuint32 run_cnt2 =  0x1234;

#pragma section fardata restore

 

 

編譯後,查看map文件,可以發現定義的變量放在預期的位置。

  

2.1.2 把變量放在其它DSRAM

默認的全局變量都是放在DSRAM0中,如果需要使用其他DSRAM,則可以把變量放在Link文件已經定義好一些段中: 

 

/* Initialized Data */

          select"*InitData.Cpux.8bit";

          select"*InitData.Cpux.16bit";

          select"*InitData.Cpux.32bit";

   

          /* UnInitialized Data */

          select"*ClearedData.Cpux.8bit";

          select"*ClearedData.Cpux.16bit";

          select"*ClearedData.Cpux.32bit";

 

 

例如,如果想把變量放在DSRAM1中,則在程序中可以這麼寫: 

 

#pragma  section farbss "ClearedData.Cpu1.32bit"

volatileuint32 run_cnt1_dsram1;

#pragma  section farbss restore

 

#pragma  section fardata "InitData.Cpu1.32bit"

volatileuint32  run_cnt2_dsram1 = 0x1234;

#pragma section fardata restore

 

 

查看map,發現變量放在PSRAM1的預期:

  

2.2 把變量放在DLMU 

在Link文件已經定義了各個CPU所屬的DLMU的段,如下: 

 

group (orderedattributes=rw, run_addr = mem:cpux_dlmu)

        {

          select".data.*.lmudata_cpux";

          select".bss.*.lmubss_cpux";

        }      

 

 

如果想把變量放在DLMU2中,則可以如下面這樣寫: 

 

#pragma  section farbss "test.lmubss_cpu2"

volatileuint32 run_cnt1_dlmu2;

#pragma  section farbss restore

 

#pragma  section fardata "test.lmudata_cpu2"

volatileuint32  run_cnt2_dlmu2 = 0x1234;

#pragma section fardata restore

 

 

查看map文件,發現這兩個變量已經放在DLMU2中:

  

2.3 把變量放在LMU 

在Link文件已經定義了LMU的段,如下: 

 

group (orderedattributes=rw, run_addr=mem:lmuram/cached)

        {

          select".data.*.lmu_data";

          select".bss.*.lmu_bss";

}

 

group (orderedattributes=rw, run_addr = mem:lmuram/not_cached)

        {

          /* Initialized Data */

          select"*InitData.LmuNC.8bit";

          select"*InitData.LmuNC.16bit";

          select"*InitData.LmuNC.32bit";

     

          /* UnInitialized Data */

          select"*ClearedData.LmuNC.8bit";

          select"*ClearedData.LmuNC.16bit";

          select"*ClearedData.LmuNC.32bit";

   

        }

 

 

如果想把變量放在LMU(不用CACHE)中,則可以如下面這樣寫: 

 

#pragma  section farbss "ClearedData.LmuNC.32bit"

volatileuint32 run_cnt1_lmu;

#pragma  section farbss restore

 

#pragma  section fardata "InitData.LmuNC.32bit"

volatileuint32 run_cnt2_lmu  = 0x1234;

#pragma section fardata restore

 

 

查看map文件,發現變量已經放在LMU區域: 

 

 

2.4 把程序放在PSRAM中運行 

有時候需要把程序放到RAM去運行,例如在擦寫Flash的時候,這個時候可以直接把代碼放在 “FLSLOADERRAMCODE” 段,也可以自己在PSRAM中再定義一個段,如下所示: 

 

section_layout  :vtc:linear

    {

        group  MY_RAM_CODE (orderedattributes=rwx, copyrun_addr=mem:psram0)

        {

           select".text.my_ram_code";

        }

    }

 

 

在程序中定義如下, 這樣RunTest()這個函數就會在PSRAM0中去運行: 

 

#pragma  section code "my_ram_code"

void RunTest(void)

{

    run_cnt1++;

    run_cnt2++;

    run_cnt1_dsram1++;

    run_cnt2_dsram1++;

    run_cnt1_dlmu2++;

    run_cnt2_dlmu2++;

    run_cnt1_lmu++;

    run_cnt2_lmu++;

}

#pragma section code restore

 

 

查看map文件,可以看到RunTest()放在PSRAM0中:

  

2.5 把程序放在PFLASH中指定位置 

如果需要把程序放在指定位置執行,則可以在Link文件中首先定義一個程序段,例如把程序放在0x80041000開始的地址,則可以如下定義: 

 

/* user define code section */

      group  user_test_code (orderedrun_addr=0x80041000)        

{

        select"(.text.user_test_code*)";

      }

 

 

在程序中定義如下,則AddTest()就會放在0x80041000地址: 

 

#pragma  section code "user_test_code"

uint32 AddTest(uint32 a, uint32 b)

{

    uint32 c = a+b;

    return c;

}

#pragma section code restore

 

 

查看map文件,發現AddTest()已經放在預期位置。

 

2.6 把常量放在PFLASH中指定位置 

如果需要把常量放在指定位置,則可以在Link文件中首先定義一個常量段,例如把常量放在0x80040000開始的地址,則可以如下定義: 

 

/* user define const section */

group  user_test_const (orderedrun_addr=0x80040000) 

      {

        select".rodata.user_test_const" ;

      }

 

 

在程序中定義如下,則user_test_const就會放在0x80040000地址: 

 

#pragma  section farrom "user_test_const"

volatileconstuint32 user_test_const[4]  = {0x12345678, 0x87654321, 0xAABBCCDD, 0xFFEEDDCC};

#pragma section farrom restore

 

 

查看map文件,發現user_test_const已經放在預期位置。

 

 

2.7 用數組設置UCB區域 

操作UCB可以使用調試器,但是一般在工廠燒錄時,需要把程序和UCB一起燒錄進去,這個時候就需要把UCB的數據放在程序中。下面以使能HSM為例介紹在程序中設置UCB的流程。 

首先需要在Link文件中定義需要操作UCB段,例如使能HSM,需要操作UCB_HSMCOTP0_ORIG。 

 

/*Fixed memory Allocations for HSM Configuration*/

    group (ordered)

    {

        group  hsmxcotp0_orig (run_addr=mem:ucb[0x2800])

        {

           select".rodata.hsmcotp0_orig";

        }

    }

 

 

在程序定義如下,則把編譯後hex中的UCB部分燒錄進去,MCU的HSM功能就能激活(具體請到英飛凌官網查看晶片用戶手冊“AURIX™ TC3xx User Manual”)。 

 

#pragma  section farrom "hsmcotp0_orig"

constIfx_HsmCotp_Config hsmcotp0_orig =

{

     0x00000000, /* sf_proconusr, offset: 0x000 */

     0x00000001, /* boot_sector, bit[7:0]: SEL0, bit[15:8]: SEL1,  bit[23:16]: SEL2, bit[31:24]: SEL3 */

     0x00000000, /* hsm_exclusive0, offset: 0x008 */

     0x00000000, /* hsm_exclusive1, offset: 0x00C */

    0x00000000, /* hsm_otp0, offset: 0x010*/

     0x00000000, /* hsm_otp1, offset: 0x014 */

     0x00000001, /* sp_proconhsmcfg, bit0: HSM boot enable, offset:  0x018 */

     {

           0x00000000,  /* 0x01C, Reserved */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x020: Reserved (0x020 - 0x02F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x030: Reserved (0x030 - 0x03F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x040: Reserved (0x040 - 0x04F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x050: Reserved (0x050 - 0x05F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x060: Reserved (0x060 - 0x06F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x070: Reserved (0x070 - 0x07F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x080: Reserved (0x080 - 0x08F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x090: Reserved (0x090 - 0x09F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x0A0: Reserved (0x0A0 - 0x0AF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x0B0: Reserved (0x0B0 - 0x0BF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x0C0: Reserved (0x0C0 - 0x0CF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x0D0: Reserved (0x0D0 - 0x0DF) */

           0x00000000, 0x00000000, 0x00000000,  0x00000000, /**<  \brief 0x0E0: Reserved (0x0E0 - 0x0EF) */

           0x00000000, 0x00000000, 0x00000000, 0x00000000, /**< \brief 0x0F0: Reserved (0x0F0 - 0x0FF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x100: Reserved (0x100 - 0x100) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x110: Reserved (0x110 - 0x01F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x120: Reserved (0x120 - 0x02F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x130: Reserved (0x130 - 0x03F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x140: Reserved (0x140 - 0x04F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x150: Reserved (0x150 - 0x05F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x160: Reserved (0x160 - 0x06F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x170: Reserved (0x170 - 0x07F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x180: Reserved (0x180 - 0x08F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x190: Reserved (0x190 - 0x09F) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x1A0: Reserved (0x1A0 - 0x0AF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x1B0: Reserved (0x1B0 - 0x0BF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x1C0: Reserved (0x1C0 - 0x0CF) */

           0x00000000,  0x00000000, 0x00000000, 0x00000000, /**<  \brief 0x1D0: Reserved (0x1D0 - 0x0DF) */

           0x00000000, 0x00000000,  0x00000000, 0x00000000, /**< \brief 0x1E0: Reserved (0x1E0 - 0x0EF) */

     },

     0x43211234,    /**<  \brief 0x1F0: .confirmation: 32-bit CODE, (always same)*/

     {

           0x00000000,  /* 0x004, Reserved */

           0x00000000,  /* 0x008, Reserved */

           0x00000000,  /* 0x00C, Reserved */

     }

};

 

 

查看map文件,發現HSM UCB區域部分已經有了數據:

 需要確保Flash中已經下載了HSM代碼,再激活HSM,否則晶片將被鎖死,因此為了安全,附帶的例程中這部分HSM的配置是被注釋掉的。



該文章來源於“英飛凌汽車電子生態圈”官方微信,英飛凌汽車電子生態圈對該內容擁有最終解釋權。如需轉載,請註明來源,英飛凌保留所有權利。
QR Code. (英飛凌汽車電子生態圈)官方微信公眾號

★博文內容參考自 網站,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

參考來源

false: https://mp.weixin.qq.com/s/QJlYSE4GpiPrVDJPZV_llQ

評論