1.6. ADC 与 eCAP/eQEP

1.6.1. ADC 模块

F28335 的 ADC 模块:12 位精度、16 通道、80 ns 转换时间。

ADC 模块结构:

                      ┌────────────┐
ADCINA0 ──────────→   │            │
ADCINA1 ──────────→   │  8 选 1    │
...                   │  MUX       │──→ S/H ─→ 12-bit ADC ─→ RESULT0
ADCINA7 ──────────→   │            │
                      └────────────┘
                      ┌────────────┐
ADCINB0 ──────────→   │            │
...                   │  8 选 1    │──→ S/H ─→ 12-bit ADC ─→ RESULT1
ADCINB7 ──────────→   │            │
                      └────────────┘

1.6.1.1. ADC 初始化

void InitAdc(void)
{
    // 1. 使能 ADC 时钟
    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;

    // 2. 上电校准
    AdcRegs.ADCTRL3.all = 0x00E0;  // ADC 上电,带隙参考使能
    DELAY_US(1000);                // 等待稳定

    // 3. 设置采样窗口
    AdcRegs.ADCTRL1.bit.ACQ_PS = 15;   // 采样窗口 = 16 个 ADCCLK
    // ADC 时钟 = HSPCLK / (ADCTRL3.ADCCLKPS + 1)
    // 典型值:150 MHz / (6+1) ≈ 21.4 MHz → 46.7 ns

    // 4. 设置转换模式
    AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;   // 级联模式(16 通道排序器)
    AdcRegs.ADCTRL1.bit.CONT_RUN = 0;   // 启动-停止模式
    AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1; // ePWM SOCA 触发
    AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;   // 使能 SEQ1 中断
}

1.6.1.2. 排序器配置

// 自动顺序转换 4 个通道
void Adc_ConfigChannels(void)
{
    // 设置采样通道顺序
    AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;   // ADCINA0
    AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 1;   // ADCINA1
    AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 2;   // ADCINA2
    AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 3;   // ADCINA3

    // 设置转换次数
    AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 3;  // 4 次转换 (0~3)
}

1.6.1.3. 读取结果

interrupt void adc_isr(void)
{
    uint16_t sample[4];

    // 读取结果(结果寄存器自动递增)
    sample[0] = AdcRegs.ADCRESULT0 >> 4;   // 右对齐→右移4位
    sample[1] = AdcRegs.ADCRESULT1 >> 4;
    sample[2] = AdcRegs.ADCRESULT2 >> 4;
    sample[3] = AdcRegs.ADCRESULT3 >> 4;

    // 转换为电压(0~4095 → 0~3.3V)
    float voltage = (sample[0] * 3.3) / 4095.0;

    // 清除标志
    AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

1.6.2. eCAP 捕获模块

eCAP 用于测量 PWM 信号的频率、占空比和相位差。

eCAP 工作模式(4 种):

模式 1:捕获模式
   捕获输入信号的边沿,记录时间戳
   用于测量频率/占空比

模式 2:APWM 模式
   作为简易 PWM 发生器使用

1.6.2.1. eCAP 捕获测量频率

void ECap1_Init(void)
{
    // 捕获模式配置
    ECap1Regs.ECEINT.all = 0x0000;     // 先关闭中断
    ECap1Regs.ECCLR.all = 0xFFFF;      // 清除标志

    ECap1Regs.ECCTL1.bit.CAPLDEN = 1;  // 使能捕获加载
    ECap1Regs.ECCTL1.bit.PRESCALE = 0; // 预分频系数 ÷1
    ECap1Regs.ECCTL1.bit.CAP1POL = 0;  // 上升沿触发
    ECap1Regs.ECCTL1.bit.CAP2POL = 1;  // 下降沿触发
    ECap1Regs.ECCTL1.bit.CAP3POL = 1;  // 下降沿
    ECap1Regs.ECCTL1.bit.CAP4POL = 0;  // 上升沿

    ECap1Regs.ECCTL2.bit.CONT_ONESHT = 1;  // 单次触发
    ECap1Regs.ECCTL2.bit.STOP_WRAP = 3;    // 4 个事件后停止
    ECap1Regs.ECCTL2.bit.REARM = 1;        // 强制重新触发
    ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;    // 启动计数器

    // 中断配置
    ECap1Regs.ECEINT.bit.CEVT4 = 1;    // 第 4 个捕获事件触发中断
}

// 计算频率
float ECap1_GetFrequency(void)
{
    uint32_t period = ECap1Regs.CAP1;   // 周期计数值
    float freq = 150e6 / (float)period; // 频率 = SYSCLKOUT / period
    return freq;
}

1.6.3. eQEP 正交编码器接口

eQEP 连接电机编码器,获取位置和速度信息。

QEP 信号:

QEPA ──┤ ├────┤ ├────┤ ├────   (A 相)
QEPB ──┤ ├──┤ ├────┤ ├──┤ ├─  (B 相,相位差 90°)
QEPI ──┤ ├───────────────────  (Z 相索引/零位)
void EQep1_Init(void)
{
    // 正交计数模式
    EQep1Regs.QUPRD = 1500;            // 速度计算周期(单位:CPU 时钟)
    EQep1Regs.QDECCTL.bit.QSRC = 0;    // 正交模式(QA+QB 输入)
    EQep1Regs.QDECCTL.bit.XCR = 0;     // 2x 分辨率(提升 2 倍)
    EQep1Regs.QDECCTL.bit.SWAP = 0;    // 不交换 QA/QB

    // 位置计数器
    EQep1Regs.QPOSINIT = 0;            // 初始位置
    EQep1Regs.QPOSMAX = 0xFFFFFFFF;    // 最大位置

    // 使能中断(位置到达或速度计算完成)
    EQep1Regs.QEINT.bit.QDC = 1;       // 方向变化中断
    EQep1Regs.QEINT.bit.QFLG = 1;
    EQep1Regs.QCAPCTL.bit.UPPS = 5;    // 单位位置事件预分频
    EQep1Regs.QCAPCTL.bit.CCPPS = 7;   // 捕获时钟预分频
    EQep1Regs.QCAPCTL.bit.CEN = 1;     // 使能位置捕获
}

// 读取位置
int32_t EQep1_GetPosition(void)
{
    return EQep1Regs.QPOSCNT;          // 当前计数值
}

// 读取速度 (rpm)
float EQep1_GetSpeed(void)
{
    uint32_t pulse = EQep1Regs.QPOSLAT; // 最后捕获的位置差
    // speed_rpm = pulse × 60 / (encoder_ppr × QUPRD × 150e6)
    return pulse * 60.0 / (4000.0 * 1500 * 150e-6);
}