3. AURIX多核启动与CPU同步控制

AURIX多核启动与CPU同步控制 学习卡片

任务目标

在AURIX TC3xx上完成三核启动:CPU0完成基础初始化后,依次唤醒CPU1、CPU2;三核通过共享同步标志会合,全部就绪后同时进入各自主循环。核心是"启动顺序 + 同步屏障"两件事。

关键机制

  • 启动顺序:复位后仅CPU0运行,CPU1/CPU2处于halt状态,需由CPU0写各自CPU的启动地址并置位启动请求。
  • 同步屏障:用共享内存中的计数器实现。每个核到达屏障时原子自增,CPU0等待计数达到3后置"放行"标志,其余核自旋等待该标志。
  • 可见性:共享变量用volatile,跨核访问前用内存屏障保证顺序。
CPU0 复位启动 基础初始化 唤醒 CPU1 写启动地址+请求 唤醒 CPU2 写启动地址+请求 同步屏障:各核到达后 count++ CPU0 等待 count==3 → 置 release=1 三核同时进入主循环

完整实现

以下代码基于iLLD(Infineon Low Level Driver)。CPU1/CPU2的入口函数地址写入各自CPU的启动配置寄存器,再触发启动。同步用共享结构体完成。

#include "IfxCpu.h"
#include "IfxCpu_reg.h"
#include "IfxScu_reg.h"

/* 共享同步结构:放在非缓存或一致访问的段,这里用普通全局并加volatile */
typedef struct {
    volatile unsigned int arrived;   /* 已到达屏障的核数 */
    volatile unsigned int release;   /* 放行标志 */
} SyncBarrier;

static SyncBarrier g_sync = { 0u, 0u };

/* 三核主循环入口 */
static void core_main(unsigned int cpuId)
{
    /* 到达屏障:原子自增 */
    IfxCpu_disableInterrupts();
    unsigned int prev = __atomic_fetch_add(&g_sync.arrived, 1u, __ATOMIC_SEQ_CST);
    IfxCpu_enableInterrupts();

    if (cpuId == 0u) {
        /* CPU0负责判定:等齐3个核后放行 */
        while (g_sync.arrived < 3u) { }
        __atomic_store_n(&g_sync.release, 1u, __ATOMIC_SEQ_CST);
    } else {
        /* CPU1/CPU2自旋等待放行 */
        while (__atomic_load_n(&g_sync.release, __ATOMIC_SEQ_CST) == 0u) { }
    }

    /* 三核在此刻之后同时进入主循环 */
    for (;;) {
        /* 各核主循环任务,此处以空转示意 */
        __asm("nop");
    }
}

/* CPU1入口 */
void core1_entry(void) { core_main(1u); }
/* CPU2入口 */
void core2_entry(void) { core_main(2u); }

/* 唤醒指定CPU:写启动地址并置启动请求位 */
static void start_cpu(IfxCpu_ResourceCpu cpu, void (*entry)(void))
{
    IfxCpu_setCoreStartAddress(cpu, (void *)entry);
    IfxCpu_startCore(cpu);
}

int core0_main(void)
{
    /* CPU0基础初始化(时钟、看门狗等由iLLD初始化代码完成) */
    IfxCpu_enableInterrupts();

    /* 依次唤醒CPU1、CPU2 */
    start_cpu(IfxCpu_ResourceCpu_1, core1_entry);
    start_cpu(IfxCpu_ResourceCpu_2, core2_entry);

    /* CPU0也进入同步与主循环 */
    core_main(0u);

    return 0;
}

运行与验证

  1. 用AURIX Development Studio或Tasking编译,链接脚本确保g_sync位于所有核可访问的共享RAM段(默认全局段即可)。
  2. 烧录后复位运行,在调试器中给core_main的for(;;)处下断点。
  3. 通过条件:三个核都停在主循环,且g_sync.arrived == 3、g_sync.release == 1。若某核未到达,检查其启动地址是否正确、该核是否被看门狗复位。

常见问题

  • CPU1/CPU2未启动:确认IfxCpu_startCore调用前已使能对应核的时钟,且入口函数地址对齐。
  • 同步卡死:g_sync若被编译器优化或放在各核私有缓存,会导致可见性问题,务必用volatile+原子操作。
  • 看门狗复位:多核等待期间需喂狗或先关闭看门狗,否则屏障等待可能超时。