1.4. GPIO 与 PIE 中断系统

F28335 有 88 个 GPIO 引脚,每个引脚可配置为通用 I/O 或外设功能。

1.4.1. GPIO 配置

// GPIO 模式设置
// 每个 GPIO 有 4 种功能(通过 GPAMUX1/2 或 GPBMUX1/2 配置)

void Gpio_setup(void)
{
    EALLOW;

    // GPIO0:通用输出
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0;   // 00 = GPIO 模式
    GpioCtrlRegs.GPADIR.bit.GPIO0 = 1;    // 输出
    GpioCtrlRegs.GPAQSEL1.bit.GPIO0 = 0;  // 同步采样(输入滤波)

    // GPIO1:通用输入(上拉)
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 0;
    GpioCtrlRegs.GPADIR.bit.GPIO1 = 0;    // 输入
    GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0;    // 使能上拉(0=启用)

    // GPIO2:ePWM1A 外设功能
    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1;   // 01 = ePWM1A

    // GPIO3:SCI 接收
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1;   // 01 = SCIRXDA

    EDIS;
}

GPAMUX 值

功能

00

通用 GPIO

01

外设功能 1

10

外设功能 2

11

外设功能 3

1.4.2. GPIO 读写

// 写输出
GpioDataRegs.GPADAT.bit.GPIO0 = 1;    // 高电平
GpioDataRegs.GPADAT.bit.GPIO0 = 0;    // 低电平

// 推荐:仅翻转指定位(不影响其他引脚)
GpioDataRegs.GPASET.bit.GPIO0 = 1;    // 置位
GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;  // 清零
GpioDataRegs.GPATOGGLE.bit.GPIO0 = 1; // 翻转

// 读输入(不管 GPIO 方向,都能读取实际引脚电平)
uint16_t pin = GpioDataRegs.GPADAT.bit.GPIO1;

1.4.3. PIE 中断系统

F28335 的 PIE(外设中断扩展)模块将 96 个外设中断复用到 12 个 CPU 中断。

PIE 中断结构:

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  外设中断源   │────→│   PIE 分组    │────→│   CPU 中断    │
│  (96个)       │     │  (12组×8路)  │     │  INT1~INT12  │
└──────────────┘     └──────────────┘     └──────────────┘

PIE 分组示意:

INT1:  TIMER0  | ADCINT  | ...
INT2:  EPWM1   | EPWM2   | ...
INT3:  EPWM3   | EPWM4   | ...
INT4:  ECAP1   | ECAP2   | ...
INT5:  EQEP1   | ...
INT6:  SPIRX   | SPITX   | ...
INT7:  ...
INT8:  I2C     | ...
INT9:  SCIRX   | SCITX   | ...
INT10: CAN     | ...
INT11: CLA     | ...
INT12: XINT1-3 | ...

1.4.3.1. 中断配置步骤

// 1. 中断服务函数声明
interrupt void adc_isr(void);

// 2. 初始化 PIE 并注册中断服务
void InitInterrupts(void)
{
    // 初始化 PIE 控制寄存器
    InitPieCtrl();

    // 关闭所有 CPU 中断
    IER = 0x0000;
    IFR = 0x0000;

    // 初始化中断向量表
    InitPieVectTable();

    // 注册中断服务函数
    EALLOW;
    PieVectTable.ADCINT1 = &adc_isr;
    EDIS;

    // 使能 PIE 分组中的具体中断
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;  // PIE 组 1 的第 1 个中断 (ADC)

    // 使能 CPU 中断
    IER |= M_INT1;   // CPU 中断 1

    // 开启全局中断
    EINT;            // 相当于 asm(" CLRC INTM")
}

// 3. 实现中断服务函数
interrupt void adc_isr(void)
{
    static uint16_t sample;

    // 读取 ADC 结果
    sample = AdcRegs.ADCRESULT0;

    // 清除 ADC 中断标志
    AdcRegs.ADCST.bit.INT_FLAG_CLR = 1;

    // 应答 PIE 中断
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;

    // CPU 自动清除 INTM(中断返回时会自动恢复)
}

重要

中断服务函数必须:

  1. 清除外设中断标志 (每个外设不同)

  2. 应答 PIE 中断:PieCtrlRegs.PIEACK.all = PIEACK_GROUPn

  3. 使用 interrupt 关键字声明

  4. 代码尽量简短(避免长时间关中断)

  5. 函数名注册到 PieVectTable

1.4.4. 外部中断(XINT1~XINT3)

void InitExternalInterrupt(void)
{
    // XINT1 连接到 GPIO0,下降沿触发
    EALLOW;
    GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 0;  // GPIO0
    EDIS;

    XIntruptRegs.XINT1CR.bit.POLARITY = 1;      // 下降沿
    XIntruptRegs.XINT1CR.bit.ENABLE = 1;        // 使能

    // 注册中断
    EALLOW;
    PieVectTable.XINT1 = &xint1_isr;
    EDIS;
    PieCtrlRegs.PIEIER12.bit.INTx1 = 1;
    IER |= M_INT12;
    EINT;
}

interrupt void xint1_isr(void)
{
    XIntruptRegs.XINT1CR.bit.ENABLE = 1;  // 清除标志
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP12;
}

1.4.5. 中断优先级

优先级

CPU 中断

典型中断源

最高

INT1

PDPINTA, ADCINT, TINT0

↓

INT2~INT4

ePWM, eCAP

↓

INT5~INT8

eQEP, SPI, I2C

↓

INT9~INT11

SCI, CAN, CLA

最低

INT12

XINT1~3, 保留

小技巧

电机控制中常见的中断优先级分配:

  1. 最高:故障捕获 (PDPINT) — 立即关 PWM

  2. 高:ePWM 中断 — 电流环 (10~20 kHz)

  3. 中:ADC 中断 — 采样完成

  4. 低:SCI/CAN 中断 — 通信

  5. 最低:CPU Timer — 后台任务