BAF 处理流程
所谓MCU的启动过程,就是MCU上电一直到运行Main 函数,这中间的所有执行过程。MCU的启动过程是MCU的学习难点,也是部分嵌入式工程师的知识盲点。
所谓MCU的启动过程,就是MCU上电一直到运行Main 函数,这中间的所有执行过程。MCU的启动过程是MCU的学习难点,也是部分嵌入式工程师的知识盲点。虽然不了解启动过程不影响大部分应用程序的编写,但当你希望更深入地编写涉及存储区域、安全启动、多核程序、Bootloader等,就需要对启动过程有一定了解。
BAF 处理流程
芯片复位后,最先进入BAF(Boot Assist Firmware),即启动固件,这是芯片出厂就已经固化在芯片内部的,用户不可见,所有复位方式复位后都会运行。BAF并不运行在芯片的CM7核,而是在Security模块HSE-B 内部的Cortex-M0+内核来运行。
首先,BAF 会区分当前启动是正常启动还是从Standby低功耗模式唤醒的,如果从Standby唤醒,可以支持Normal weakup 和 Fast weakup。如果是正常的复位,会解析IVT(Image Vector Table),是Flash 中断向量表之前的数据,用于配置整个应用工程和内核的关键配置信息。
通过解析IVT信息,会得到是不是Security boot,如果安全启动的话会检测芯片的Life cycle,Life cycle类似一个不可逆的安全状态机是为了做信息安全的管控和密钥的管理。如果安全启动没有问题,会到应用核CM7的启动,从IVT里会获得应用核的启动地址,跳转执行,同时会把 HSE-B 内部的Cortex-M0+ 内核进入低功耗模式。
IVT 解析
上文提到BAF会解析IVT(ImageVector Table)获得应用工程和内核的关键配置信息。IVT 总共256 Bytes,必须放在每一个Pflash 或者Dflash 最开始的256个字节,S32K344总共有4个Pflash 的Blocks 和1个Dflash 的Block,总共有5个可选地址,程序会按Block 依次去找,找到后就不再往下寻找。
00H偏移地址:第一个word (4个字节) 是IVTMarker,固定为0x5AA55AA5,用于确定是不是合法的IVT。
04H偏移地址:第二个 word (4个字节)是Boot configuration word,保存信息为是否SecuretyBoot。
0CH偏移地址/14H 偏移地址:两个应用核启动地址。
24H偏移地址:存放Lifecycle。
Boot Configuration Word 配置
上文提到 IVT 04H 偏移地址为Boot configuration word,具体配置数据如下。
Bit3:Boot_SEQ ,Securety boot 是否使能。
Bit5:应用核CM7的看门狗是否使能。
Bit1Bit0: 两个CM7应用核是否使能,双核启动的话一定是先启动一个核,主核配好时钟后,从核再起来。IVT 里Enable 的核必须是主核,bootloader也必须在这个上面。
RTD工程启动所需文件
程序从BAF跳出来后,首先运行的是 startup_cm7.s 的Reset_Handler 程序入口(IVT 地址指向),整个的启动过程代码都在这个汇编文件里,文件同时会调用到startup.c 和system.c 中的各种初始化函数。实现的是数据的初始化,全局变量的初始化和MPU 的初始化,Cache 的初始化,FPU初始化,看门狗初始等。
另外,启动过程非常重要的是链接文件,链接文件会保存段 section 的定义,也会提供初始化时各类段的地址信息,比如全局变量存储地址,保留多大空间等。链接文件的另外一个作用是工程代码代码编译后,具体的存储的地址,会提供据实际目标MCU的Memory的地址映射。
NXP Demo工程中LD文件一般有两个,一个是Flash 的,一个是RAM的。RAM只用临时Debug,编译后的代码会下载到RAM里执行,重启后数据会丢失。
RTD启动流程图
RTD的启动流程即 startup_cm7.s 具体的处理过程:
第一步 清CPU的通用寄存器
第二步 打开MSCM 的时钟
第三步 中断向量表重映射到RAM,映射到RAM后 用户可以应用install中断服务函数
第四步 初始化CPU的堆栈,堆栈在CortexM 内核就是R13寄存器,他的值来自 中断向量表0 地址的第一个word
第五步 关闭看门狗,HSE-B 跳到CM7时看门狗打开的,如果不关掉或不及时喂狗,MCU就会复位
第六步 RAM ECC的初始化
第七步 TCM 及TCM ECC 初始化,S32K3 每个核有 32bit ITCM和64bit 的DTCM
第八步 Wait for debugger to hold the core,这是调试器相关的,为了保证我们可靠的调试需要的代码,是由我们应用工具链决定的
第九步 C代码用到的全局变量 bss段和data段初始化
第十步 调用 SystemInit() ,主要完成以下功能,中断具体应用的核配置,FPU使能,MPU配置和cache 配置
第十一步 使能全局中断
第十二步 可选,应用Autosar 时应用
最后,跳转到main 函数。
总结
可以说理解了MCU的硬件和软件启动过程才是真正理解了这颗MCU,也为用户更深入的通过配置IVT 链接文件等来定制化启动过程成为可能。