启动文件流程图:
TC3xx系列MCU复位后会从Ifx_Ssw_Tc0.c文件的_START()函数开始启动,启动的时候都会从CPU0开始运行,直到在__StartUpSoftware_Phase6()函数中才会根据用户配置依次启动其他核。
_START()
_START()的地址由link文件中RESET决定,以Tasking为例. 在Link文件中:
这个地址也必须和BMHD中的应用程序起始地址定义一致。
_START()代码解析:
__StartUpSoftware()
__StartUpSoftware()主要用来设置A1寄存器,设置PSW寄存器,以及判断是否是Application Reset, 从而进行不同的跳转。
在Tricore中A0,A1,A8,A9是全局地址寄存器,此处的A1所指向区域用来存放small RODATA, 所谓small data区域就是可以直接寻址。
PSW的默认值设的是0x980, 即Supervise mode, Global Address Register Write Permission Enable, Call Depth Count Enable, User Stack
__StartUpSoftware()代码解析:
__StartUpSoftware_Phase2()
在这个API里面,会根据用户的配置,执行EVRC的初始化配置,LBIST测试,MONBIST测试。
__StartUpSoftware_Phase2()代码解析:
__StartUpSoftware_Phase3PowerOnResetPath()
在这个API里面, 会初始化上下文,所谓的上下文就是SP指针和CSA。
在Tricore中,SP是A10寄存器,在这里会把栈顶地址赋给A10.
CSA是存放上下文的区域,在Tricore中,每当调用子函数或者进中断时,都会把一些通用寄存器自动存放在CSA区域 (Push),然后等到子函数返回或中断返回时,再把这些寄存器恢复(Pop)。
__StartUpSoftware_Phase3ApplicationResetPath代码解析:
__StartUpSoftware_Phase4
在这个API里面,会首先进行对CPU0 watchdog和safety watchdog进行一次喂狗(注意:复位后CPU0 watchdog和safety watchdog是使能的),然后根据用户配置,完成时钟初始化以及MBIST测试。
__StartUpSoftware_Phase5
在这个API里面, 只有SMU配置的一个API,但是这个API只是个空函数,所以其实在这里什么都没有做。
__StartUpSoftware_Phase3ApplicationResetPath
和__StartUpSoftware_Phase3PowerOnResetPath()一样。
__StartUpSoftware_Phase6
根据用户配置启动不同的内核。
SYSCON寄存器的BHALT位用来设置Core是否启动,PC用来设置程序指针,Ifx_Ssw_startCore()中设置这两个寄存器,来启动其他内核。
__StartUpSoftware_Phase6()代码解析:
__Ifx_Ssw_startCore()代码解析:
以TC38x为例,如果所有4个内核都启动,那么__StartUpSoftware_Phase6()中会启动CORE1。这个时候,__Core0_Start()和__Core1_Start()是同时运行的,在__Core1_Start()的最后会启动Core2,然后跳转到__Core2_Start(),在_Core2_Start() 最后会启动Core3, 然后跳转到__Core3_Start().
__Corex_start
以__Core0_Start()为例,在__Core0_Start()中,会根据配置使能PCACHE和DCACHE,设置A0, A8, A9地址,配置Trap和中断向量表起始地址,配置中断栈指针,初始化全局变量。
CACHE配置:
是否使能CACHE,通过配置下面两个宏:
通过配置PCON0的PCBYP位来使能PCACHE:
通过配置DCON0的PCBYP来使能DCACHE:
Trap和中断向量配置:
BTV寄存器用来设置Trap向量表的首地址,在工程中Trap向量表的首地址在link文件中设置,通过下面语句会把link文件中Trap向量表地址赋给BTV.
BIV寄存器用来设置中断向量表的首地址,在工程中中断向量表的首地址在link文件中设置,通过下面语句会把link文件的中断向量表地址赋给BIV. 注意在Tricore中,默认状态下,中断向量是32字节对齐的,中断向量的位置不是固定的,而是由中断优先级决定的。
配置ISTACK:
在Tricore中,栈分为USTACK和ISTACK, 他们的使用由PSW.IS位来决定,默认配置PSW.IS=0,即在线程中的函数调用时,会用USTACK(A11)部分作为CPU的栈,而在中断函数中会用ISTACK(ISP)作为CPU的栈。USTACK和ISTACK大小和位置是在Link文件中配置的。下面语句设置ISP:
对于CPU0,在__StartUpSoftware_Phase3ApplicationResetPath()已经把USTACK的栈顶指针赋给了A10. 对于其他CPU,在各自的__Corex_Start()把USTACK的栈顶指针赋给了各自CPU的A10。
初始化全局变量:
下面函数用来初始化全局变量 (这个函数是编译器来实现的),全局变量分为两部分:Data和BSS。
Data: 存放有初始化全局变量,有初始化的全局变量的初始值最初是放在Flash中,在这个函数里面,会把初始值从Flash赋给全局变量。
BSS: BSS段用于存放没有初始化值的全局变量,在这个函数里面会把没有初始化值的全局变量清零。
对于其它__Corex_Start()而言,和__Core0_Start()的流程基本一样,另外增加了把USTACK栈顶指针赋给A10的操作和PSW初始化操作。
在各个CPU的__Corex_Start()最后会跳转到各自的corex_main()中运行。