Tricore学习-芯片启动流程
第一次接触Tricore, 学习下从芯片上电到运行到main函数的过程,本文以TC36X为例,具体可参考英飞凌官方的Infineon-AURIX_TC3xx_Part1-UserManual-v02_00-EN
首先Tricore类似三星的MPU,有一段自带的BROM,这段FLASH中存储了一段固化的启动代码,称为Startup Sofrware(SSW), 这个意味着这段代码是英飞凌出厂就烧进去的,且无法覆盖。
然后SSW什么时候执行呢?当然是RESET的时候,英飞凌把RESET分为三种:
- Cold (initial) power-on reset 上电复位,一切都处于初始状态
- System reset 触发源为内部看门狗,软件主动请求,PORST输入脉冲复位等,复位后一切都处于初始状态
- Application reset 触发源和System reset相同,只是可以通过复位前软件配置,使得复位后时钟,RAM不会跟着复位
复位后如果一切正常就会自动执行SSW
先放张图
SSW会去读取DFLASH UCB区的BMHD(Boot Mode Header)内容。
一共四个配置项,从BMHD0开始检测是否有效,如果BMHD0有效则使用它,否则依次检测出第一个有效的BMHD,如果都无效则需要进入BootStrap Loader刷程序,芯片无法正常启动,跳转到用户写的代码去执行
这就是一个UCB-BMHD内容,需要用户自己填写(不确定出厂是否会有默认的内容),编译链接到.section .bmhd_0_orig 并下载到DFLASH.UCB.BMHD对应的地址上去,这样下次芯片上电执行SSW才能读到正确的内容。
找了一个例程,大家看下配置
#if defined(__HIGHTEC__)
#pragma section
#pragma section ".bmhd_0_orig" a
#endif
#if defined(__TASKING__)
#pragma section farrom "bmhd_0_orig"
#endif
#if defined(__DCC__)
#pragma section CONST ".bmhd_0_orig" far-absolute R
#endif
#if defined(__ghs__)
#pragma ghs section rodata= ".bmhd_0_orig"
#endif
const Ifx_Ssw_Bmhd bmhd_0_orig =
{0x003E, /* 0x000: .bmi: Boot Mode Index (BMI) PINDIS */0xB359, /* 0x002: .bmhdid: Boot Mode Header ID (CODE) = B359H */0xA0000000, /* 0x004: .stad: User Code start address */0xD86CBDAB, /* 0x008: .crc: Check Result for the BMI Header (offset 000H - 007H) */0x27934254, /* 0x00C: .crcInv: Inverted Check Result for the BMI Header (offset 000H - 007H) */{0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x010: Reserved (0x010 - 0x01F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x020: Reserved (0x020 - 0x02F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x030: Reserved (0x030 - 0x03F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x040: Reserved (0x040 - 0x04F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x050: Reserved (0x050 - 0x05F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x060: Reserved (0x060 - 0x06F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x070: Reserved (0x070 - 0x07F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x080: Reserved (0x080 - 0x08F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x090: Reserved (0x090 - 0x09F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0A0: Reserved (0x0A0 - 0x0AF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0B0: Reserved (0x0B0 - 0x0BF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0C0: Reserved (0x0C0 - 0x0CF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0D0: Reserved (0x0D0 - 0x0DF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x0E0: Reserved (0x0E0 - 0x0EF) */0x00000000, 0x00000000, 0x00000000, 0x00000000 /* 0x0F0: Reserved (0x0F0 - 0x0FF) */},{0x00000000, /* 0x100: .pw0: Password protection word 0 (lsw) */0x00000000, /* 0x104: .pw1: Password protection word 1 */0x00000000, /* 0x108: .pw2: Password protection word 2 */0x00000000, /* 0x10C: .pw3: Password protection word 3 */0x00000000, /* 0x110: .pw4: Password protection word 4 */0x00000000, /* 0x114: .pw5: Password protection word 5 */0x00000000, /* 0x118: .pw6: Password protection word 6 */0x00000000, /* 0x11C: .pw7: Password protection word 7 (msw) */},{0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x120: Reserved (0x120 - 0x12F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x130: Reserved (0x130 - 0x13F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x140: Reserved (0x140 - 0x14F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x150: Reserved (0x150 - 0x15F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x160: Reserved (0x160 - 0x16F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x170: Reserved (0x170 - 0x17F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x180: Reserved (0x180 - 0x18F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x190: Reserved (0x190 - 0x19F) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x1A0: Reserved (0x1A0 - 0x1AF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x1B0: Reserved (0x1B0 - 0x1BF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x1C0: Reserved (0x1C0 - 0x1CF) */0x00000000, 0x00000000, 0x00000000, 0x00000000, /* 0x1D0: Reserved (0x1D0 - 0x1DF) */0x00000000, 0x00000000, 0x00000000, 0x00000000 /* 0x1E0: Reserved (0x1E0 - 0x1EF) */},0x43211234 /* 0x1F0: .confirmation: 32-bit CODE, (always same) */
};
这里的BMI =0x3E =0b111110 ,大家可以具体看看这种配置是社么意思
比如PINDIS=0且 HWCFGbits [3:1] = 0b111 代表上电无需检测外部Pin14.2等引脚电平,直接start from Flash,那么从Flash哪个地址开始执行呢?
BMHD.STAD: User Code start address 是可以配置的
这里配置为了0xA0000000
这是NON-CACHE CPU0的Program Flash起始地址
#if defined(__HIGHTEC__)
#pragma section
#pragma section ".start" x
#endif
void _START(void)
{Ifx_Ssw_jumpToFunction(__StartUpSoftware);
}
#if defined(__HIGHTEC__)
#pragma section
#endif
通过宏将void _START(void)代码放到了section .start
链接脚本
#define LCF_STARTPTR_NC_CPU0 0xA0000000group (ordered){group reset (run_addr=RESET){section "reset" ( size = 0x20, fill = 0x0800, attributes = r ){select ".text.start";}}group interface_const (run_addr=mem:pfls0[0x0020]){select "*.interface_const";}"__IF_CONST" := addressof(group:interface_const);"__START0" := LCF_STARTPTR_NC_CPU0;"__START1" := LCF_STARTPTR_NC_CPU1;}
总之就是将_START放到了CPU0的PFLASH0的起始地址,也就是BMHD中指定的STAD,而CPU1的_START1同样也放到了PFLASH1的起始地址,顺便提一下,上电的时候CPU0是默认开启的,且SSW也是由这个核执行的,其他所有CPU都处于HALT状态。
到这里SSW就结束了,后面就是执行用户写的代码,第一个指令就是_START(相当于CPU0的启动代码)位于Ifx_Ssw_Tc0.c
void _START(void)
{Ifx_Ssw_jumpToFunction(__StartUpSoftware);
}/*汇编直接跳转到__StartUpSoftware*/
static void __StartUpSoftware(void)
{/* Initialize A1 pointer to use the global constants with small data addressing */Ifx_Ssw_setAddressReg(a1, __SDATA2(0));/* Set the PSW to its reset value in case of a warm start,clear PSW.IS */Ifx_Ssw_MTCR(CPU_PSW, IFX_CFG_SSW_PSW_DEFAULT);/* This phase is executed only if last reset is not of type application reset */if (Ifx_Ssw_isApplicationReset() != 1){Ifx_Ssw_jumpToFunction(__StartUpSoftware_Phase2);}else{Ifx_Ssw_jumpToFunction(__StartUpSoftware_Phase3ApplicationResetPath);}
}
/*System Reset*/
static void __StartUpSoftware_Phase3ApplicationResetPath(void)
{IFX_SSW_INIT_CONTEXT();Ifx_Ssw_jumpToFunction(__StartUpSoftware_Phase5);
}
#define IFX_SSW_INIT_CONTEXT() \{ \/* Load user stack pointer */ \Ifx_Ssw_setAddressReg(a10, __USTACK(0)); \Ifx_Ssw_DSYNC(); \\/*Initialize the context save area for CPU0. Function Calls Possible */ \/* Setup the context save area linked list */ \Ifx_Ssw_initCSA((unsigned int *)__CSA(0), (unsigned int *)__CSA_END(0)); \/* Clears any instruction buffer */ \Ifx_Ssw_ISYNC(); \}/*初始化CPU0 的RAM, 其他核也有自己的专用RAM,参考手册MemoryMap 包括CSA 将utack 栈顶赋值给寄存器A10(相当于ARM 的LDR SP ,= StackTopAddr) CPU的RAM怎么分配的可以参考链接脚本*/按道理说只有初始化的Stack才能执行C语言写的函数,那么在这之前的那些步骤难道不算C语言函数?static void __StartUpSoftware_Phase5(void)
{/* SMU alarm handling */IFX_CFG_SSW_CALLOUT_SMU();Ifx_Ssw_jumpToFunction(__StartUpSoftware_Phase6);
}/*其实是直接跳转到phase6*/
static void __StartUpSoftware_Phase6(void)
{/* Start remaining cores as a daisy-chain */
#if (IFX_CFG_SSW_ENABLE_TRICORE1 != 0)Ifx_Ssw_startCore(&MODULE_CPU1, (unsigned int)__START(1)); /*The status returned by function call is ignored */
#endif /* #if (IFX_CFG_CPU_CSTART_ENABLE_TRICORE1 != 0)*/Ifx_Ssw_jumpToFunction(__Core0_start);
}/*可以看到CPU1其实是由CPU0启动的,当然你要配置使用CPU1*/
Ifx_Ssw_startCore(&MODULE_CPU1, (unsigned int)__START(1));
void Ifx_Ssw_startCore(Ifx_CPU *cpu, unsigned int programCounter)
{/* Set the PC */cpu->PC.B.PC = (unsigned int)programCounter >> 1U;/* release boot halt mode if required */Ifx_CPU_SYSCON syscon;syscon = cpu->SYSCON;if (syscon.B.BHALT){syscon.B.BHALT = 0U;cpu->SYSCON = syscon;}}
可以看到是直接将cpu1->PC寄存器指向_START1()函数,
并且通过设置某个特殊寄存器,解除CPU1的HALT状态,使其进入RUN,
那么CPU1就可以执行_START1()了
CPU0开启CPU1后,继续自己的初始化
Ifx_Ssw_jumpToFunction(__Core0_start);
static void __Core0_start(void)
{... 很多代码大家可以自己去看, 这里就不分析了,值得注意的是初始化看门狗, 初始化RAM,建立异常和中断Vector,中断栈, 使能或不使能Cache等等/*Call main function of Cpu0 */Ifx_Ssw_jumpToFunction(core0_main);
}
最重要的是Ifx_Ssw_jumpToFunction(core0_main) 这样芯片从上电CPU0 RUN CPUX HALT ->读取UFLASH-UCB-BMHD->_START0->core_start(cpu1)->go to MAIN函数就完成了, 同样的CPU1执行_START1() 后也会继续执行自己的core1_main
现在多核CPU就可以各自执行自己的MAIN函数(它们在不同的flash地址), 各玩各的,但这样是显然不行的,涉及到共享资源访问,核间通信等问题以后再研究。
Tricore学习-芯片启动流程相关推荐
- 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)
[SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...
- Cortex-M3/M4芯片启动流程概括
Cortex-M3/M4芯片启动流程理解 启动模式 烧录方式(ISP ICP IAP的区别) 中断向量表 SystemInit __main 启动模式 首先从芯片的启动模式讲起,如下图所示 这是STM ...
- 【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析
[SemiDrive源码分析][X9芯片启动流程]12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析 一.s ...
- 【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍
[SemiDrive源码分析][X9芯片启动流程]08 - X9平台 lk 目录源码分析 之 目录介绍 一./rtos/lk/ 目录结构分析 1.1 /rtos/lk_boot/ 目录结构分析 1.2 ...
- 【SemiDrive源码分析】【X9芯片启动流程】21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇
[SemiDrive源码分析][X9芯片启动流程]21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇 一.Mailbox for Linux 驱动框架分 ...
- 【SemiDrive源码分析】【X9芯片启动流程】20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇
[SemiDrive源码分析][X9芯片启动流程]20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇 一.Mailbox for RTOS 源码分析 1. ...
- 【SemiDrive源码分析】【X9芯片启动流程】19 - MailBox 核间通信机制介绍(理论篇)
[SemiDrive源码分析][X9芯片启动流程]19 - MailBox 核间通信机制介绍(理论篇) 一.核间通信 二.核间通信软件架构 三.Mailbox 设备驱动 3.1 Mailbox for ...
- 【SemiDrive源码分析】【X9芯片启动流程】23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇
[SemiDrive源码分析][X9芯片启动流程]23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇 一.RPMSG 接口 1.1 Linux Kern ...
- 【SemiDrive源码分析】【X9芯片启动流程】25 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC RTOS QNX篇
[SemiDrive源码分析][X9芯片启动流程]25 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC RTOS & QNX篇 一.RPMSG 接口 1.1 Lin ...
- 【SemiDrive源码分析】【X9芯片启动流程】14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析
[SemiDrive源码分析][X9芯片启动流程]14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析 一.SafetyOS 工作流程分析 1. ...
最新文章
- 史上最全Android开发中100%会用到的开源框架整理(1/5)
- [转]hibernate------HQL总结
- 皮一皮:充实的一天...
- python的引用计数分析(二)
- 二叉树的四种遍历方式(递归和非递归双重实现)
- C语言学习之分别用while、 for双重循环的方式编程绘制如下图形
- 开发常用常用插件介绍
- Vue3(监视器watch)
- Initial Audio Urban Essentials Heatup3 Expansion Mac(都市流派音色库)v1.0特别版
- 列出访问ftp 文件传输服务器过程,FTP文件传输协议简介及命令描述
- verifycode验证码模版
- python做正态分布的例子_python 绘制正态曲线的示例
- 无法识别的USB设备解决方法
- 初几学的计算机二进制,说说二进制与计算机的那些事儿
- mysql2005编辑器用法,文本编辑器 - Visual Studio的隐藏功能(2005-2010)?
- 浅析人工智能体系建设
- ST_Intersects
- SQL Studio
- 矩阵分析L1 线性空间基础
- Dispatcher has no subscribers for channel排坑指南
热门文章
- PS将可见图层创建为一个新的图层,保留原来的图层,Photoshop 导出可见图层
- 联想台式计算机 不启动u盘,联想台式机u盘启动不了怎么办
- 史上最全最详细的Anaconda安装教程
- Asp.net web服务处理程序(第六篇)
- 【AI视野·今日NLP 自然语言处理论文速览 第三十二期】Wed, 20 Apr 2022
- 谷歌浏览器百度网盘在线倍速播放
- 分布式系统容错性方案设计:重试与幂等
- LR下载地址及破解方法
- 指令(MISP技术的指令集)
- 计算机最大化快捷键,最大化窗口快捷键,mac窗口最大化快捷键