【风电控制】TI TMS320F28379D 双CPU架构解析与任务分布设计

【风电控制】TI TMS320F28379D 双CPU架构解析与任务分布设计


一、C2000 28379D 双核架构总览

1.1 芯片基本参数

参数 CPU1 (CLA1 + CPU1) CPU2 (CLA2 + CPU2)
CPU主频 200 MHz 200 MHz
CPU核心 C28x浮点核 C28x浮点核
FPU 硬件单精度浮点 硬件单精度浮点
TMU 三角函数加速单元 三角函数加速单元
CLA 协处理器CLA1 协处理器CLA2
Flash 共享1MB(各512KB分区)
RAM 各有独立的本地RAM

1.2 双核的硬件关系

复制代码
┌─────────────────────────────────────────────────────────┐
│                    TMS320F28379D                         │
│                                                         │
│  ┌─────────────┐    IPC总线     ┌─────────────┐        │
│  │    CPU1      │◄══════════════►│    CPU2      │        │
│  │  C28x + FPU  │               │  C28x + FPU  │        │
│  │  + TMU       │               │  + TMU       │        │
│  │  200MHz      │               │  200MHz      │        │
│  ├─────────────┤               ├─────────────┤        │
│  │    CLA1      │               │    CLA2      │        │
│  │  协处理器     │               │  协处理器     │        │
│  │  (独立执行)   │               │  (独立执行)   │        │
│  └──────┬──────┘               └──────┬──────┘        │
│         │                             │                │
│    ┌────┴────┐                   ┌────┴────┐          │
│    │ 本地RAM  │                   │ 本地RAM  │          │
│    │ LS0~LS5  │                   │ LS0~LS5  │          │
│    └────┬────┘                   └────┬────┘          │
│         │                             │                │
│         └──────────┬─────────────────┘                │
│                    │                                   │
│              ┌─────┴─────┐                             │
│              │ 共享资源    │                             │
│              │           │                             │
│              │ · Flash   │                             │
│              │ · GS RAM  │                             │
│              │ · 外设     │                             │
│              │   ADC     │                             │
│              │   PWM     │                             │
│              │   EQEP    │                             │
│              │   SPI/CAN │                             │
│              │   GPIO    │                             │
│              └───────────┘                             │
└─────────────────────────────────────────────────────────┘

1.3 关键差异:不是"两个相同的核"

虽然CPU1和CPU2的计算能力相同,但它们在外设访问权限、启动顺序、系统管理权限上有本质区别:

差异点 CPU1 CPU2
系统管理权限 主核,负责系统初始化 从核,由CPU1唤醒
启动顺序 先启动,执行Boot ROM 被CPU1通过IPC唤醒
时钟配置 CPU1负责配置系统时钟 不能配置时钟
外设时钟使能 CPU1负责使能所有外设时钟 不能使能外设时钟
GPIO配置 CPU1负责配置GPIO复用 不能配置GPIO
Flash等待状态 CPU1配置 不能配置
ADC外设 可访问ADC-A, ADC-C 可访问ADC-B, ADC-D
PWM外设 可访问ePWM1~8 可访问ePWM9~12
EQEP(编码器) 可访问EQEP1~2 可访问EQEP3
DMA DMA通道1~6 DMA通道7~12

核心原则:CPU1是"管家",CPU2是"干活的"。 系统级配置必须由CPU1完成,CPU2只负责执行分配给它的控制任务。


二、外设资源分配------双核分工的硬件基础

2.1 外设分配表

28379D的外设在两个CPU之间的分配是硬件固化的,不能随意更改:

复制代码
CPU1 专属外设:
├── ADC-A (ADCINA0~15)     ← 机侧三相电流/电压采样
├── ADC-C (ADCINC0~15)     ← 机侧备用/直流母线电压
├── ePWM1~8                ← 机侧PWM驱动(三相6路)
├── EQEP1~2                ← 编码器接口
├── GPIO (大部分)           ← 通信、指示灯、保护信号
├── SPI-A                  ← 与上位机/FPGA通信
├── CAN-A                  ← CAN总线
└── I2C                    ← EEPROM

CPU2 专属外设:
├── ADC-B (ADCINB0~15)     ← 网侧三相电流/电压采样
├── ADC-D (ADCIND0~15)     ← 网侧备用/电网电压
├── ePWM9~12               ← 网侧PWM驱动(三相6路)
├── EQEP3                  ← 备用编码器
├── SPI-B                  ← 备用通信
└── CAN-B                  ← 备用CAN

共享资源:
├── GS RAM (全局共享RAM)    ← 双核交换数据的桥梁
├── IPC (核间通信)           ← Flag + Message RAM
└── Flash (各512KB分区)

2.2 ADC分配的设计考虑

28379D有4个独立的ADC模块(ADC-A/B/C/D),每个ADC模块有自己的采样保持电路和转换器,可以并行采样

关键设计:将机侧和网侧的模拟信号分配到不同的ADC模块:

复制代码
机侧信号 (CPU1负责):
├── ADC-A: 定子三相电流 Is_a, Is_b, Is_c
├── ADC-A: 转子三相电流 Ir_a, Ir_b, Ir_c (或用ADC-C)
├── ADC-C: 直流母线电压 Vdc, 中点电压 Vnp
└── ADC-C: 定子三相电压 Vs_a, Vs_b (用于磁链观测)

网侧信号 (CPU2负责):
├── ADC-B: 电网侧三相电流 Ig_a, Ig_b, Ig_c
├── ADC-B: 电网三相电压 Vg_a, Vg_b, Vg_c
├── ADC-D: 直流母线电压 Vdc (与CPU1共享,用于协调)
└── ADC-D: 备用通道

为什么这样分配?

  1. 采样同步性 :机侧和网侧的电流需要在同一时刻 采样,否则功率计算有误差。将两侧信号分配到不同ADC模块,可以利用ADC的同步采样功能。
  2. 中断隔离:ADC-A的完成中断给CPU1,ADC-B的完成中断给CPU2,互不干扰。
  3. 减少IPC通信:如果把机侧信号都给CPU1、网侧信号都给CPU2,两个核可以独立完成各自的控制,不需要通过IPC传递采样数据。

2.3 PWM分配的设计考虑

复制代码
机侧PWM (CPU1控制):
├── ePWM1A/B → A相上/下桥臂
├── ePWM2A/B → B相上/下桥臂
├── ePWM3A/B → C相上/下桥臂
├── ePWM4    → 机侧Crowbar/Chopper控制
└── ePWM5    → 备用

网侧PWM (CPU2控制):
├── ePWM9A/B  → A相上/下桥臂
├── ePWM10A/B → B相上/下桥臂
├── ePWM11A/B → C相上/下桥臂
└── ePWM12    → 网侧Chopper控制

ePWM模块的同步

机侧和网侧的PWM需要同步(避免直流母线纹波),通过ePWM模块的同步链实现:

复制代码
ePWM1 (机侧主PWM, CPU1控制)
  │
  ├── 同步信号 → ePWM2 → ePWM3 (机侧从PWM)
  │
  └── 同步信号 → ePWM9 (网侧主PWM, CPU2控制)
                   │
                   └── ePWM10 → ePWM11 (网侧从PWM)

三、任务分布策略

3.1 分布原则

原则 说明
物理就近 外设分配到哪个CPU,控制任务就分配到哪个CPU
时间隔离 机侧和网侧的快任务不抢占同一个CPU的时间
独立性 尽量减少双核之间的数据交换
安全冗余 关键保护逻辑在两个核上都有副本

3.2 推荐的任务分布方案

复制代码
┌──────────────────────────────────┐  ┌──────────────────────────────────┐
│          CPU1 (机侧)              │  │          CPU2 (网侧)              │
│                                  │  │                                  │
│  ┌────────────────────────────┐  │  │  ┌────────────────────────────┐  │
│  │ PWM中断 (250μs, ePWM1触发) │  │  │  │ PWM中断 (250μs, ePWM9触发) │  │
│  │                            │  │  │  │                            │  │
│  │  · ADC-A/C采样 (Is, Ir, Vdc)│  │  │  │  · ADC-B/D采样 (Ig, Vg, Vdc)│  │
│  │  · Clarke/Park变换          │  │  │  │  · Clarke/Park变换          │  │
│  │  · RSC电流环PI              │  │  │  │  · GSC电流环PI              │  │
│  │  · 前馈解耦                 │  │  │  │  · 前馈解耦 + 电压前馈      │  │
│  │  · SVPWM计算               │  │  │  │  · SVPWM计算               │  │
│  │  · 更新ePWM1~3占空比        │  │  │  │  · 更新ePWM9~11占空比       │  │
│  │  · RSC过流保护              │  │  │  │  · GSC过流保护              │  │
│  │  · 采样数据→共享RAM(给CPU2) │  │  │  │  · 采样数据→共享RAM(给CPU1) │  │
│  └────────────────────────────┘  │  │  └────────────────────────────┘  │
│                                  │  │                                  │
│  ┌────────────────────────────┐  │  │  ┌────────────────────────────┐  │
│  │ 定时器中断 (1ms)            │  │  │  │ 定时器中断 (1ms)            │  │
│  │                            │  │  │  │                            │  │
│  │  · 转矩外环PI               │  │  │  │  · 直流母线电压环PI          │  │
│  │  · 弱磁控制                 │  │  │  │  · PLL锁相环                │  │
│  │  · 磁链观测器               │  │  │  │  · 无功功率控制              │  │
│  │  · 编码器角度计算           │  │  │  │  · LVRT无功注入逻辑         │  │
│  └────────────────────────────┘  │  │  └────────────────────────────┘  │
│                                  │  │                                  │
│  ┌────────────────────────────┐  │  │  ┌────────────────────────────┐  │
│  │ 后台任务 (10ms, 主循环)     │  │  │  │ 后台任务 (10ms, 主循环)     │  │
│  │                            │  │  │  │                            │  │
│  │  · 同步/并网状态机          │  │  │  │  · 故障录波                  │  │
│  │  · LVRT检测与切换          │  │  │  │  · MODBUS通信               │  │
│  │  · MPPT计算                │  │  │  │  · CAN通信                  │  │
│  │  · 系统状态管理            │  │  │  │  · 参数读写                  │  │
│  │  · 故障管理                │  │  │  │  · 功率协调(与CPU1交换数据)  │  │
│  │  · 编码器自检              │  │  │  │  · DC-Chopper控制            │  │
│  └────────────────────────────┘  │  │  └────────────────────────────┘  │
│                                  │  │                                  │
│  ┌────────────────────────────┐  │  │  ┌────────────────────────────┐  │
│  │ CLA1 (协处理器)            │  │  │  │ CLA2 (协处理器)            │  │
│  │                            │  │  │  │                            │  │
│  │  · sin/cos查表加速          │  │  │  │  · sin/cos查表加速          │  │
│  │  · Park/Clarke变换         │  │  │  │  · Park/Clarke变换         │  │
│  │  · SVPWM计算               │  │  │  │  · SVPWM计算               │  │
│  └────────────────────────────┘  │  │  └────────────────────────────┘  │
└──────────────────────────────────┘  └──────────────────────────────────┘

3.3 为什么这样分配?

理由1:外设物理就近(最重要)

ADC-A采样的机侧电流,转换完成后立即触发CPU1的中断。CPU1就地执行Park变换、PI控制、SVPWM,然后更新ePWM1~3。整个链路不需要跨核通信,延迟最小。

如果把机侧控制放到CPU2,就需要:

  1. CPU1读取ADC-A
  2. CPU1通过IPC将数据传给CPU2
  3. CPU2执行控制算法
  4. CPU2通过IPC将PWM占空比传回CPU1
  5. CPU1更新ePWM

每一步IPC通信都会增加延迟,且增加了出错的风险。

理由2:CPU时间预算

让我们计算CPU1在一个PWM周期(250μs)内需要完成的计算量:

复制代码
CPU1快任务 (250μs内完成):
├── ADC读取: 6个通道 × ~1μs = 6μs
├── Clarke变换: 3次乘法+加法 ≈ 0.5μs
├── Park变换: 4次乘法+2次加法 ≈ 1μs (sin/cos用查表)
├── PI控制器 (2个): 2 × (2次乘法+2次加法+限幅) ≈ 2μs
├── 前馈解耦: 4次乘法+2次加法 ≈ 1μs
├── 反Park变换: 4次乘法+2次加法 ≈ 1μs
├── SVPWM: 扇区判断+时间计算 ≈ 3μs
├── PWM更新: 3次寄存器写入 ≈ 0.5μs
├── 保护判断: 比较+逻辑 ≈ 1μs
├── 数据写入共享RAM ≈ 1μs
└── 中断响应/恢复开销 ≈ 5μs
────────────────────────────
总计: ≈ 22μs
CPU1利用率: 22/250 = 8.8%

如果把网侧控制也放到CPU1:

复制代码
CPU1快任务 (250μs内, 双侧):
├── 机侧控制: 22μs
├── 网侧控制: 22μs
├── IPC通信开销: ~5μs
├── 上下文切换: ~5μs
────────────────────────────
总计: ≈ 54μs
CPU1利用率: 54/250 = 21.6%

看起来21.6%也不高?但这是理想情况。 在实际中:

  • 中断嵌套和优先级管理会增加开销
  • Flash等待状态会增加代码执行时间
  • 如果机侧和网侧的PWM中断同时触发,高优先级会抢占低优先级,导致延迟抖动

双核分离后,两侧的快任务完全并行执行,互不影响。

理由3:故障隔离

如果机侧控制出现异常(如PI积分风暴、死循环),不会影响网侧控制。网侧可以继续维持直流母线电压和并网运行,给系统留出安全降额的时间。


四、核间通信(IPC)设计

4.1 IPC机制

28379D提供以下IPC通信方式:

方式 延迟 带宽 适用场景
IPC Flag ~100ns 1 bit × 16通道 状态标志、触发信号
IPC Message RAM ~500ns 4×32bit × 2通道 少量数据交换
共享RAM (GS) ~100ns 任意大小 大量数据交换

4.2 共享RAM的数据结构设计

c 复制代码
// 共享RAM区域 (放在GS0 RAM中)
#pragma DATA_SECTION(shared_data, "SHAREDMEM")
volatile SharedData_t shared_data;

typedef struct {
    // ---- CPU1 → CPU2 (机侧给网侧) ----
    float Vdc_rsc;              // 机侧测量的直流母线电压
    float P_rsc;                // 机侧有功功率
    float Q_rsc;                // 机侧无功功率
    float id_rsc;               // 机侧d轴电流 (实际值)
    float iq_rsc;               // 机侧q轴电流 (实际值)
    float omega_r;              // 转子电角速度
    int   system_state;         // 系统状态 (同步/运行/LVRT/故障)
    int   fault_code;           // 故障码
    int   is_lvrt;              // LVRT标志
    
    // ---- CPU2 → CPU1 (网侧给机侧) ----
    float Vdc_gsc;              // 网侧测量的直流母线电压
    float P_gsc;                // 网侧有功功率
    float Q_gsc;                // 网侧无功功率
    float id_gsc;               // 网侧d轴电流
    float iq_gsc;               // 网侧q轴电流
    float theta_pll;            // PLL角度
    float omega_pll;            // PLL角速度
    float Vg_pu;                // 电网电压标幺值
    int   grid_connected;       // 并网状态
    
    // ---- 保护协调 (双向) ----
    int   emergency_stop;       // 紧急停机标志 (任一核可设置)
    int   chopper_enable;       // DC-Chopper使能
    float Vdc_max_recorded;     // 记录到的最大Vdc
    
} SharedData_t;

4.3 IPC同步策略

原则:尽量减少同步等待,用"最新值"策略。

c 复制代码
// CPU1: 写入共享数据 (快任务末尾)
void CPU1_WriteSharedData(void) {
    // 使用"先写后标记"策略
    shared_data.Vdc_rsc = Vdc_measured;
    shared_data.P_rsc = P_stator;
    shared_data.Q_rsc = Q_stator;
    shared_data.omega_r = omega_elec;
    shared_data.system_state = current_state;
    shared_data.is_lvrt = is_lvrt_flag;
    
    // 原子标记: 数据已更新
    // 使用Flag通知CPU2
    IPC_setFlag(IPC_CPU1_TO_CPU2, FLAG_DATA_READY);
}

// CPU2: 读取共享数据 (快任务开始)
void CPU2_ReadSharedData(void) {
    // 直接读取, 不等待Flag (最新值策略)
    // 如果上一拍的数据还没更新, 用上一拍的也没关系
    Vdc_from_rsc = shared_data.Vdc_rsc;
    P_rsc_actual = shared_data.P_rsc;
    omega_elec = shared_data.omega_r;
    system_state = shared_data.system_state;
    is_lvrt = shared_data.is_lvrt;
    
    // 清除Flag
    IPC_clearFlag(IPC_CPU1_TO_CPU2, FLAG_DATA_READY);
}

关键设计 :不要用IPC Flag做阻塞等待(如 while(!flag)),这会导致CPU空转,浪费时间。用"最新值"策略------直接读共享RAM中的数据,如果数据是上一拍的,对控制性能的影响微乎其微。

4.4 共享RAM的Cache一致性问题

28379D的CPU有L1 Cache(指令Cache和数据Cache)。如果共享RAM的数据被Cache缓存,CPU2修改了共享RAM,CPU1的Cache中还是旧值。

解决方案

c 复制代码
// 方法1: 将共享RAM区域配置为Non-Cacheable
// 在CMD文件中:
// SHAREDMEM : > GS0, PAGE 1, type = NOCACHE

// 方法2: 在读写共享数据前后手动刷新Cache
void CPU2_WriteSharedData_Safe(void) {
    // 写入
    shared_data.P_gsc = P_grid;
    
    // 写回Cache到RAM (确保CPU1能看到)
    // 对于C2000, 通常不需要手动flush (Write-Through策略)
    // 但建议使用volatile关键字确保编译器不优化掉读写操作
}

工程建议 :在CMD链接文件中将共享RAM区域标记为 NOCACHE,最简单可靠。


五、启动与初始化流程

5.1 双核启动顺序

复制代码
┌─────────────────────────────────────────────────────────────────┐
│ 上电复位                                                        │
│     │                                                           │
│     ▼                                                           │
│ CPU1 Boot ROM (自动执行)                                        │
│     │                                                           │
│     ▼                                                           │
│ CPU1 main()                                                     │
│     │                                                           │
│     ├── Step 1: 系统时钟初始化 (200MHz)                          │
│     ├── Step 2: 使能所有外设时钟                                 │
│     ├── Step 3: GPIO复用配置                                    │
│     ├── Step 4: 配置ADC-A, ADC-C (机侧)                        │
│     ├── Step 5: 配置ePWM1~8 (机侧)                             │
│     ├── Step 6: 配置EQEP1 (编码器)                              │
│     ├── Step 7: 配置共享RAM                                     │
│     ├── Step 8: 配置IPC                                         │
│     │                                                           │
│     ├── Step 9: 启动CPU2! ─────────────────────────┐           │
│     │     (通过写IPC Boot寄存器)                     │           │
│     │                                               │           │
│     ├── Step 10: 配置CPU1的中断                      │           │
│     ├── Step 11: 使能PWM中断                         │           │
│     │                                               ▼           │
│     ├── Step 12: 进入主循环                        CPU2 Boot ROM │
│     │                                               │           │
│     │                                               ▼           │
│     │                                          CPU2 main()      │
│     │                                               │           │
│     │                                               ├── 配置ADC-B, ADC-D │
│     │                                               ├── 配置ePWM9~12    │
│     │                                               ├── 配置中断        │
│     │                                               ├── 使能PWM中断     │
│     │                                               └── 进入主循环      │
│     │                                                           │
│     ▼                                                           │
│  双核并行运行                                                    │
└─────────────────────────────────────────────────────────────────┘

5.2 CPU1启动CPU2的代码

c 复制代码
// CPU1代码中, 启动CPU2
void CPU1_BootCPU2(void) {
    // Step 1: 将CPU2的程序加载到Flash/RAM
    // (通常由链接器自动完成, CPU2代码放在CPU2的Flash分区)
    
    // Step 2: 配置CPU2的Boot地址
    // 写入IPC Boot寄存器
    IPC_setBootMode(IPC_CPU2, BOOT_FROM_FLASH);  // 或 BOOT_FROM_RAM
    
    // Step 3: 释放CPU2
    IPC_releaseCPU2();
    
    // Step 4: 等待CPU2就绪 (可选)
    while (!IPC_getFlag(IPC_CPU2_TO_CPU1, FLAG_CPU2_READY)) {
        // 等待, 但加超时保护
        if (timeout_counter++ > MAX_TIMEOUT) {
            FAULT_Set(FAULT_CPU2_BOOT_FAIL);
            break;
        }
    }
}

5.3 双核同步的关键时序

问题:CPU1和CPU2的PWM中断必须同步,否则机侧和网侧的控制不同步,直流母线功率会出现不平衡。

解决方案:用ePWM的同步链实现硬件级同步:

c 复制代码
// CPU1配置 (ePWM1作为主同步源)
void CPU1_PWM_SyncConfig(void) {
    // ePWM1: 主PWM, 产生同步信号
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;   // 不接收外部同步
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // 在计数器=0时输出同步
    
    // ePWM2, ePWM3: 从PWM, 接收ePWM1的同步
    EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    
    // 同步信号链: ePWM1 → ePWM2 → ePWM3 → ... → ePWM9 (CPU2)
}

// CPU2配置 (ePWM9接收来自ePWM1的同步)
void CPU2_PWM_SyncConfig(void) {
    // ePWM9: 接收CPU1 ePWM1的同步信号
    EPwm9Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm9Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
    
    // ePWM10, ePWM11: 接收ePWM9的同步
    EPwm10Regs.TBCTL.bit.PHSEN = TB_ENABLE;
    EPwm11Regs.TBCTL.bit.PHSEN = TB_ENABLE;
}

这样,所有PWM模块(ePWM1~11)都以ePWM1的计数器为基准同步运行,采样时刻和PWM更新时刻完全对齐。


六、CLA协处理器的使用

6.1 CLA是什么?

CLA(Control Law Accelerator)是C2000 DSP中的独立协处理器,专门用于执行控制算法。它有以下特点:

特性 CLA CPU (C28x)
架构 独立哈佛架构 冯·诺依曼架构
浮点支持 硬件单精度浮点 硬件单精度浮点
指令集 C28x子集(无中断、无I/O) 完整C28x
执行方式 独立并行执行 主CPU执行
与CPU的关系 被CPU触发,执行完通知CPU 触发CLA,不等待

6.2 CLA的价值

CLA可以在CPU执行中断服务的同时,独立执行控制算法。 这相当于免费获得了额外的计算能力

复制代码
不使用CLA:
时间 ──────────────────────────────────►
CPU1: [ADC中断]──[控制算法计算]──[更新PWM]──[主循环]──[ADC中断]...
      │←──────── 22μs ────────→│

使用CLA:
时间 ──────────────────────────────────►
CPU1: [ADC中断]──[触发CLA]──[主循环]──[CLA完成中断]──[更新PWM]...
      │← 2μs →│                           │← 3μs →│

CLA:               [控制算法计算]──[完成]
                    │←── 20μs ──→│

CPU1的中断服务时间从22μs缩短到5μs,释放了大量CPU时间。

6.3 CLA的任务分配建议

复制代码
CLA1 (配合CPU1, 机侧):
├── Park/Clarke变换
├── PI控制器计算
├── 前馈解耦计算
├── SVPWM占空比计算
└── sin/cos查表 (通过TMU)

CLA2 (配合CPU2, 网侧):
├── Park/Clarke变换
├── PI控制器计算
├── 前馈解耦计算
├── SVPWM占空比计算
└── PLL计算

注意:CLA不能访问外设寄存器(如ADC结果寄存器、PWM占空比寄存器)。CPU需要先把数据从外设读到RAM中,CLA从RAM读取计算,计算结果放回RAM,CPU再写入外设。

c 复制代码
// CPU1的ADC中断服务 (触发CLA)
__interrupt void ADC_ISR(void) {
    // Step 1: 从ADC读取原始数据到CLA的数据RAM
    Cla1Regs.MVECT = TASK_CONTROL_ALGORITHM;  // 指定CLA任务
    
    // 将ADC结果拷贝到CLA可访问的RAM
    Cla1Data.Ia_raw = AdcaResultRegs.ADCRESULT0;
    Cla1Data.Ib_raw = AdcaResultRegs.ADCRESULT1;
    Cla1Data.Vdc_raw = AdccResultRegs.ADCRESULT0;
    Cla1Data.theta = encoder_angle;
    
    // Step 2: 触发CLA执行
    __cla1_force_task(TASK_CONTROL_ALGORITHM);
    
    // Step 3: CPU1不等待CLA, 继续执行其他任务
    // (如保护判断、通信处理)
    
    // Step 4: CLA完成后, 在CLA完成中断中读取结果并更新PWM
}

// CLA完成中断
__interrupt void CLA1_Done_ISR(void) {
    // 从CLA的数据RAM读取结果
    float Ta = Cla1Data.Ta_result;
    float Tb = Cla1Data.Tb_result;
    float Tc = Cla1Data.Tc_result;
    
    // 更新PWM占空比
    EPwm1Regs.CMPA.bit.CMPA = (uint16_t)(Ta * PWM_PERIOD);
    EPwm2Regs.CMPA.bit.CMPA = (uint16_t)(Tb * PWM_PERIOD);
    EPwm3Regs.CMPA.bit.CMPA = (uint16_t)(Tc * PWM_PERIOD);
}

七、中断优先级设计

7.1 CPU1的中断优先级

复制代码
优先级   中断源              用途                    最大响应延迟
─────────────────────────────────────────────────────────────────
最高     ADC-A完成中断        机侧电流采样+控制       < 1μs
         ↓
高       ePWM1过流比较中断    硬件过流保护            < 200ns (硬件)
         ↓
中       定时器0中断 (1ms)    转矩环/弱磁/磁链观测    < 5μs
         ↓
低       ePWM1周期中断        同步/状态更新           < 10μs
         ↓
最低     IPC中断              核间通信                < 20μs
         ↓
最低     SCI/SPI中断          通信                    不要求实时

7.2 关键设计:ADC中断必须最高优先级

c 复制代码
// ADC中断配置 (PIE Group 1, 最高优先级)
void Config_ADC_ISR(void) {
    // ADC-A完成 → PIE1.1 (ADCA1)
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;  // 使能ADCA1中断
    IER |= M_INT1;                        // 使能Group 1
    
    // 优先级: 通过PIE内的轮转顺序, INTx1自然具有最高优先级
}

为什么ADC中断必须最高?

ADC中断是整个控制链的"起点"。如果ADC中断被延迟,后续所有计算都会延迟,导致:

  • 采样时刻偏移(不在PWM中心)
  • PI计算延迟增大(等效增大 1.5Ts1.5T_s1.5Ts 中的 TsT_sTs)
  • 电流控制性能恶化

八、工程实践中的常见问题

问题1:双核同时写同一个寄存器

现象:CPU1和CPU2同时尝试写ADC的某个配置寄存器,导致配置混乱。

对策:严格遵守"谁的外设谁配置"原则。在CPU1的初始化代码中,一次性配置完所有共享外设,然后CPU2不再修改。

问题2:共享RAM数据不一致

现象:CPU1正在写共享数据结构(多字节),CPU2读到了"一半新一半旧"的值。

对策 :使用双缓冲原子标志

c 复制代码
// 双缓冲方案
typedef struct {
    SharedData_t buffer[2];
    volatile int write_index;  // 0 或 1
} DoubleBuffer_t;

// CPU1写入
void CPU1_Write(DoubleBuffer_t *db) {
    int idx = db->write_index;
    db->buffer[idx].P_rsc = P_measured;
    db->buffer[idx].Vdc = Vdc_measured;
    // ... 写完所有数据后, 切换索引
    db->write_index = 1 - idx;  // 原子切换
}

// CPU2读取
void CPU2_Read(DoubleBuffer_t *db) {
    int idx = 1 - db->write_index;  // 读另一个buffer
    P_from_rsc = db->buffer[idx].P_rsc;
    Vdc_from_rsc = db->buffer[idx].Vdc;
}

问题3:CPU2启动失败

现象:上电后CPU2没有正常运行,网侧变流器不工作。

对策

  1. CPU1启动CPU2后加超时检测
  2. CPU2启动后通过IPC Flag报告"就绪"
  3. 如果CPU2启动失败,CPU1进入安全模式(只运行机侧,限制功率)

问题4:Flash访问竞争

现象:CPU1和CPU2同时从Flash取指令,Flash只有一个读端口,需要仲裁,导致其中一个CPU等待。

对策

  • 将热点代码(快任务)拷贝到RAM中执行
  • 使用 #pragma CODE_SECTION 将关键函数分配到RAM
c 复制代码
#pragma CODE_SECTION(RSC_CurrentLoop, "ramfuncs")
void RSC_CurrentLoop(void) {
    // 这个函数将在RAM中执行, 不受Flash等待状态影响
    // ...
}

九、任务分布的替代方案对比

方案 描述 优点 缺点
A: 机侧/网侧分离(推荐) CPU1=RSC, CPU2=GSC 外设就近、独立性强、故障隔离 需要IPC交换数据
B: 快任务/慢任务分离 CPU1=快任务(两侧), CPU2=慢任务 不需要IPC交换实时数据 CPU1负担重、两侧不独立
C: 单核运行 只用CPU1, CPU2空闲 最简单 浪费50%计算能力
D: 三环分离 CPU1=电流环, CPU2=转矩环+电压环 与控制层级对应 电流环延迟增大

工程界主流选择是方案A(机侧/网侧分离),原因是外设分配决定了任务分配,强行将两侧的控制放在同一个核上只会增加不必要的复杂度和延迟。


十、总结

问题 答案
CPU1和CPU2的计算能力有区别吗? 没有,完全相同的C28x核,都是200MHz + FPU + TMU
那区别在哪? 外设访问权限和系统管理权限不同,CPU1是"管家"
任务怎么分? 按外设分:机侧外设→CPU1,网侧外设→CPU2
为什么这样分? 物理就近(减少IPC延迟)、时间隔离(并行执行)、故障隔离
两个核怎么交换数据? 共享RAM + IPC Flag,用"最新值"策略,不用阻塞等待
CLA怎么用? 承担数学密集型计算(三角函数、PI、SVPWM),与CPU并行执行
启动顺序? CPU1先启动→配置系统→启动CPU2→双核并行运行
PWM怎么同步? ePWM硬件同步链,ePWM1为全局主时基

一句话:28379D的双核设计不是让你"把一个程序拆成两半",而是让你"把两个独立的控制系统放在一颗芯片上"。机侧变流器和网侧变流器本身就是两个独立的物理系统,天然适合分配到两个核上。

相关推荐
小羊在睡觉7 小时前
力扣84. 柱状图中最大的矩形
后端·算法·leetcode·golang·go
3DVisionary7 小时前
蓝光三维扫描:医疗制造的精度焦虑怎么解
人工智能·算法·制造·蓝光三维扫描·医疗制造·三维检测·义齿检测
好评笔记7 小时前
机器学习面试八股——常用损失函数
人工智能·深度学习·算法·机器学习·校招
weixin_468466857 小时前
全局与局部注意力机制新手实战指南
人工智能·python·深度学习·算法·自然语言处理·transformer·注意力机制
_日拱一卒7 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
珂朵莉MM8 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--束搜索
人工智能·算法
Omics Pro9 小时前
首个!外源天然产物综合性代谢图谱
数据库·人工智能·算法·机器学习·r语言
voidmort9 小时前
3. 微调(Fine-tuning)与强化学习(RL)的核心思想
python·深度学习·算法
三易串口屏9 小时前
实验20 自动灭火场景实验
嵌入式硬件·串口屏·三易串口屏·uart 通信