HRPWM和普通PWM都是用于控制电机速度、电力信号、灯光亮度等的脉冲宽度调制技术,HRPWM特别适用于需要极高精度和快速响应的应用,如高端电机控制、精密位置控制、高性能开关电源等。中科昊芯HXS320F28025C集成了HRPWM功能,这些集成模块提供了更多的功能、故障保护等。
HRPWM和普通PWM的主要区别在于分辨率、精度、响应时间,这决定了他们的应用场景不同,查阅F280参考手册可以看到官方给出的对比表格
一、理论计算:常用32单片机F1系列TIM8,TIM1挂在APB2上,理论最大频率72Mhz,1/72Mhz 周期时间≈14纳秒,生成100KHZ的PWM波,理论精度在0.3%,中央计数还要对半,可以说是很低了。跟日益增长的精细化控制要求渐行渐远了。目前电力电子/电机领域,高频化趋势明显。
根据手册宣传,当PWM分辨率低于9~10位时,通常需要使用HRPWM,ePWM外设设备用于执行数学上等同于数模转换器的功能DAC,HRPWM基于微边沿定位( MEP) 技术。 MEP逻辑能够通过细分传统PWM发生器的一个粗略系统时钟来非常精细地定位边沿。
二、配置HXS320F28025C的HRPWM
查阅手册,可以发现HRPWM是一个比较复杂的模块,各种陌生寄存器,不同配置模式整整塞了200页左右。根据认知负荷理论,我们先易后难,忽略斩波捕获,安全锁、滤波等配置,先把最简单的程序跑起来再说。
提取关于手册中关于HRTIM有用的片段:
HRPWM的MEP由六个扩展寄存器控制。 这些HRPWM寄存器与用于控制PWM操作的16位TBPH、 TBPRD、 CMPA、 CMPBM、 DBREDM和DBFEDM寄存器串联.
打开中科昊芯提供的例程库发现一个比较奇怪的问题,开发板型号确认为HX320F280025CEDC,官方例程库中有CEDB,CEDC,CEDD三种尾标,烧写CEDC中的LED闪烁程序一切正常,开发板对应的LED闪烁,烧写相同文件夹内ADC/EPWM/HRTIME等例程提示失败:
尝试烧写CEDB文件夹内程序,提示禁止烧写,CEDD内程序可以正常烧写但无法运行,真是比较奇怪的BUG,也许是我编译器的配置问题,或者是厂家在打包例程的时候弄错了?
没有办法,那就自己移植一下吧,也能加深对库的理解。
根据外设配置经验,三部走:
①IO口配置
void epwm_gpio(void)
{
/*配置GPIO0为EPWM1A*/
GPIO_setPinConfig(GPIO_0_EPWM1_A);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(0, GPIO_QUAL_SYNC);
/*配置GPIO1为EPWM1B*/
GPIO_setPinConfig(GPIO_1_EPWM1_B);
GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(1, GPIO_QUAL_SYNC);
/*配置GPIO2为EPWM2A*/
GPIO_setPinConfig(GPIO_2_EPWM2_A);
GPIO_setPadConfig(2, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(2, GPIO_QUAL_SYNC);
/*配置GPIO3为EPWM2B*/
GPIO_setPinConfig(GPIO_3_EPWM2_B);
GPIO_setPadConfig(3, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(3, GPIO_QUAL_SYNC);
/*配置GPIO4为EPWM3A*/
GPIO_setPinConfig(GPIO_4_EPWM3_A);
GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(4, GPIO_QUAL_SYNC);
/*配置GPIO5为EPWM3B*/
GPIO_setPinConfig(GPIO_5_EPWM3_B);
GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(5, GPIO_QUAL_SYNC);
/*配置GPIO6为EPWM4A*/
GPIO_setPinConfig(GPIO_6_EPWM4_A);
GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(4, GPIO_QUAL_SYNC);
/*配置GPIO7为EPWM4B*/
GPIO_setPinConfig(GPIO_7_EPWM4_B);
GPIO_setPadConfig(7, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(7, GPIO_QUAL_SYNC);
}
把IO0~IO7分别设置为EPWM1~4的AB双通道
②HRTIME配置
void hrpwm_config(uint32_t epwm_base,uint32_t epwm_tbprd,uint32_t epwm_cmpa,
uint32_t epwm_cmpb,uint32_t epwm_tbphs,
uint32_t ET_interruptSource,uint32_t ET_eventCount,
HRPWM_Channel channel,HRPWM_MEPEdgeMode mepEdgeMode_A)
{
/*HRPWM仿真模式:自由运行*/
HRPWM_setEmulationMode(epwm_base, EPWM_EMULATION_FREE_RUN);
/*EPWM1时基分频配置:低速时钟EPWM_CLOCK_DIVIDER_1-1分频,高速时钟EPWM_HSCLOCK_DIVIDER_1-1分频*/
HRPWM_setClockPrescaler(epwm_base, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
/*EPWM周期配置:SYSCLK/CLKDIV/HSPCLKDIV/TBPRD/2=160M/1/1/99/2=800kHz*/
EPWM_setTimeBasePeriod(epwm_base, epwm_tbprd);
/*HRPWM时基初值:TBCTR=0*/
HRPWM_setTimeBaseCounter(epwm_base, 0);
/*HRPWM时基计数模式:向上向下计数*/
HRPWM_setTimeBaseCounterMode(epwm_base, EPWM_COUNTER_MODE_UP_DOWN);
/*HRPWM相位禁止装载:TBPHSHRLOADE=0*/
HRPWM_disablePhaseShiftLoad(epwm_base);
/*高精度HRPWM相移:TBPHSHR=0*/
HRPWM_setPhaseShift(epwm_base, epwm_tbphs);
/*EPWM比较值CMPA配置:CMPA=50-占空比50%*/
EPWM_setCounterCompareValue(epwm_base, EPWM_COUNTER_COMPARE_A, epwm_cmpa);
/*EPWM比较值CMPA装载点配置:在EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD-TBCTR=0或TBPRD-零或周期值时装载*/
HRPWM_setCounterCompareShadowLoadMode(epwm_base, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD);
/*EPWM比较值CMPB配置:CMPB=50-占空比50%*/
EPWM_setCounterCompareValue(epwm_base, EPWM_COUNTER_COMPARE_B, epwm_cmpb);
/*EPWM比较值CMPB装载点配置:在EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD-TBCTR=0或TBPRD-零或周期值时装载*/
HRPWM_setCounterCompareShadowLoadMode(epwm_base, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO-TBCTR=零时
* EPWM_AQ_OUTPUT_NO_CHANGE-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD-TBCTR=周期值时
* EPWM_AQ_OUTPUT_NO_CHANGE-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA-向上计数时TBCTR=CMPA事件时
* EPWM_AQ_OUTPUT_HIGH,-输出置高动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA-向下计数时TBCTR=CMPA事件时
* EPWM_AQ_OUTPUT_LOW,-输出置低动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB-向上计数时TBCTR=CMPB事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB-向下计数时TBCTR=CMPB事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_A-EPWM1A
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO时计数TBCTR=ZERO-零事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_B-EPWM1B
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD时计数TBCTR=PERIOD-周期事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_B-EPWM1B
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA-向上计数TBCTR=CMPA事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_B-EPWM1B
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA-向下计数TBCTR=CMPA事件时
* EPWM_AQ_OUTPUT_NO_CHANGE,-不产生动作*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_B-EPWM1B
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB-向上计数TBCTR=CMPB事件时
* EPWM_AQ_OUTPUT_LOW,-置低*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
/*HRPWM动作配置:EPWM_AQ_OUTPUT_B-EPWM1B
* 在EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB-向下计数TBCTR=CMPB事件时
* EPWM_AQ_OUTPUT_HIGH,-置高*/
HRPWM_setActionQualifierAction(epwm_base, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
/*EPWM事件中断使能*/
EPWM_enableInterrupt(epwm_base);
/*EPWM事件中断选择:在CTR=0时触发中断*/
EPWM_setInterruptSource(epwm_base,ET_interruptSource);
/*EPWM事件中断次数选择:每次进中断触发一次,最多可支持15次*/
EPWM_setInterruptEventCount(epwm_base,ET_eventCount);
/*HRPWM使能自动转换:AUTOCONV=1*/
HRPWM_enableAutoConversion(epwm_base);
/*HRPWM MEP微边沿定位选择:HRPWM_CHANNEL_A-通道A
* HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE-双边沿定位*/
HRPWM_setMEPEdgeSelect(epwm_base, channel, mepEdgeMode_A);
/*HRPWM 计数比较装载:HRPWM_CHANNEL_A-通道A
* HRPWM_LOAD_ON_CNTR_ZERO_PERIOD-在CTR=零或周期值时装载影子模式*/
HRPWM_setCounterCompareShadowLoadEvent(epwm_base, channel, HRPWM_LOAD_ON_CNTR_ZERO_PERIOD);
/*HRPWM 使能周期控制:HRPE=1*/
HRPWM_enablePeriodControl(epwm_base);
}
/*HRPWM配置:TBPRD=99-频率800kHz,CMPA=50,CMPB=50-占空比50%
* 相位偏移:TBPHS=0,
* 事件中断:EPWM_INT_TBCTR_ZERO-在CTR=0时触发,1-每周期触发一次中断
* 通道选择:HRPWM_CHANNEL_A-通道A
* MEP微边沿定位:HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE-双边沿定位*/
hrpwm_config(EPWM1_BASE,99,50,50,0,
EPWM_INT_TBCTR_ZERO,1,
HRPWM_CHANNEL_A,HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
/*HRPWM配置:TBPRD=99-频率800kHz,CMPA=50,CMPB=50-占空比50%
* 相位偏移:TBPHS=0,
* 事件中断:EPWM_INT_TBCTR_PERIOD-在CTR=周期值时触发,1-每周期触发一次中断
* 通道选择:HRPWM_CHANNEL_A-通道A
* MEP微边沿定位:HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE-双边沿定位*/
hrpwm_config(EPWM2_BASE,99,50,50,0,
EPWM_INT_TBCTR_PERIOD,1,
HRPWM_CHANNEL_A,HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
/*HRPWM配置:TBPRD=99-频率800kHz,CMPA=50,CMPB=50-占空比50%
* 相位偏移:TBPHS=0,
* 事件中断:EPWM_INT_TBCTR_U_CMPA-向上计数时CTR=CMPA时触发,1-每周期触发一次中断
* 通道选择:HRPWM_CHANNEL_A-通道A
* MEP微边沿定位:HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE-双边沿定位*/
hrpwm_config(EPWM3_BASE,99,50,50,0,
EPWM_INT_TBCTR_U_CMPA,1,
HRPWM_CHANNEL_A,HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
/*HRPWM配置:TBPRD=99-频率800kHz,CMPA=50,CMPB=50-占空比50%
* 相位偏移:TBPHS=0,
* 事件中断:EPWM_INT_TBCTR_D_CMPA-向下计数时CTR=CMPA时触发,1-每周期触发一次中断
* 通道选择:HRPWM_CHANNEL_A-通道A
* MEP微边沿定位:HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE-双边沿定位*/
hrpwm_config(EPWM4_BASE,99,50,50,0,
EPWM_INT_TBCTR_D_CMPA,1,
HRPWM_CHANNEL_A,HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
以上是一些EPWM基本信息,给定800khz频率,50%占空比,中断触发事件,双边沿微定位,接下来是在中断函数中对占空比进行更新
/****对照组①*****/
__interrupt void epwm1ISR(void)
{
epwm1_ctr++;
for(periodFine = 0.2; periodFine < 0.9; periodFine += 0.01)
{
DEVICE_DELAY_US(1000);
float32_t count = ((EPWM_TIMER_TBPRD-1) << 8UL) + (float32_t)(periodFine * 256);
uint32_t compCount = count;
HRPWM_setTimeBasePeriod(EPWM1_BASE, compCount);
}
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}
/****对照组②*****/
__interrupt void epwm2ISR(void)
{
epwm2_ctr++;
EPWM_clearEventTriggerInterruptFlag(EPWM2_BASE);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}
EPWM1中断函数内每次循环从0.2自增到0.9,步进0.01,移植完可以正常烧录了。
在家里写的文章,家中只有普源最入门的DS1054Z,达不到高精度的要求,波形讲究着看吧。