Looking for suggestions on changing the PWM consistently and glitchlessly.
I need to implement a dimmable LCD backlight on our design. Using a simple configuration of the eHRPWM I'm able to initialize and run the PWM to control the backlight. However, I'm not able to change the PWM's duty cycle in a consistent manner.
On start up the PWM is configured to generate a waveform with a 50% duty cycle. The action qualifier is configured to toggle the PWM signal when the period counter (PRD) equals counter compare A (CMPA) or counter compare B (CMPB). To change the duty cycle I make only change; write a new value to the counter compare A register. Here's a simple diagram that shows how I expect this to work.
____________1
|
|_______________2 and 3
1 - CMPA -- when period counter = CMPA toggle (expect signal to go high)
2 - CMPB -- when period counter = CMPB toggle (expect signal to go low)
3 - PRD count
I see two issues when changing the duty cycle
- changing CMPA does not always change the duty cycle as expected. Most times increasing CMPA increases the on time (expected behaviour) but occasionally this will reduce the on time.
- changing the duty cycle is glitchy. For a short period of time the PWM output produces a signal at a constant level, before the updated PWM waveform appears. This constant level is visibly noticeable on the LCD.
void pwm_change_duty_cycle(uint32_t on_time)
{
uint32_t on_period;
bool ret = 0;
on_period = (pwm_period_counter * on_time)/100;
/* Load Compare A value */
//ret = EHRPWMLoadCMPA(SOC_EHRPWM_0_REGS, on_period, EHRPWM_SHADOW_WRITE_DISABLE,
// EHRPWM_COMPA_NO_LOAD, EHRPWM_CMPCTL_OVERWR_SH_FL);
ret = EHRPWMLoadCMPA(SOC_EHRPWM_0_REGS, on_period, EHRPWM_SHADOW_WRITE_ENABLE,
EHRPWM_COMPA_LOAD_COUNT_EQUAL_PERIOD, EHRPWM_CMPCTL_OVERWR_SH_FL);
}
uint32_t clock_div_val = 0x700;
uint32_t pwm_period_counter = 1820;
void pwm_start(uint32_t pwm_module_freq)
{
/* TimeBase configuration */
/* Configure the clock frequency */
EHRPWMTimebaseClkConfig(SOC_EHRPWM_0_REGS, pwm_module_freq/clock_div_val, pwm_module_freq);
/* Configure the period of the output waveform */
EHRPWMPWMOpFreqSet(SOC_EHRPWM_0_REGS, pwm_module_freq/clock_div_val,
(pwm_module_freq/clock_div_val)/pwm_period_counter, EHRPWM_COUNT_UP, EHRPWM_SHADOW_WRITE_DISABLE);
/* Disable synchronization*/
EHRPWMTimebaseSyncDisable(SOC_EHRPWM_0_REGS);
/* Disable syncout*/
EHRPWMSyncOutModeSet(SOC_EHRPWM_0_REGS, EHRPWM_SYNCOUT_DISABLE);
/* Configure the emulation behaviour*/
EHRPWMTBEmulationModeSet(SOC_EHRPWM_0_REGS, EHRPWM_STOP_AFTER_NEXT_TB_INCREMENT);
/* Configure Counter compare sub-module */
/* Load Compare A value */
EHRPWMLoadCMPA(SOC_EHRPWM_0_REGS, (pwm_period_counter/2), EHRPWM_SHADOW_WRITE_DISABLE,
EHRPWM_COMPA_NO_LOAD, EHRPWM_CMPCTL_OVERWR_SH_FL);
/* Load Compare B value */
EHRPWMLoadCMPB(SOC_EHRPWM_0_REGS, pwm_period_counter, EHRPWM_SHADOW_WRITE_DISABLE,
EHRPWM_COMPB_NO_LOAD, EHRPWM_CMPCTL_OVERWR_SH_FL);
/* Configure Action qualifier */
/* Toggle when CTR = CMPA OR CMPB */
EHRPWMConfigureAQActionOnA(SOC_EHRPWM_0_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);
/* Bypass dead band sub-module */
EHRPWMDBOutput(SOC_EHRPWM_0_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
/* Disable Chopper sub-module */
EHRPWMChopperDisable(SOC_EHRPWM_0_REGS);
/* Disable trip events */
EHRPWMTZTripEventDisable(SOC_EHRPWM_0_REGS, EHRPWM_TZ_ONESHOT);
EHRPWMTZTripEventDisable(SOC_EHRPWM_0_REGS, EHRPWM_TZ_CYCLEBYCYCLE);
/* Event trigger */
/* Generate interrupt every 3rd occurance of the event */
EHRPWMETIntPrescale(SOC_EHRPWM_0_REGS, EHRPWM_ETPS_INTPRD_THIRDEVENT);
/* Generate event when CTR = CMPB */
EHRPWMETIntSourceSelect(SOC_EHRPWM_0_REGS, EHRPWM_ETSEL_INTSEL_TBCTREQUCMPBINC);
/* Enable interrupt */
EHRPWMETIntEnable(SOC_EHRPWM_0_REGS);
/* Disable High resolution capability */
EHRPWMHRDisable(SOC_EHRPWM_0_REGS);
}