This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi Champ,
I would like to seek your advice regarding an issue I am currently facing. My application utilizes two PWM modules, PWM1 and PWM2. Phase is enabled on PWM2, with PWM1 as SYNCIN (master).
The problem arises when the phase is slowly descending near the CMPA value. I have observed that PWM2 skips for one cycle. Based on some posts I found here, the suggested solution is to handle the phase update by changing the CMPA value to be less than TBPHS in one cycle and then changing back the CMPA to the normal value in the next cycle.
However, this method(*) does not resolve the issue in my case. Are there any specific settings or handlers that I need to add?
I have attached my code here for your reference.
void PWM_init(void){ EPwm1Regs.TBPRD = pwm_prd; EPwm1Regs.TBPHS.bit.TBPHS = 0; // PWM-1 serves as reference EPwm1Regs.CMPA.bit.CMPA = pwm_cmpa; EPwm1Regs.CMPB.bit.CMPB = 0; EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; //change to sysclk EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Symmetrical mode EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm1Regs.EPWMSYNCOUTEN.bit.ZEROEN = 1; EPwm1Regs.EPWMSYNCINSEL.bit.SEL = SYNC_IN_SRC_DISABLE_ALL; EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO; EPwm1Regs.AQCTLA.bit.CAD = AQ_SET; // Active high EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; EPwm1Regs.AQCTLB.bit.CAD = AQ_CLEAR; // Active LOW EPwm1Regs.AQCTLB.bit.CAU = AQ_SET; EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active Hi complementary EPwm1Regs.DBFED.bit.DBFED = Deadtime; EPwm1Regs.DBRED.bit.DBRED = Deadtime; EPwm2Regs.TBPRD = pwm_prd; EPwm2Regs.TBPHS.bit.TBPHS = pwm_phs; EPwm2Regs.CMPA.bit.CMPA = pwm_cmpa; EPwm2Regs.CMPB.bit.CMPB = 0; EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1; EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW; EPwm2Regs.EPWMSYNCINSEL.bit.SEL = SYNC_IN_SRC_SYNCOUT_EPWM1; EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_IMMEDIATE; EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_IMMEDIATE; // EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD; // load on CTR=Zero // EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD; // load on CTR=Zero EPwm2Regs.AQCTLA.bit.CAD = AQ_CLEAR; //Active LOW EPwm2Regs.AQCTLA.bit.CAU = AQ_SET; EPwm2Regs.AQCTLB.bit.CAD = AQ_SET; //Active HIGH EPwm2Regs.AQCTLB.bit.CAU = AQ_CLEAR; EPwm2Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // Enable Dead-band module EPwm2Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // Active Hi complementary EPwm2Regs.DBFED.bit.DBFED = Deadtime; EPwm2Regs.DBRED.bit.DBRED = Deadtime; EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE; } void phase_update(uint16_t phase) { static uint16_t temp; temp = (uint16_t)(((uint32_t)phase* EPwm1Regs.TBPRD) / 180); pwm_phs = temp; update_request = 1; } void PWMUpdate(void) { if (skip_pwm_flag == 1) { EPwm2Regs.TBPHS.bit.TBPHS = pwm_phs; pwm_phs_prev = EPwm2Regs.TBPHS.bit.TBPHS; skip_pwm_flag++; } else if (skip_pwm_flag == 2) { EPwm2Regs.CMPA.bit.CMPA = (EPwm2Regs.TBPRD >> 1); skip_pwm_flag = 0; } if (update_request == 1) { update_request = 0; if (pwm_phs_prev > EPwm2Regs.CMPA.bit.CMPA && pwm_phs <= EPwm2Regs.CMPA.bit.CMPA) { EPwm2Regs.CMPA.bit.CMPA = pwm_phs - 1; skip_pwm_flag = 1; } else { EPwm2Regs.TBPHS.bit.TBPHS = pwm_phs; pwm_phs_prev = EPwm2Regs.TBPHS.bit.TBPHS; } } }
E2E references(*)
https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1163045/tms320f28069-epwm-miss-cycle-while-tbphs-change?tisearch=e2e-sitesearch&keymatch=tbphs%2525252525252520cmpa%2525252525252520pwm%2525252525252520missed#
https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1161072/tms320f28033-when-tbphs-load-value-is-less-than-cmpa-value-the-below-figure-will-the-aq-action-be-lost
Hello Luiz,
Yes the general idea is to modify the compare values such that when we modify the timebase counter value at syncin event with the PHS values the compare event is not missed.
Based on the code you posted here, EPWM2 is set at count down CMPA value and cleared at count-up CMPA value. Can you tell which compare event is missed set or clear in your case ? Since you are using Active -high complementary CMPB values wont matter.
In your case there is possibility that both set or clear events are missed depending on your phs value and loading time. For example in up count is phs is set to value higher then cmpa it could miss clear/set-low event if timebase counter for epwm2 is less than cmpa when syncronization happens. Same for set-high at down count cmpa value but that you have already accounted for in PWMUpdate() function.
Sequence for the phase_update and PWMUpdate would also matter. Also if you can share the snapshot where the compare event is missed on sync-in based phase loading ?
Thanks.
Hi Prarthan,
Thank you for your swift response.
Yes the general idea is to modify the compare values such that when we modify the timebase counter value at syncin event with the PHS values the compare event is not missed.
Understand.
ased on the code you posted here, EPWM2 is set at count down CMPA value and cleared at count-up CMPA value. Can you tell which compare event is missed set or clear in your case ?
Sequence for the phase_update and PWMUpdate would also matter
void PWMUpdate(void) { if (skip_pwm_flag == 1) { EPwm2Regs.TBPHS.bit.TBPHS = pwm_phs; pwm_phs_prev = EPwm2Regs.TBPHS.bit.TBPHS; skip_pwm_flag++; } else if (skip_pwm_flag == 2) { EPwm2Regs.CMPA.bit.CMPA = (EPwm2Regs.TBPRD >> 1); skip_pwm_flag = 0; } if (update_request == 1) { update_request = 0; if (pwm_phs_prev >= EPwm2Regs.CMPA.bit.CMPA && pwm_phs <= EPwm2Regs.CMPA.bit.CMPA) { EPwm2Regs.CMPA.bit.CMPA = pwm_phs - 1; skip_pwm_flag = 1; } else { EPwm2Regs.TBPHS.bit.TBPHS = pwm_phs; pwm_phs_prev = EPwm2Regs.TBPHS.bit.TBPHS; } } }
For example in up count is phs is set to value higher then cmpa it could miss clear/set-low event if timebase counter for epwm2 is less than cmpa when syncronization happens.
EPwm1Regs.EPWMSYNCOUTEN.bit.ZEROEN = 1; EPwm1Regs.EPWMSYNCINSEL.bit.SEL = SYNC_IN_SRC_DISABLE_ALL; EPwm2Regs.EPWMSYNCINSEL.bit.SEL = SYNC_IN_SRC_SYNCOUT_EPWM1; EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_IMMEDIATE; EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_IMMEDIATE;
is there any additional setting required? apart from the attached setting.
Best regards,
Luiz
First, reduce CMPA value to be lower than target phase. CMPA = pwm_phs - 1. Second, set PHS to target phase. TBPHS = pwm_phs.
If CMPA is updated before phase is written it should be okay. At zero sync-in event phase is loaded automatically how are you delaying the phase load event?
Main part is sequence timing for counter zero sync-in event and CMPA value update. Can you describe more on that?
Hi Prarthan,
First, reduce CMPA value to be lower than target phase. CMPA = pwm_phs - 1. Second, set PHS to target phase. TBPHS = pwm_phs. Finally, set back CMPA to normal values. CMPA = (EPwm2Regs.TBPRD >> 1);
The sequence is executed in the ADC interrupt which is triggered by the PWM1 PRD event.
After the update request is received, in the next interrupt CMPA is updated. Then PHS is updated only in the next following interrupt.
2nd event change phs how are you providing synchronization event. phs is loaded to counter only on synchronization event.
After the update request is received, in the next interrupt CMPA is updated. Then PHS is updated only in the next following interrupt.
When does these 3 event interrupts occur ? at pwm1 prd event.
The sequence is executed in the ADC interrupt which is triggered by the PWM1 PRD event
Do you mean to say the three interrupts occur within ADC interrupt ?
Thanks,
Prarthan.
Hi Prarthan,
When does these 3 event interrupts occur ? at pwm1 prd event.
Yes, at pwm prd event as shown by the pic.
Do you mean to say the three interrupts occur within ADC interrupt
No, one interrupt per A/D Conversion. but there's an interval (1x interrupt) between setting the CMPA and PHS. They are not loaded at the same time.
I did not see the pwm skip, when setting the interval to 2x interrupt between setting the CMPA and PHS. I guess 1x interrupt is not enough based on my config.
Thank you for your support,
Luiz