目录

一、ePWM---时基模块TB

二、ePWM---计数器比较子模块CC

三、 ePWM---动作限定模块AQ

四、ePWM---死区发生器模块DB

五、ePWM---高分辨模块HRPWM

六、ePWM---事件触发器模块ET

以上,第一节至第六节内容,配置完成了中心对称、互补、死区的两路高精度HRPWM输出,并且完成PWM触发ADC-EOC中断计算PID更新下一个周期的占空比。接下来配置CMPSS比较器&X-BAR&ePWM的DC模块&ePWM的TZ模块,来完成One-Shot过流/过压保护功能。

七、CMPSS---比较器

八、X-BAR----交叉开关ePWM-BAR

九、ePWM----数字比较模块DC

十、错误联防模块TZ

以上,当A2端口超过阈值,信号会连接到CMPSS---EPWM-BAR---DC模块---TZ模块,已达到过流/过压封波的功能。

十一、CPUTimer&SFO

贴个代码,代码由SysCfg工具导出,生成的代码在Board_init()中,在while(1)中写了一个占空比一直滑动的程序,并且建立了两个中断函数接口TZ/ADC。


  STM32现在开发流行使用STM32CUBEMX来完成初始化,极大得节省了配置单片机时间,也让配置变得更加简单可靠。Ti的C2000也随之推出自己的System Configuration Tool工具用来对C2000初始化。

图1:ePWM模块与其他外设关系

 图2:ePWM内部子模块之间关系

 打开CCS最新版,任意导入一个F28002X工程(建议简单的GPIO工程),点击左侧C2000.syscfg会弹出Ti的System Configuration Tool,添加一个EPWM,在EPWM模块下找到Time Base子模块配置栏。

  • 一、ePWM---时基模块TB

   计划配置一对中心对称且互补的PWM,频率为100Khz,那么TimeBase作为定时器将它定义为向上向下计数方式,TimeBasePeriod=999。

  • 二、ePWM---计数器比较子模块CC

设置比较器CMPA,CMPB初始值=0,这里不再赘述比较简单。

  • 三、 ePWM---动作限定模块AQ

AQ模块内部图 

这里AQ模块仅需要更改ePWMxA部分,TB计数等于COMPA时的变化来输出 互补中心对称PWMxA/PWMxB,为什么无需配置ePWMxB部分,接下来说到DB模块会讲到。

  • 四、ePWM---死区发生器模块DB

 DB模块内部图

 选择Active High Complementary(AHC), 即互补带死区输出模式。由DB模块内部图可知,OUTA/OUTB可以由AQ模块输出的ePWMxA为信号源,在ePWMxA基础上叠加死区延时和反向器完成了互补带死区输出方式,其中Rising/Falling Edge Delay Value分别为OUTA/OUTB的死区延时值10,10=10*TBclk,由之前配置的TBclk=主频100M/(1*1),可知10这里延时为100ns。

  • 五、ePWM---高分辨模块HRPWM

 

 因为是中心对称PWM,那么MEP作用于上升沿和下降沿。

 上图为参考文档翻译下来的,由此可知,当使用HRPWM时且Period=1000时,那么普通比较值CMPA只能在3~997之间,即占空比为0.3%~99.7%。

 设置比较器值时使用

HRPWM_setCounterCompareValue(EPWM1_BASE,HRPWM_COUNTER_COMPARE_A,X);

来调制占空比,X值为CMPA<<8+CMPAHR,由Period(1000<<8=25600)和范围限制可知X范围为:768~255232(0.3%~99.7%)。

计算分辨率EPWMclk=100Mhz,普通精度=1/100Mhz=10ns,高分辨精度=10ns/256=40ps。

但是由于规格书描述,F28002X的HRPWM精确度固定约为190ps。

则高分辨相对精度=190ps/(1/100khz)=0.002%

  • 六、ePWM---事件触发器模块ET

 ET模块内部关系图

因为前面配置为中心对称PWM,而我们想要在ePWMxA输出位置的负脉宽中心去触发ADC采样,所以配置为TB计数=Period触发。

 ADC模块位置相应,SOC选用ePWMx的ADCSOCA作为采样触发源。

 紧接下来,使能ADC中断,并将ADC的EOC2作为中断源,发生ADC采样完成后进入中断函数。

 数字电源的环路原理即,采样->PID计算更改比较值->更改占空。ET模块配合ADC的EOC模块,完成了由PWM中心位置触发ADC到完成ADC进入中断函数的过程,中断函数中更改CMPA/CMPAHR来更改下一个周期的占空比。

以上,第一节至第六节内容,配置完成了中心对称、互补、死区的两路高精度HRPWM输出,并且完成PWM触发ADC-EOC中断计算PID更新下一个周期的占空比。接下来配置CMPSS比较器&X-BAR&ePWM的DC模块&ePWM的TZ模块,来完成One-Shot过流/过压保护功能。

  • 七、CMPSS---比较器

 比较器与外部IO的关系图

IO口复用为CMPSS表,此例使用A2作为PWM刹车One-Shot

 CMPSS内部关系图

 比较器配置如上,当A2检测值大于2500/4096*VDDA时,将输出高电平信号给ePWM-BAR

  • 八、X-BAR----交叉开关ePWM-BAR

添加一个EPWM-BAR,链接CMPSS1_CTRIPH至TRIP4,如此TRIP4就可以链接到下一个模块ePWM的DC模块

  • 九、ePWM----数字比较模块DC

 数字比较器模块DC关系图

 DCxEVT1  Event Trigger内部图,图中红线即下图配置完成后的路径

上一节已经讲述到TRIP4连接至DC模块,配置未启用数字滤波功能,后续根据项目需求启用以防止误触发,现在我们配置完成输出DCAEVT1.force至下一个模块TZ

  • 十、错误联防模块TZ

 TZ模块内部图

以上,当A2端口超过阈值,信号会连接到CMPSS---EPWM-BAR---DC模块---TZ模块,已达到过流/过压封波的功能。

  • 十一、CPUTimer&SFO

 

 另外添加CPUTIMER2作为系统心跳,添加SFO软件库用于高分辨率校准。

  • 贴个代码,代码由SysCfg工具导出,生成的代码在Board_init()中,在while(1)中写了一个占空比一直滑动的程序,并且建立了两个中断函数接口TZ/ADC。

#include "main.h"

#define EPWM_TIMER_TBPRD            1000UL
#define MIN_HRPWM_DUTY_PERCENT      4.0/((float32_t)EPWM_TIMER_TBPRD)*100.0
//
// Defines
//
#define LAST_EPWM_INDEX_FOR_EXAMPLE    5
//
// Globals
//
uint16_t cpuTimer2IntCount;
float32_t dutyFine = MIN_HRPWM_DUTY_PERCENT;
uint16_t i;
/*For SFO*/
//uint16_t status;
//int MEP_ScaleFactor; // Global variable used by the SFO library
                     // Result can be used for all HRPWM channels
                     // This variable is also copied to HRMSTEP
                     // register by SFO() function.

//volatile uint32_t ePWM[] = {0, myEPWM1_BASE};//, myEPWM2_BASE, myEPWM3_BASE, myEPWM4_BASE};
/*For SFO*/

//
// Function Prototypes
//
//static void error(void);

__interrupt void INT_myCPUTIMER2_ISR(void);
__interrupt void INT_myADCA_1_ISR(void);
__interrupt void INT_myEPWM1_TZ_ISR(void);
//__interrupt void INT_myEPWM1_ISR(void);


//
// Main
//
void main(void)
{
    Device_init();// Initializes device clock and peripherals
    Interrupt_initModule();// Initializes PIE and clears PIE registers. Disables CPU interrupts.
    Interrupt_initVectorTable();// Initializes the PIE vector table with pointers to the shell Interrupt Service Routines (ISR).
    C2000Ware_libraries_init();//Initializes C2000Ware_libraries
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);// Disable sync(Freeze clock to PWM as well)
    Board_init();// Board Initialization
//    HRPWM_setChannelBOutputPath(EPWM1_BASE,HRPWM_OUTPUT_ON_B_INV_A);//设定B通道为A的反向
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);// Enable sync and clock to PWM

    EINT;// Enable Global Interrupt (INTM)
    ERTM;// Enable realtime interrupt (DBGM)

    while (1)
    {
        if(cpuTimer2IntCount)
        {
            cpuTimer2IntCount = 0;
            LedTask();
            if(dutyFine < 99.9f)
            {
                dutyFine += 0.01f;
                float32_t count = (dutyFine * (float32_t)(EPWM_TIMER_TBPRD << 8))/100;
                uint32_t compCount = (count);
                HRPWM_setCounterCompareValue(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A, compCount);
//                HRPWM_setCounterCompareValue(EPWM1_BASE, HRPWM_COUNTER_COMPARE_B, compCount);
            }
            else
            {
                dutyFine = MIN_HRPWM_DUTY_PERCENT;
            }
            /*
                Call the scale factor optimizer lib function SFO()
                periodically to track for any change due to temp/voltage.
                This function generates MEP_ScaleFactor by running the
                MEP calibration module in the HRPWM logic. This scale
                factor can be used for all HRPWM channels. The SFO()
                function also updates the HRMSTEP register with the
                scale factor value.
            */
            mySFO0_runtime();
        }
    }
}
//
// cpuTimer2ISR - Counter for CpuTimer2
//
__interrupt void INT_myCPUTIMER2_ISR(void)
{
    //
    // The CPU acknowledges the interrupt.
    //
    cpuTimer2IntCount++;
}
//
// ADC A Interrupt 1 ISR
//
__interrupt void INT_myADCA_1_ISR(void)
{
    HWREG(GPIODATA_BASE + GPIO_O_GPATOGGLE) |= 0x80000000;//RedLED 翻转测试
    //
    // Store results
    //
//    adcAResult0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
//    adcAResult1 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
//    adcAResult2 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER2);
//    adcCResult0 = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
//    adcCResult1 = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER1);
//    adcCResult2 = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER2);

    //
    // Clear the interrupt flag
    //
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
    {
        ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    }

    //
    // Acknowledge the interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

__interrupt void INT_myEPWM1_TZ_ISR(void){


     //
     // Clear the flags
     //


     //
     // Acknowledge this interrupt to receive more interrupts from group 2
     //
     Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP2);
}

  终于写完C2000了,发表这个文章的目的是记录本菜鸡学DSP的过程,也当做一个笔记,有错误的地方欢迎指出,或更好的建议大家一起分享,共同进步。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐