目录
1.主函数执行流程
此程序的作用是实现eHRPWM(高精度脉冲宽度调制器)输出功能。OMAPL138/TMS320C6748共有两个eHRPWM模块,此处测试模块1的EPWM1_A引脚。主函数执行流程如下:
主函数如下:
int main(void)
{
// 外设使能配置
PSCInit();
// GPIO 管脚复用配置
GPIOBankPinMuxSet();
// DSP 中断初始化
InterruptInit();
// PWM 中断初始化
PWMInterruptInit();
// 产生波形
PWM1ABasic(10000,50);
// 斩波实验
// ChopperWaveform();
// 主循环
for(;;)
{
}
}
2.外设使能配置
函数首先使能外设,这里是eHRPWM模块1,外设使能配置函数PSCInit如下:
void PSCInit(void)
{
// 使能 EHRPWM 模块
// 对相应外设模块的使能也可以在 BootLoader 中完成
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_EHRPWM, PSC_POWERDOMAIN_ALWAYS_ON,
PSC_MDCTL_NEXT_ENABLE);
}
函数在PSC中使能HW_PSC_EHRPWM(#17)模块,该模块的Power Domain是ALWAYS_ON域(POWER DOMAIN 0),PSCModuleControl细节可参考这里:
3.GPIO管脚复用配置
将EHRPWM1模块所在的引脚的功能(function)配置为EHRPWM1功能,GPIO管脚复用配置函数GPIOBankPinMuxSet如下:
void GPIOBankPinMuxSet(void)
{
EHRPWM1PinMuxSetup();
}
EHRPWM1PinMuxSetup函数在demo的Platform工程下的EHRPWM.c文件中,函数如下:
void EHRPWM1PinMuxSetup(void)
{
// EPWM1A
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(5)) =
(HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(5)) & (~ (SYSCFG_PINMUX5_PINMUX5_3_0))) |
(PINMUX5_EPWM1A_ENABLE);
// EPWM1B
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(5)) =
(HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(5)) & (~(SYSCFG_PINMUX5_PINMUX5_7_4))) |
(PINMUX5_EPWM1B_ENABLE);
// EPWM1TZ[0]
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(2)) =
(HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(2)) & (~(SYSCFG_PINMUX2_PINMUX2_3_0))) |
(PINMUX2_EPWM1TZ0_ENABLE);
// EPWMSYNCO
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(3)) =
(HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(3)) & (~(SYSCFG_PINMUX3_PINMUX3_15_12))) |
(PINMUX3_EPWMSYNCO_ENABLE);
// EPWMSYNCI
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(3)) =
(HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_PINMUX(3)) & (~(SYSCFG_PINMUX3_PINMUX3_11_8))) |
(PINMUX3_EPWMSYNCI_ENABLE);
// 使能 PWM 时钟
HWREG(SOC_SYSCFG_0_REGS + SYSCFG0_CFGCHIP1) |= SYSCFG_CFGCHIP1_TBCLKSYNC;
}
函数将EPWM1模块的相关引脚配置为EPWM1A、EPWM1B、EPWM1TZ[0]、EPWMSYNCO、EPWMSYNCI功能引脚,然后设置CFGCHIP1(Chip Configuration 1 Register)寄存器的TBCLKSYNC位,将所有被使能的eHRPWM模块同步到时基时钟(time base clock,TBCLK),使能PWM时钟。
(指南P228)
(指南P222)
(指南P224)
(CFGCHIP1,指南P266)
4.DSP中断初始化
DSP中断初始化函数InterruptInit如下:
void InterruptInit(void)
{
// 初始化 DSP 中断控制器
IntDSPINTCInit();
// 使能 DSP 全局中断
IntGlobalEnable();
}
函数细节参考这里
5.PWM中断初始化
PWM中断初始化函数PWMInterruptInit如下:
void PWMInterruptInit(void)
{
// 注册中断服务函数
IntRegister(C674X_MASK_INT4, PWMEventIsr);
IntRegister(C674X_MASK_INT5, PWMTZIsr);
// 映射中断到 DSP 可屏蔽中断
IntEventMap(C674X_MASK_INT4, SYS_INT_EHRPWM1);
IntEventMap(C674X_MASK_INT5, SYS_INT_EHRPWM1TZ);
// 使能 DSP 可屏蔽中断
IntEnable(C674X_MASK_INT4);
IntEnable(C674X_MASK_INT5);
}
函数将CPU可屏蔽中断C674X_MASK_INT4和C674X_MASK_INT5的中断服务函数注册为PWMEventIsr和PWMTZIsr。然后将中断事件SYS_INT_EHRPWM1(#18,PWM1中断)和SYS_INT_EHRPWM1TZ(#23,PWM1错误处理中断)分别映射到CPU中断INT4和INT5,最后使能INT4和INT5。关于IntRegister、IntEventMap、IntEnable等函数可参考这里。
(手册P93)
6.产生波形
产生波形函数PWM1ABasic (10000,50)如下,其中第一个参数10000表示产生的PWM波的频率为10000Hz(10KHz),第二个参数50表示波形占空比为50%。
void PWM1ABasic(unsigned int pwm_clk,unsigned short duty_ratio)
{
// 时间基准配置
// 时钟配置
EHRPWMTimebaseClkConfig(SOC_EHRPWM_1_REGS, SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL ,
SOC_EHRPWM_1_MODULE_FREQ);
// 配置周期
EHRPWMPWMOpFreqSet(SOC_EHRPWM_1_REGS, SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL,
pwm_clk, EHRPWM_COUNT_UP, EHRPWM_SHADOW_WRITE_DISABLE);
// 禁用输入同步信号
EHRPWMTimebaseSyncDisable(SOC_EHRPWM_1_REGS);
// 禁用输出同步信号
EHRPWMSyncOutModeSet(SOC_EHRPWM_1_REGS, EHRPWM_SYNCOUT_DISABLE);
// 仿真(DEBUG)模式行为配置
EHRPWMTBEmulationModeSet(SOC_EHRPWM_1_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
// 配置计数比较器子模块
// 加载比较器 A 值
EHRPWMLoadCMPA(SOC_EHRPWM_1_REGS,
(SOC_EHRPWM_1_MODULE_FREQ/CLOCK_DIV_VAL/pwm_clk)*duty_ratio/100,
EHRPWM_SHADOW_WRITE_DISABLE,
EHRPWM_COMPA_NO_LOAD, EHRPWM_CMPCTL_OVERWR_SH_FL);
// 加载比较器 B 值
EHRPWMLoadCMPB(SOC_EHRPWM_1_REGS, 0, EHRPWM_SHADOW_WRITE_DISABLE,
EHRPWM_COMPB_NO_LOAD, EHRPWM_CMPCTL_OVERWR_SH_FL);
// 功能限定配置(输出引脚触发方式设定)
// 时间基准计数等于有效计数比较寄存器 A/B 值时EPWM1_A翻转,波形由EPWM1_A输出
EHRPWMConfigureAQActionOnA(SOC_EHRPWM_1_REGS, EHRPWM_AQCTLA_ZRO_DONOTHING,
EHRPWM_AQCTLA_PRD_DONOTHING,
EHRPWM_AQCTLA_CAU_EPWMXATOGGLE, EHRPWM_AQCTLA_CAD_DONOTHING,
EHRPWM_AQCTLA_CBU_EPWMXATOGGLE,
EHRPWM_AQCTLA_CBD_DONOTHING, EHRPWM_AQSFRC_ACTSFA_DONOTHING);
// 禁用(旁路,信号直接输出到斩波子模块)死区模块
EHRPWMDBOutput(SOC_EHRPWM_1_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
// 禁用斩波子模块
EHRPWMChopperDisable(SOC_EHRPWM_1_REGS);
// 禁用错误控制事件
EHRPWMTZTripEventDisable(SOC_EHRPWM_1_REGS, EHRPWM_TZ_ONESHOT);
EHRPWMTZTripEventDisable(SOC_EHRPWM_1_REGS, EHRPWM_TZ_CYCLEBYCYCLE);
// 事件触发配置
// 每三次事件发生产生中断
EHRPWMETIntPrescale(SOC_EHRPWM_1_REGS, EHRPWM_ETPS_INTPRD_THIRDEVENT);
// 时间基准计数等于有效计数比较寄存器 B 值 产生事件
EHRPWMETIntSourceSelect(SOC_EHRPWM_1_REGS, EHRPWM_ETSEL_INTSEL_TBCTREQUCMPBINC);
// 使能中断
EHRPWMETIntEnable(SOC_EHRPWM_1_REGS);
// 禁用高精度子模块
EHRPWMHRDisable(SOC_EHRPWM_1_REGS);
}
6.1 时间基准配置/时钟配置
要输出PWM波,首先要配置时间基准,EHRPWMTimebaseClkConfig函数在Drivers工程下的ehrpwm.c文件中,API如下:
void EHRPWMTimebaseClkConfig(unsigned int baseAddr,
unsigned int tbClk,
unsigned int moduleClk)
{
unsigned int clkDiv = moduleClk/tbClk;
unsigned int hspClkDiv;
unsigned int lspClkDiv, lspClkDivSetting = 0;
if(clkDiv > EHRPWM_TBCTL_HSPCLKDIV_14)
{
hspClkDiv = EHRPWM_TBCTL_HSPCLKDIV_DIVBY14; /* reg setting */
lspClkDiv = clkDiv/EHRPWM_TBCTL_HSPCLKDIV_14; /* divider */
/* reg setting */
while(lspClkDiv > 1)
{
lspClkDiv = lspClkDiv >> 1;
lspClkDivSetting++;
}
}
else
{
hspClkDiv = clkDiv/2; /* reg setting */
/* divide by 1 */
lspClkDivSetting = EHRPWM_TBCTL_HSPCLKDIV_DIVBY1;
}
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_TBCTL_CLKDIV)) | ((lspClkDivSetting <<
EHRPWM_TBCTL_CLKDIV_SHIFT) & EHRPWM_TBCTL_CLKDIV);
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_TBCTL_HSPCLKDIV)) | ((hspClkDiv <<
EHRPWM_TBCTL_HSPCLKDIV_SHIFT) & EHRPWM_TBCTL_HSPCLKDIV);
}
该函数配置时基模块(Time base module)的时钟分频器(clock divider),baseAddr是PWM模块寄存器组的基地址,tbClk为要产生的时基时钟,moduleClk是输入到PWM模块的时钟(sysclk2)。时基时钟TBCLK(Time-base Clock)计算公式为:TBCLK = SYSCLKOUT/(HSPCLKDIV × CLKDIV)。HSPCLKDIV和CLKDIV是TBCTL寄存器的位,则时钟分频值clkdiv=SYSCLKOUT/TBCLK=HSPCLKDIV x CLKDIV。
函数先计算时钟分频值clkdiv,如果CLKDIV大于HSPCLKDIV所能设置的最大分频值14(HSPCLKDIV=7h)时,则还需要计算TBCTL的CLKDIV部分。否则,HSPCLKDIV分频值就是clkdiv,CLKDIV分频值为1。这里设置tbclk为1MHz,eHRPWM1模块的输入时钟为228MHz(sysclk/2)。
(指南P465)
(指南P131)
6.2 配置周期
配置周期函数EHRPWMPWMOpFreqSet如下:
void EHRPWMPWMOpFreqSet(unsigned int baseAddr,
unsigned int tbClk,
unsigned int pwmFreq,
unsigned int counterDir,
bool enableShadowWrite)
{
unsigned int tbPeriodCount = tbClk/pwmFreq;
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_PRD_LOAD_SHADOW_MASK)) | ((enableShadowWrite <<
EHRPWM_TBCTL_PRDLD_SHIFT) & EHRPWM_PRD_LOAD_SHADOW_MASK);
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_COUNTER_MODE_MASK)) | ((counterDir <<
EHRPWM_TBCTL_CTRMODE_SHIFT) & EHRPWM_COUNTER_MODE_MASK);
if(EHRPWM_COUNT_UP_DOWN == counterDir)
{
HWREGH(baseAddr + EHRPWM_TBPRD) = (unsigned short)tbPeriodCount/2;
}
else
{
HWREGH(baseAddr + EHRPWM_TBPRD) = (unsigned short)tbPeriodCount;
}
}
该函数配置输出的PWM频率/周期。周期计数器决定了最后输出波形的周期。对给定的周期值,在UP 和 DOWN模式下,所装载的周期值就是给定的周期值,在UP_DOWN模式下,所装载的周期值是给定的周期值的一半。pwmFreq是PWM输出波形的频率,如果计数器的方向是up-down,该值必须为输出频率的一半,这样最终输出的信号频率才能等于输出频率。CounterDir是计数器的计数方向(up,down,up-down),enableShadowWrite指明是否使能写往周期寄存器的影子寄存器。
(指南P338)
函数先是计算周期计数值tbPeriodCount,然后设置TBCTL的PRDLD位确定周期寄存器TBPRD的值是否从Shadow寄存器中加载;设置TBCTL的CTRMODE位,确定计数器模式,是向上计数还是向下计数还是上下计数。最后根据计数方向,确定存入周期寄存器TBPRD的值tbPeriodCount是否要减半(这里设置up和down计数模式的tbPeriodCount好像少减了1?)。这里程序设置TBCTL[CTRMODE]位为0h,即time-base计数器计数模式为Up-count mode。设置TBCTL[PRDLD]位为1,即直接加载TBPRD而不使用影子寄存器。设置TBPRD为100(1MHz/10KHz=tbclkFREQ/pwmclkFREQ),即PWM波频率为10KHz。
(指南P388)
6.3 禁用输入同步信号
EHRPWMTimebaseSyncDisable函数设置TBCTL的PHSEN位(counter Register Load From Phase Register Enable)为0,禁用EHRPWM1的输入同步信号,即使EPWM1SYNCI引脚有同步信号输入,EPWM1也不会把相位寄存器TBPHS(TB phase register)的值装入到计数器TBCNT(time-base counter)中。
(指南P389)
(指南P390)
(指南P466)
该API如下:
void EHRPWMTimebaseSyncDisable(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_TBCTL) &= (~EHRPWM_SYNC_ENABLE);
}
6.4 禁用输出同步信号
EHRPWMSyncOutModeSet函数设置TBCTL的SYNCOSEL位为3h,禁用EPWM1的输出同步信号EPWM1SYNCO,输出同步信号产生的条件可以是EPWM1SYNCIN、CTR=0、CTR=CMPB三个。
(指南P386)
(指南P387)
(指南P465)
该API如下:
void EHRPWMSyncOutModeSet(unsigned int baseAddr, unsigned int syncOutMode)
{
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_SYNCOUT_MASK)) | syncOutMode;
}
6.5 仿真模式行为配置
EHRPWMTBEmulationModeSet函数设置TBCTL的FREE、SOFT位,配置EPWM的仿真模式行为(即在调试时timebase的行为),这里将FREE、SOFT位设为0,则在仿真事件(emulation event)发生后,ePWM的时基计数器(time-base counter)将在下一次增量(increment)或减量(decrement)发生后停止。
(指南P465)
该API如下:
void EHRPWMTBEmulationModeSet(unsigned int baseAddr, unsigned int mode)
{
HWREGH(baseAddr + EHRPWM_TBCTL) = (HWREGH(baseAddr + EHRPWM_TBCTL) &
(~EHRPWM_TBCTL_FREE_SOFT)) | (mode & EHRPWM_TBCTL_FREE_SOFT);
}
6.6 配置计数比较器子模块
6.6.1 加载比较器A值
计数器比较子模块(counter-compare submodule)接收时基计数器(time-base counter)的值作为输入,这个值不断地同比较计数器(counter-compare)A和比较计数器B寄存器相比较。当时基计数器的值等于其中一个比较寄存器时,这个计数器比较单元就会产生相应的事件,将事件信号输出到AQ模块中(Action Qualifier)。
(指南P394)
加载比较器A值函数EHRPWMLoadCMPA如下:
bool EHRPWMLoadCMPA(unsigned int baseAddr,
unsigned int CMPAVal,
bool enableShadowWrite,
unsigned int ShadowToActiveLoadTrigger,
bool OverwriteShadowFull)
{
bool status = FALSE;
if((OverwriteShadowFull) ||
((HWREGH(baseAddr+EHRPWM_CMPCTL) & EHRPWM_CMPCTL_SHDWAFULL) ==
EHRPWM_SHADOW_A_EMPTY))
{
HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
(~EHRPWM_CMPCTL_SHDWAMODE)) | ((enableShadowWrite <<
EHRPWM_CMPCTL_SHDWAMODE_SHIFT) & EHRPWM_CMPCTL_SHDWAMODE);
HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
(~EHRPWM_COMPA_LOAD_MASK)) |((ShadowToActiveLoadTrigger <<
EHRPWM_CMPCTL_LOADAMODE_SHIFT) & EHRPWM_COMPA_LOAD_MASK);
HWREGH(baseAddr + EHRPWM_CMPA) = CMPAVal & EHRPWM_CMPA_CMPA;
status = TRUE;
}
return status;
}
函数先判断OverwriteShadowFull标志是否为1(真),如果为真,则不管Counter-compare A(CMPA)影子寄存器(shadow register)是否为满(SHDWAFULL=1),都往里overwrite,又或者CMPA影子寄存器为空(SHDWAFULL),也往CMPA Shadow register所在地址写数据。
(指南P469)
CMPA shadow register与CMPA active register共享同一地址,往该地址写数据时,到底往哪一个寄存器写是通过CMPCTL寄存器的SHDWAMODE位(CMPA寄存器操作模式)来决定的。这里程序把该位设为了1,即选择immediate模式,往该地址写数据直接往active register写。然后程序又设置CMPCTL的LOADAMODE位(active counter-compare A load from shadow select mode)为3h,则freeze加载行为,CMPA的active register将不从shadow register加载。
(指南P469)
最后将要写往CMPA active register的值CMPAVal写入到CMPA active register中。这里
(指南P470)
6.6.2 加载比较器B值
加载比较器B值函数EHRPWMLoadCMPB如下:
bool EHRPWMLoadCMPB(unsigned int baseAddr,
unsigned int CMPBVal,
bool enableShadowWrite,
unsigned int ShadowToActiveLoadTrigger,
bool OverwriteShadowFull)
{
bool status = FALSE;
if((OverwriteShadowFull) ||
((HWREGH(baseAddr+EHRPWM_CMPCTL) & EHRPWM_CMPCTL_SHDWBFULL) ==
EHRPWM_SHADOW_B_EMPTY))
{
HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL)
& (~EHRPWM_CMPCTL_SHDWBMODE)) | ((enableShadowWrite <<
EHRPWM_CMPCTL_SHDWBMODE_SHIFT) & EHRPWM_CMPCTL_SHDWBMODE);
HWREGH(baseAddr + EHRPWM_CMPCTL) = (HWREGH(baseAddr + EHRPWM_CMPCTL) &
(~EHRPWM_COMPB_LOAD_MASK)) | ((ShadowToActiveLoadTrigger <<
EHRPWM_CMPCTL_LOADBMODE_SHIFT) & EHRPWM_COMPB_LOAD_MASK);
HWREGH(baseAddr + EHRPWM_CMPB) = CMPBVal & EHRPWM_CMPB_CMPB;
status = TRUE;
}
return status;
}
函数与加载比较器A值函数基本一致,不同的只是判断的条件变成了CMPB shadow register是否满。设置的位变成了CMPCTL的SHDWBMODE和LOADBMODE位,比较器数据写往了CMPB。这里不再细述。
6.7 功能限定配置(输出引脚触发方式设定)
函数EHRPWMConfigureAQActionOnA设定输出引脚触发方式,这里设置时间基准计数等于有效计数比较寄存器A/B值时EPWM1_A翻转,波形由EPWM1_A输出。该API如下:
void EHRPWMConfigureAQActionOnA(unsigned int baseAddr,
unsigned int zero,
unsigned int period,
unsigned int CAUp,
unsigned int CADown,
unsigned int CBUp,
unsigned int CBDown,
unsigned int SWForced)
{
HWREGH(baseAddr + EHRPWM_AQCTLA) =
((CBDown << EHRPWM_AQCTLA_CBD_SHIFT) & EHRPWM_AQCTLA_CBD) |
((CBUp << EHRPWM_AQCTLA_CBU_SHIFT) & EHRPWM_AQCTLA_CBU) |
((CADown << EHRPWM_AQCTLA_CAD_SHIFT) & EHRPWM_AQCTLA_CAD) |
((CAUp << EHRPWM_AQCTLA_CAU_SHIFT) & EHRPWM_AQCTLA_CAU) |
((period << EHRPWM_AQCTLA_PRD_SHIFT) & EHRPWM_AQCTLA_PRD) |
((zero << EHRPWM_AQCTLA_ZRO_SHIFT) & EHRPWM_AQCTLA_ZRO);
HWREGH(baseAddr + EHRPWM_AQSFRC) = (HWREGH(baseAddr + EHRPWM_AQSFRC) &
(~EHRPWM_AQSFRC_ACTSFA)) | ((SWForced <<
EHRPWM_AQSFRC_ACTSFA_SHIFT) & EHRPWM_AQSFRC_ACTSFA);
}
该函数设置AQCTLA寄存器的CBD、CBU、CAD、CAU、PRD、ZRO位,配置EPWM模块的A通道在相应事件发生时的动作。然后设置AQSFRC寄存器的ACTSFA位,配置EPWM1_A在One-time Force A被invoke时的动作(action)。
(指南P472)
(指南P474)
这里程序设置在TBCNT向上计数等于CMPA和CMPB时EPWM1_A输出翻转,其它时候不动作。
6.8 禁用死区模块
EHRPWMDBOutput函数选择死区模块的输出模式,这里禁用死区模块,由AQ模块(action qualifier)输出的信号在通过死区模块(dead band)时,被旁路,不做任何处理,信号被直接输出到斩波(PC,PWM chopper)子模块,注意图中DB的虚线,虚线表示旁路处理。
(指南P417)
通过设置DBCTL[OUT_MODE]位可以控制信号是否旁路,如图:
(指南P418)
该API如下:
void EHRPWMDBOutput(unsigned int baseAddr, unsigned int DBgenOpMode)
{
HWREGH(baseAddr + EHRPWM_DBCTL) =
(HWREGH(baseAddr + EHRPWM_DBCTL) & (~EHRPWM_DBCTL_OUT_MODE)) |
((DBgenOpMode << EHRPWM_DBCTL_OUT_MODE_SHIFT) & EHRPWM_DBCTL_OUT_MODE);
}
函数通过设置DBCTL[OUT_MODE]位可以设置4种不同的输出模式,分别确定A通道和B通道信号是否要旁路。
(指南P476)
6.9 禁用斩波子模块
EHRPWMChopperDisable函数设置PCCTL的CHPEN位为0,禁用PWM斩波子模块的PWM斩波功能,信号经过斩波子模块时,直接被bypass,不作任何处理。该API如下:
void EHRPWMChopperDisable(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_PCCTL) &= (~EHRPWM_PCCTL_CHPEN);
}
(指南P422)
(指南P478)
6.10 禁用错误控制事件
EHRPWMTZTripEventDisable函数禁用错误控制事件(trip event),当TZ引脚输入了错误信号时,错误处理模块(Trip Zone)将不会作任何处理。这里,程序设置TZSEL[OSHT1]位和TZSEL[CBC1]位为0,禁用了EPWM1模块的Trip Zone子模块产生CBC事件(Cycle-by-Cycle)和OSHT事件(One-Shot)。该API如下:
void EHRPWMTZTripEventDisable(unsigned int baseAddr, bool osht_CBC)
{
if(EHRPWM_TZ_ONESHOT == osht_CBC)
{
HWREGH(baseAddr + EHRPWM_TZSEL) &= (~EHRPWM_TZSEL_OSHT1);
}
if(EHRPWM_TZ_CYCLEBYCYCLE == osht_CBC)
{
HWREGH(baseAddr + EHRPWM_TZSEL) &= (~EHRPWM_TZSEL_CBC1);
}
}
(指南P428)
(指南P479)
6.11 事件触发配置
6.11.1 每三次事件发生产生中断
EHRPWMETIntPrescale函数设置事件触发(event trigger,ET)子模块的ETPS寄存器(event prescale),设置ETPS[INTPRD]位对要产生中断的事件进行预分频处理(即发生多少次事件才产生一次中断),这里程序设置为3次,即每3次事件发生,产生1次中断。ET子模块接收由时基子模块(time-base)和计数器比较子模块(counter-compare)所产生的事件信号输入,并产生中断信号给CPU。要产生中断的事件由ETSEL[INTSEL]位选择。EHRPWMETIntPrescale函数如下:
void EHRPWMETIntPrescale(unsigned int baseAddr, unsigned int prescale)
{
HWREGH(baseAddr + EHRPWM_ETPS) =
(HWREGH(baseAddr + EHRPWM_ETPS) & (~EHRPWM_ETPS_INTPRD)) |
((prescale << EHRPWM_ETPS_INTPRD_SHIFT) & EHRPWM_ETPS_INTPRD);
}
(指南P484)
6.11.2 时间基准等于有效计数比较寄存器B值产生事件
EHRPWMETIntSourceSelect函数设置产生EPWM中断的源(source),函数设置ETSEL[INTSEL]位,确定什么事件发生时,ETPS[INTCNT]会加1。这里程序设置源为CTRU=CMPB,即TBCTR向上计数到等于CMPB时产生一次事件。该API如下:
void EHRPWMETIntSourceSelect(unsigned int baseAddr, unsigned int selectInt)
{
HWREGH(baseAddr + EHRPWM_ETSEL) =
(HWREGH(baseAddr + EHRPWM_ETSEL) & (~EHRPWM_ETSEL_INTSEL)) |
((selectInt << EHRPWM_ETSEL_INTSEL_SHIFT) & EHRPWM_ETSEL_INTSEL);
}
(指南P432)
(指南P483)
6.12 使能中断
EHRPWMETIntEnable函数设置ETSEL[INTEN]位为1,使能EPWMx_INT中断信号的产生。该API如下:
void EHRPWMETIntEnable(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_ETSEL) |= EHRPWM_ETSEL_INTEN;
}
6.13 禁用高精度子模块
EHRPWMHRDisable函数设置HRCNFG寄存器(HRPWM configuration register)的EDGEMODE位,禁用HRPWM功能。该API如下:
void EHRPWMHRDisable(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_HRCNFG) &= (~EHRPWM_HR_EDGEMODE);
}
(指南P488)
7.斩波(可选)
斩波函数如下:
void ChopperWaveform(void)
{
// 50% 占空比
EHRPWMConfigureChopperDuty(SOC_EHRPWM_1_REGS, EHRPWM_CHP_DUTY_50_PER);
// 4 分频
EHRPWMConfigureChopperFreq(SOC_EHRPWM_1_REGS, EHRPWM_PCCTL_CHPFREQ_DIVBY4);
// 单个脉冲宽度
EHRPWMConfigureChopperOSPW(SOC_EHRPWM_1_REGS, 0xF);
// 使能斩波子模块
EHRPWMChopperEnable(SOC_EHRPWM_1_REGS);
}
7.1 设置斩波占空比
EHRPWMConfigureChopperDuty函数设置PCCTL[CHPDUTY]位,设置斩波PSCLK的占空比,这里设为3h,即50%,该API如下:
void EHRPWMConfigureChopperDuty(unsigned int baseAddr, unsigned int dutyCycle)
{
HWREGH(baseAddr + EHRPWM_PCCTL) =
(HWREGH(baseAddr + EHRPWM_PCCTL) & (~EHRPWM_PCCTL_CHPDUTY)) |
((dutyCycle << EHRPWM_PCCTL_CHPDUTY_SHIFT) & EHRPWM_PCCTL_CHPDUTY);
}
(指南P424)
7.2 设置斩波频率
EHRPWMConfigureChopperFreq函数设置PCCTL[CHPFREQ],通过设置分频细述,设置斩波频率,斩波频率是从SYSCLKOUT(即CPU时钟频率)分频得来的。该API如下:
void EHRPWMConfigureChopperFreq(unsigned int baseAddr, unsigned int freqDiv)
{
if(freqDiv > EHRPWM_PCCTL_CHPFREQ_DIVBY8)
{
freqDiv = EHRPWM_PCCTL_CHPFREQ_DIVBY8;
}
HWREGH(baseAddr + EHRPWM_PCCTL) =
(HWREGH(baseAddr + EHRPWM_PCCTL) & (~EHRPWM_PCCTL_CHPFREQ)) |
((freqDiv << EHRPWM_PCCTL_CHPFREQ_SHIFT) & EHRPWM_PCCTL_CHPFREQ);
}
(指南P422)
(指南P478)
7.3 设置单个脉冲宽度
EHRPWMConfigureChopperOSPW函数设置PCCTL[OSHTWTH]位,设置one-shot pulse width,这里设为0x0F,即one-shot脉冲宽度为16 x SYSCLKOUT/8。
(指南P423)
(指南P478)
7.4 使能斩波子模块
EHRPWMChopperEnable函数设置PCCTL[CHPEN]位为1,使能斩波子模块,该API如下:
void EHRPWMChopperEnable(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_PCCTL) |= EHRPWM_PCCTL_CHPEN;
}
(指南P478)
8.中断服务函数
8.1 PWM事件中断服务函数
PWM事件中断服务函数PWMEventIsr如下:
void PWMEventIsr(void)
{
IntEventClear(SYS_INT_EHRPWM1);
EHRPWMETIntClear(SOC_EHRPWM_1_REGS);
}
函数先是清除EVTFLAGn被置位的中断标志(SYS_INT_EHRPWM1位),IntEventClear函数在\demo\StarterWare\Source\StarterWare\SystemConfig 路径system_config工程下的interrupt.c文件中,函数如下:
void IntEventClear(unsigned int sysINT)
{
unsigned int dspintcREG;
/* Check the system event number */
ASSERT((sysINT <= 127));
/* Get the address of the correct event register */
dspintcREG = SOC_INTC_0_REGS + DSPINTC_EVTCLR((sysINT >> 5));
/* Clear the corresponding bit within the event clear register */
HWREG(dspintcREG) = DSPINTC_EVTCLR_EC(sysINT);
}
细节可参考这篇博文。
然后EHRPWMETIntClear函数往ETCLR寄存器的INT位写1,清除ETFLG[INT]位,清除ePWM中断标志。该API如下:
void EHRPWMETIntClear(unsigned int baseAddr)
{
HWREGH(baseAddr + EHRPWM_ETCLR) |= EHRPWM_ETCLR_INT;
}
(指南P485)
指南P485)
8.2 PWM错误事件中断服务函数
PWM错误事件中断服务函数PWMTZIsr如下:
void PWMTZIsr(void)
{
IntEventClear(SYS_INT_EHRPWM1TZ);
EHRPWMTZFlagClear(SOC_EHRPWM_1_REGS, EHRPWM_TZ_CYCLEBYCYCLE_CLEAR);
}
首先在EVTFLAGn寄存器中清除SYS_INT_EHRPWM1TZ(#23)对应的中断标志位,然后EHRPWMTZFlagClear函数设置TZCLR的相应位,清除相应错误标志,这里设置TZCLR[CBC]和TZCLR[INT]位,清除CBC trip latch标志和ePWM模块trip-interrupt中断标志TZFLG[INT]。EHRPWMTZFlagClear函数如下:
void EHRPWMTZFlagClear(unsigned int baseAddr, unsigned int flagToClear)
{
HWREGH(baseAddr + EHRPWM_TZCLR) = flagToClear &
(EHRPWM_TZCLR_OST | EHRPWM_TZCLR_CBC | EHRPWM_TZCLR_INT);
}
(指南P482)
(指南P428)