[原创] 中科昊芯HXS320F28025C的高分辨率脉冲宽度调制器( HRPWM)

jixulifu2   2024-11-17 00:54 楼主

    HRPWM和普通PWM都是用于控制电机速度、电力信号、灯光亮度等的脉冲宽度调制技术,HRPWM特别适用于需要极高精度和快速响应的应用,如高端电机控制、精密位置控制、高性能开关电源等。中科昊芯HXS320F28025C集成了HRPWM功能,这些集成模块提供了更多的功能、故障保护等。
    HRPWM和普通PWM的主要区别在于分辨率、精度、响应时间,这决定了他们的应用场景不同,查阅F280参考手册可以看到官方给出的对比表格

1.png
 

一、理论计算:常用32单片机F1系列TIM8,TIM1挂在APB2上,理论最大频率72Mhz,1/72Mhz  周期时间≈14纳秒,生成100KHZ的PWM波,理论精度在0.3%,中央计数还要对半,可以说是很低了。跟日益增长的精细化控制要求渐行渐远了。目前电力电子/电机领域,高频化趋势明显。

根据手册宣传,当PWM分辨率低于9~10位时,通常需要使用HRPWM,ePWM外设设备用于执行数学上等同于数模转换器的功能DAC,HRPWM基于微边沿定位( MEP) 技术。 MEP逻辑能够通过细分传统PWM发生器的一个粗略系统时钟来非常精细地定位边沿。

 
2.png

二、配置HXS320F28025C的HRPWM

    查阅手册,可以发现HRPWM是一个比较复杂的模块,各种陌生寄存器,不同配置模式整整塞了200页左右。根据认知负荷理论,我们先易后难,忽略斩波捕获,安全锁、滤波等配置,先把最简单的程序跑起来再说。

    提取关于手册中关于HRTIM有用的片段:

3.png
HRTIME系统总框图
4.png
HRTIME源时钟框图
5.png
6.png

 

HRPWM的MEP由六个扩展寄存器控制。 这些HRPWM寄存器与用于控制PWM操作的16位TBPH、 TBPRD、 CMPA、 CMPBM、 DBREDM和DBFEDM寄存器串联.

打开中科昊芯提供的例程库发现一个比较奇怪的问题,开发板型号确认为HX320F280025CEDC,官方例程库中有CEDB,CEDC,CEDD三种尾标,烧写CEDC中的LED闪烁程序一切正常,开发板对应的LED闪烁,烧写相同文件夹内ADC/EPWM/HRTIME等例程提示失败: image.png  

尝试烧写CEDB文件夹内程序,提示禁止烧写,CEDD内程序可以正常烧写但无法运行,真是比较奇怪的BUG,也许是我编译器的配置问题,或者是厂家在打包例程的时候弄错了?

094c55ef9294d8c17497e3bb37e1104.jpg   image.png  

没有办法,那就自己移植一下吧,也能加深对库的理解。

根据外设配置经验,三部走:

①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,达不到高精度的要求,波形讲究着看吧。

3e33d72c509bb1ea8c6b3edf05eddc3.jpg  

WeChat_20241117005409

 

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复