第一次接触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学习-芯片启动流程相关推荐

  1. 【SemiDrive源码分析】【X9芯片启动流程】30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一)

    [SemiDrive源码分析][X9芯片启动流程]30 - AP1 Android Kernel 启动流程 start_kernel 函数详细分析(一) 一.Android Kernel 启动流程分析 ...

  2. Cortex-M3/M4芯片启动流程概括

    Cortex-M3/M4芯片启动流程理解 启动模式 烧录方式(ISP ICP IAP的区别) 中断向量表 SystemInit __main 启动模式 首先从芯片的启动模式讲起,如下图所示 这是STM ...

  3. 【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 ...

  4. 【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍

    [SemiDrive源码分析][X9芯片启动流程]08 - X9平台 lk 目录源码分析 之 目录介绍 一./rtos/lk/ 目录结构分析 1.1 /rtos/lk_boot/ 目录结构分析 1.2 ...

  5. 【SemiDrive源码分析】【X9芯片启动流程】21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇

    [SemiDrive源码分析][X9芯片启动流程]21 - MailBox 核间通信机制介绍(代码分析篇)之 Mailbox for Linux 篇 一.Mailbox for Linux 驱动框架分 ...

  6. 【SemiDrive源码分析】【X9芯片启动流程】20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇

    [SemiDrive源码分析][X9芯片启动流程]20 - MailBox 核间通信机制介绍(代码分析篇)之 MailBox for RTOS 篇 一.Mailbox for RTOS 源码分析 1. ...

  7. 【SemiDrive源码分析】【X9芯片启动流程】19 - MailBox 核间通信机制介绍(理论篇)

    [SemiDrive源码分析][X9芯片启动流程]19 - MailBox 核间通信机制介绍(理论篇) 一.核间通信 二.核间通信软件架构 三.Mailbox 设备驱动 3.1 Mailbox for ...

  8. 【SemiDrive源码分析】【X9芯片启动流程】23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇

    [SemiDrive源码分析][X9芯片启动流程]23 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC Kernel 篇 一.RPMSG 接口 1.1 Linux Kern ...

  9. 【SemiDrive源码分析】【X9芯片启动流程】25 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC RTOS QNX篇

    [SemiDrive源码分析][X9芯片启动流程]25 - MailBox 核间通信机制介绍(代码分析篇)之 RPMSG-IPCC RTOS & QNX篇 一.RPMSG 接口 1.1 Lin ...

  10. 【SemiDrive源码分析】【X9芯片启动流程】14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析

    [SemiDrive源码分析][X9芯片启动流程]14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析 一.SafetyOS 工作流程分析 1. ...

最新文章

  1. 史上最全Android开发中100%会用到的开源框架整理(1/5)
  2. [转]hibernate------HQL总结
  3. 皮一皮:充实的一天...
  4. python的引用计数分析(二)
  5. 二叉树的四种遍历方式(递归和非递归双重实现)
  6. C语言学习之分别用while、 for双重循环的方式编程绘制如下图形
  7. 开发常用常用插件介绍
  8. Vue3(监视器watch)
  9. Initial Audio Urban Essentials Heatup3 Expansion Mac(都市流派音色库)v1.0特别版
  10. 列出访问ftp 文件传输服务器过程,FTP文件传输协议简介及命令描述
  11. verifycode验证码模版
  12. python做正态分布的例子_python 绘制正态曲线的示例
  13. 无法识别的USB设备解决方法
  14. 初几学的计算机二进制,说说二进制与计算机的那些事儿
  15. mysql2005编辑器用法,文本编辑器 - Visual Studio的隐藏功能(2005-2010)?
  16. 浅析人工智能体系建设
  17. ST_Intersects
  18. SQL Studio
  19. 矩阵分析L1 线性空间基础
  20. Dispatcher has no subscribers for channel排坑指南

热门文章

  1. PS将可见图层创建为一个新的图层,保留原来的图层,Photoshop 导出可见图层
  2. 联想台式计算机 不启动u盘,联想台式机u盘启动不了怎么办
  3. 史上最全最详细的Anaconda安装教程
  4. Asp.net web服务处理程序(第六篇)
  5. 【AI视野·今日NLP 自然语言处理论文速览 第三十二期】Wed, 20 Apr 2022
  6. 谷歌浏览器百度网盘在线倍速播放
  7. 分布式系统容错性方案设计:重试与幂等
  8. LR下载地址及破解方法
  9. 指令(MISP技术的指令集)
  10. 计算机最大化快捷键,最大化窗口快捷键,mac窗口最大化快捷键