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.

Workaround for enabling 0/100% duty cycle (2809, SPRAAI1)

Hi, I have tried implementing the described workaround for enabling 0/100% duty cycle. As I want to put this in a general driver, not a specific interrupt, I have used the knowledge of current and next (desired) CMP value and register states to determine which "step" the code currently is in. The following code is an excerpt from the function that is called in every PWM interrupt.

void DutyWorkaround(volatile struct EPWM_REGS *epwm_regs_p, enum PWM_CHANNEL channel, uint16_t next_cmp) {

			if (next_cmp == 0) {
				if (epwm_regs_p->CMPA.half.CMPA != 0) { // CMP non-zero -> zero

					epwm_regs_p->AQCTLA.bit.ZRO = AQ_ACTION_SET;

				} else { // Next cycle after CMP non-zero -> zero

					epwm_regs_p->AQCTLA.bit.ZRO = AQ_ACTION_NONE;
					epwm_regs_p->AQCTLA.bit.CAD = AQ_ACTION_CLEAR;

				}


			} else {

				if (epwm_regs_p->CMPA.half.CMPA == 0) { // CMP zero -> non-zero

					epwm_regs_p->AQCTLA.bit.ZRO = AQ_ACTION_CLEAR;
					epwm_regs_p->AQCTLA.bit.CAD = AQ_ACTION_NONE;
					epwm_regs_p->CMPCTL.bit.LOADAMODE = 2;

				} else { // Next cycle after CMP zero -> non-zero

					epwm_regs_p->AQCTLA.bit.ZRO = AQ_ACTION_NONE;
					epwm_regs_p->AQCTLA.bit.CAD = AQ_ACTION_CLEAR;
					epwm_regs_p->CMPCTL.bit.LOADAMODE = 0;

				}

			}


This seems to work, with the exception that when I toggle the duty cycle between zero (CMP = PRD) and 100 (CMP = 0) in every interrupt, it does no longer work, and produces an output looking like a 75% duty cycle.

1: Is this workaround incompatible with this kind of toggling? Does it expect at least two cycles after CMP going to/from 0 before it does the opposite?

2: The workaround only describes the method, not the source of the problem. Could you please provide me with more information on what causes this problem, so that it is easier to understand and maybe implement a better workaround?

  • Please give me an indication if this is an issue being worked on, or if I need to contact support to get further help.

  • What is the frequency of your PWM ISR?

    What mode is your PWM in?

    What is your PWM TBPRD value?

  • Thank you for your interest! Please tell me if you need more information.

    Daniel Chang said:

    What is the frequency of your PWM ISR?

    2 kHz

    Daniel Chang said:

    What mode is your PWM in?

    Up-Down Count, if that's what you mean. I use channel A and B as individual outputs, triggered by CMPA and CMPB, respectively. AQCTLA: CAU = 1, CAD = 2, others = 0. AQCTLB: CBU = 1, CBD = 2. In DBCTL, OUT_MODE = 3, others = 0.

    Daniel Chang said:

    What is your PWM TBPRD value?

    781
  • How is the PWM ISR triggered?  Is it based on a PWM event such as TBCTR = ZERO?

  • Correct, it triggers on every TBCTR = ZERO. That interrupt further calls my SetDutyCycle function for both channels for three PWMs (including the one triggering the interrupt), which then calls the function that tries to work around the PWM issues.

    I suspect that the problem is that when the fix is applied every second interrupt, the procedure for leaving CMP = 0 overlaps with the procedure for entering CMP = 0. If this is the case, I would appreciate if I could have the documentation of the silicon bug, not only the workaround, so I could try developing a better workaround.

  • How are you achieving the 2 KHz rate?  Is the first ISR further managing the Duty Workaround ISR at the 2 KHz rate?

    F2809 is a 100 MHz maximum device.  At TBPRD=781 in Up-Down count mode, that gives 64 KHz.

  • Stian Soevik said:

    I suspect that the problem is that when the fix is applied every second interrupt, the procedure for leaving CMP = 0 overlaps with the procedure for entering CMP = 0. If this is the case, I would appreciate if I could have the documentation of the silicon bug, not only the workaround, so I could try developing a better workaround.

    This is just my initial reaction, but a 75% effective Duty, in Up-Down count mode, when toggling between 0% and 100% Duty leads me to suspect that this is an issue related to the update code execution speed.  It is possible that your code executing time is exceeding the PWM register reload trigger, causing an incomplete/late update.  
    For example, if you were updating the registers on a TBCTR=PRD event, your code may not be updating the behavior of your CMPA event until after TBCTR=PERIOD event has occured, causing you to create 150% duty, which would appear as 75% effective.
    (See the second note at the end of section 3 in the app note)
  • Stian Soevik said:

    2: The workaround only describes the method, not the source of the problem. Could you please provide me with more information on what causes this problem, so that it is easier to understand and maybe implement a better workaround?

    I checked with someone more familiar with this issue.  There is a silicon bug where the compare based action qualifier output does not function properly for one PWM cycle under certain conditions-

    1) Action qualifier is configured to SET/CLEAR on a CTR=CMP event
            AND
    2) Compare active register load from shadow is configured to occur on a
        CTR=Zero event and the new Compare value is equal to 0
                OR
        CTR=Period event and the new Compare value is equal to Period

    Basically, the compare register is updated a CPU cycle late so the output from the action qualifier will be wrong for one PWM cycle.

    This is why workaround modifies the action qualifier settings to use events like CTR=ZERO instead of CMPA-Up.  The bug applies only for the 1st cycle after the update.  That is why you restore the original action qualifier settings after one cycle, since the PWM will operate properly from cycles 2 and on.

    There is a note in subsection 2.4.4 of SPRU791F, the F280x ePWM user guide.

  • Daniel Chang said:

    How are you achieving the 2 KHz rate?  Is the first ISR further managing the Duty Workaround ISR at the 2 KHz rate?

    F2809 is a 100 MHz maximum device.  At TBPRD=781 in Up-Down count mode, that gives 64 KHz.

    I use a prescaler of 32. Yes, all duty cycles are updated every cycle, so if either CMP goes from or to 0, or it is the cycle after, workaround code will be run.

    Daniel Chang said:

    I checked with someone more familiar with this issue.  There is a silicon bug where the compare based action qualifier output does not function properly for one PWM cycle under certain conditions-

    1) Action qualifier is configured to SET/CLEAR on a CTR=CMP event
            AND
    2) Compare active register load from shadow is configured to occur on a
        CTR=Zero event and the new Compare value is equal to 0
                OR
        CTR=Period event and the new Compare value is equal to Period

    Basically, the compare register is updated a CPU cycle late so the output from the action qualifier will be wrong for one PWM cycle.

    This is why workaround modifies the action qualifier settings to use events like CTR=ZERO instead of CMPA-Up.  The bug applies only for the 1st cycle after the update.  That is why you restore the original action qualifier settings after one cycle, since the PWM will operate properly from cycles 2 and on.

    There is a note in subsection 2.4.4 of SPRU791F, the F280x ePWM user guide.

    Thank you, this is very interesting information. I expected the explanation to be in SPRAAI1, but I will have another look at the ePWM user guide.