1、Tasking的链接文件
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 是用来在函数调用或者进出中断时用来保存通用寄存器的区域,具体可以看 Tricore 内核参考手册。它的大小由 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), 在 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、LMU
LMU 分为各个 CPU 私有的 dLMU 和共用的 LMU 两部分,在 MCAL 中的 Link 文件中只是定义了 LMU 的几个段,在工程中并没有用到这个区域,关于怎么把变量放到 LMU 中,下文会解释。
1.4、PSRAM
每个 CPU 都有自己的 PSRAM 区域,这个区域可以运行程序,也可以存放数据,在 Link 中只是定义了几个段,在工程中并没有用到这个区域,关于怎么在这个区域运行程序,下文会解释。
1.5、UCB
UCB 是配置 MCU 参数的一块区域,关于怎么在程序中配置 UCB 区域,下文会解释。
2、代码与变量定位
2.1、把变量放在 DSRAM
2.1.1、把变量放在固定位置
如果需要把变量放在固定位置,则需要在 Link 文件中,首先定义一个 bss段,从0x7001000 开始,一个 data 段,从 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"
volatile uint32 run_cnt1;
#pragma section farbss restore
#pragma section fardata "user_test_data"
volatile uint32 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"
volatile uint32 run_cnt1_dsram1;
#pragma section farbss restore
#pragma section fardata "InitData.Cpu1.32bit"
volatile uint32 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";
}
cpux_dlmu = 0x90020004
如果想把变量放在 DLMU2 中,则可以下面这样写:
#pragma section farbss "test.lmubss_cpu2"
volatile uint32 run_cnt1_dlmu2;
#pragma section farbss restore
#pragma section fardata "test.lmudata_cpu2"
volatile uint32 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"
volatile uint32 run_cnt1_lmu;
#pragma section farbss restore
#pragma section fardata "InitData.LmuNC.32bit"
volatile uint32 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 中:
此处注意一个问题:DSRAM与PSRAM地址是不一样的,假设将程序放置在了DSRAM里面也是运行不起来的。
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"
volatile const uint32 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 功能就能激活(具体请查看芯片用户手册)。
#pragma section farrom "hsmcotp0_orig"
const Ifx_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 的配置是被注释掉的。