一
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 (ordered, attributes=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 (ordered, contiguous, align = 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 (ordered, attributes=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 (ordered, contiguous, align = 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 (ordered, align = 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 (ordered, run_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 (ordered, align = 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 (ordered, align = 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 (ordered, attributes=rw, run_addr=0x70001000) { select".bss.user_test_bss"; }
group (ordered, attributes=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 (ordered, attributes=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 (ordered, attributes=rw, run_addr=mem:lmuram/cached) { select".data.*.lmu_data"; select".bss.*.lmu_bss"; }
group (ordered, attributes=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 (ordered, attributes=rwx, copy, run_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 (ordered, run_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 (ordered, run_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的配置是被注释掉的。
一文详解CAN总线错误帧|附下载
DoIP协议介绍,资料分享!
详解车载网络 OTA系统的开发|文末附下载
一文了解汽车嵌入式AUTOSAR架构|附下载
关于 ASPICE 的理解
详解汽车Bootloader设计
特斯拉Autopilot系统安全研究|附dbc下载