2. AURIX启动流程分析与启动代码修改

任务目标

阅读 AURIX TC3xx 的启动代码,定位复位向量、启动模式判定与时钟初始化流程,并通过修改启动配置调整时钟初始化的执行顺序。本案例以最小可复现的启动代码片段演示:复位入口如何跳转到启动模式判定,再进入时钟初始化,并给出修改顺序后的验证方法。

启动流程结构

复位向量 0xA0000000 启动模式判定 _Start / BMHD 时钟初始化 ClockInit() 外设初始化 PeriphInit() main() 应用入口

复位后 CPU 从复位向量取指,进入启动代码 _Start;启动代码读取启动模式头(BMHD)判定启动模式,随后调用时钟初始化与外设初始化,最终跳转 main()。本案例修改点在于调整时钟初始化与外设初始化的先后顺序。

关键代码

以下为最小可复现的启动代码片段(TC3xx 风格,使用 GCC/Tasking 通用写法)。STARTUP_ORDER 宏控制时钟初始化顺序,修改该宏即可改变执行次序。

/* startup_cfg.h —— 启动配置 */
#ifndef STARTUP_CFG_H
#define STARTUP_CFG_H

/* 启动顺序选择:0 = 先时钟后外设(默认);1 = 先外设后时钟 */
#define STARTUP_ORDER   0

/* 启动模式定义(与 BMHD 对应) */
typedef enum {
    BOOT_MODE_INTERNAL = 0,   /* 内部 Flash 启动 */
    BOOT_MODE_ALT      = 1,   /* 备用启动 */
    BOOT_MODE_UNKNOWN  = 2
} BootMode_t;

#endif
/* startup.c —— 复位向量与启动流程 */
#include "startup_cfg.h"

/* 复位向量:链接脚本将 .reset 段定位到 0xA0000000 */
__attribute__((section(".reset")))
void _Start(void);

/* 前向声明 */
static BootMode_t GetBootMode(void);
static void ClockInit(void);
static void PeriphInit(void);
extern int main(void);

/* 复位入口 */
void _Start(void)
{
    BootMode_t mode = GetBootMode();

    if (mode == BOOT_MODE_UNKNOWN) {
        /* 未知启动模式:停在安全循环,等待看门狗复位 */
        for (;;) { }
    }

#if (STARTUP_ORDER == 0)
    ClockInit();      /* 默认:先初始化时钟 */
    PeriphInit();     /* 再初始化外设 */
#else
    PeriphInit();     /* 修改后:先初始化外设 */
    ClockInit();      /* 再初始化时钟 */
#endif

    main();           /* 跳转应用入口 */
    for (;;) { }      /* main 不应返回 */
}

/* 读取启动模式:实际项目中读取 BMHD 或 SCU 寄存器 */
static BootMode_t GetBootMode(void)
{
    /* 简化示例:固定返回内部 Flash 启动 */
    return BOOT_MODE_INTERNAL;
}

/* 时钟初始化:配置 PLL、分频等 */
static void ClockInit(void)
{
    /* 示例:使能 PLL,等待锁定 */
    volatile unsigned int *pll_con = (volatile unsigned int *)0xF0036000u;
    *pll_con |= 0x1u;                 /* 使能 PLL */
    while ((*pll_con & 0x2u) == 0u) { } /* 等待锁定 */
}

/* 外设初始化:GPIO、UART 等 */
static void PeriphInit(void)
{
    volatile unsigned int *gpio_dir = (volatile unsigned int *)0xF003A000u;
    *gpio_dir = 0x00000001u;          /* 配置 P0.0 为输出 */
}

运行与验证

编译(以 GCC 交叉工具链为例):

tricore-elf-gcc -c startup.c -o startup.o -I.
tricore-elf-gcc -c main.c -o main.o -I.
tricore-elf-gcc startup.o main.o -T tc3xx.ld -o app.elf

验证方法:

  1. 用 tricore-elf-objdump -d app.elf 反汇编,确认 _Start 位于 .reset 段且地址为 0xA0000000。
  2. 将 STARTUP_ORDER 改为 1 重新编译,反汇编确认 _Start 中 PeriphInit 的调用指令出现在 ClockInit 之前。
  3. 通过条件:复位向量地址正确,且修改宏后调用顺序随之改变,即判定启动配置修改生效。

注意:ClockInit 与 PeriphInit 中的寄存器地址为示例值,实际项目需替换为对应 TC3xx 型号的寄存器基址。