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.

TMS320F28379D: PWM interrupt problem

Part Number: TMS320F28379D

Hello, 

I ran into another problem concerning the EPWM interrupt generation. At the start of my ISR, I am setting GPIOs to monitor the handling of the ISR on the scope. 

I am using two EPWM modules to generate a burst-mode operation to output a defined number of high-frequency pulses with a specific repetition rate (low frequence timer). 

I am setting the compare register and use a counter which is decremented to keep track of the generated pulses in the ISR of the high frequency PWM module. If the desired number of pulses is generated (counter < 1)I am stopping to clear the interrupt flag and the pulse generation stops.

The second PWM (configured at a much lower frequency) is (re)setting the counter variable and clear the interrupt flag from the high frequency PWM and the process starts again.

This works quite well, however it seems that once the flag is cleared there is immediately an interrupt generated (2 interrupts directly one after another)


Yellow: GPIO test pin set at start and cleared at end of high-frequency ISR (GPIO 105)

Blue: generated PWM


Any idea what could be the reason for that? The problem is that the generated number of pulses varies from time to time since the counter is decremented already but no pulse is generated (b/c of shadow registers).

Looking forward to hear your thoughts.

Edit 1:

// EPWM2 timer configured such that interrupt occurs with a high rate of 100kHz
// Interrupt at every CNT=Zero event
__interrupt void epwm2ISR(void)
{
    GPIO_writePin(105, 1);
 

    if(pulse_cnt_val > 0)
    {
        EPWM_setCounterCompareValue(EPWM2_BASE, EPWM_COUNTER_COMPARE_A,compA_value);

        pulse_cnt_val--;

    }
    else
    {
            EPWM_setCounterCompareValue(EPWM2_BASE, EPWM_COUNTER_COMPARE_A,0U);
            EPWM_disableInterrupt(EPWM2_BASE);
      
    }

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(EPWM2_BASE);

    //
    // Acknowledge interrupt group
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    GPIO_writePin(105, 0);
}



// EPWM7 timer configured such that interrupt occurs with a low rate of 1kHz
// Interrupt at every CNT=Zero event
// EPWM7 and EPWM2 not syncronized 

__interrupt void epwm7ISR(void)
{
    GPIO_writePin(104, 1);


    // Update pulse count, compare register will be updated in EPWM2 interrupt
    pulse_cnt_val = 10;
    EPWM_enableInterrupt(EPWM2_BASE);

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE);

    //
    // Acknowledge interrupt group
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    GPIO_writePin(104, 0);
}

EDIT 2: EPWM Init Code

//
// initEPWM2 - Configure Phase B
//
void initEPWM2()
{

    //
    // Set-up TBCLK
    //
    EPWM_setTimeBasePeriod(EPWM2_BASE, EPWM2_TIMER_TBPRD);
    EPWM_setTimeBaseCounter(EPWM2_BASE, 0U);
    EPWM_setPhaseShift(EPWM2_BASE, 0U);
    EPWM_enablePhaseShiftLoad(EPWM2_BASE);
    EPWM_setSyncOutPulseMode(EPWM2_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);

    //
    // Set up counter mode
    //
    EPWM_setTimeBaseCounterMode(EPWM2_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setClockPrescaler(EPWM2_BASE,
                           EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_1);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(EPWM2_BASE,
                                EPWM_COUNTER_COMPARE_A,
                                EPWM2_CMPA);
    EPWM_setCounterCompareValue(EPWM2_BASE,
                                EPWM_COUNTER_COMPARE_B,
                                EPWM2_CMPB);
    EPWM_setCounterCompareValue(EPWM2_BASE,
                                EPWM_COUNTER_COMPARE_C,
                                EPWM2_CMPB);



    //
    // Set up shadowing
    //
    EPWM_setCounterCompareShadowLoadMode(EPWM2_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_SYNC_ONLY);
    EPWM_setCounterCompareShadowLoadMode(EPWM2_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_SYNC_ONLY);
    // used to trigger SOC-A
    EPWM_setCounterCompareShadowLoadMode(EPWM2_BASE,
                                         EPWM_COUNTER_COMPARE_C,
                                         EPWM_COMP_LOAD_ON_SYNC_ONLY);


    EPWM_selectPeriodLoadEvent(EPWM2_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);

    //
    // Set actions
    //
    EPWM_setActionQualifierAction(EPWM2_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    EPWM_setActionQualifierAction(EPWM2_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);


    //Trigger ADC SOC

    //
    // Configure  SOC-A to occur at CTR Zero
    //
    EPWM_setADCTriggerSource(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPC);
    EPWM_setADCTriggerEventPrescale(EPWM2_BASE, EPWM_SOC_A, 1);
    EPWM_enableADCTrigger(EPWM2_BASE, EPWM_SOC_A);


    //
    // Interrupt where we will change the Compare Values
    // Select INT on Time base counter zero event,
    // Enable INT, generate INT on 1st event
    //
    EPWM_setInterruptSource(EPWM2_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(EPWM2_BASE);
    EPWM_setInterruptEventCount(EPWM2_BASE, 1U);

}


//
// initEPWM7 - Burst/Pulse Train Timer
//
void initEPWM7(void)
{
    //
    // Set-up TBCLK
    //

    EPWM_setTimeBasePeriod(EPWM7_BASE, EPWM7_TIMER_TBPRD);
    EPWM_disablePhaseShiftLoad(EPWM7_BASE);
    EPWM_setPhaseShift(EPWM7_BASE, 0U);
    EPWM_setTimeBaseCounter(EPWM7_BASE, 0U);
    EPWM_setTimeBaseCounterMode(EPWM7_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setClockPrescaler(EPWM7_BASE,
                           EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_8);
    EPWM_selectPeriodLoadEvent(EPWM7_BASE, EPWM_SHADOW_LOAD_MODE_COUNTER_ZERO);

    //
    // Set up shadowing
    //
    EPWM_setCounterCompareShadowLoadMode(EPWM7_BASE,
                                         EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    EPWM_setCounterCompareShadowLoadMode(EPWM7_BASE,
                                         EPWM_COUNTER_COMPARE_B,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    //
    // Set Compare values
    //
    EPWM_setCounterCompareValue(EPWM7_BASE,
                                EPWM_COUNTER_COMPARE_A,
                                EPWM7_CMPA);

    EPWM_setCounterCompareValue(EPWM7_BASE,
                                EPWM_COUNTER_COMPARE_B,
                                EPWM7_CMPB);

    //
    // Set actions
    //
    EPWM_setActionQualifierAction(EPWM7_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_HIGH,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
    EPWM_setActionQualifierAction(EPWM7_BASE,
                                  EPWM_AQ_OUTPUT_A,
                                  EPWM_AQ_OUTPUT_LOW,
                                  EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

    //
    // Interrupt where we will change the Compare Values
    // Select INT on Time base counter zero event,
    // Enable INT, generate INT on 1st event
    //
    EPWM_setInterruptSource(EPWM7_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_enableInterrupt(EPWM7_BASE);
    EPWM_setInterruptEventCount(EPWM7_BASE, 1U);

}

EDIT 3:

Also interesting to note is that the ADC interrupt is not triggered when the premature execution of the EPW2_ISR occurs?

  • Your image didnt go through

  • Hi Nima,

    any suggestions? I would really appreciate if you could take a look. 

    If this cannot be resolved, any suggestions how to better implement such a burst timer, i.e. a certain number of high frequency (100 kHz) pulses repeated at a comparably low repetition rate (1kHz).

    Kind Regards,

  • The solution could be to check what the interrupt source was.

    It could be that since you have SYNCIN enabled, a SYNC signal is generated, which loads the PHS value into the counter, which is ZERO, causing a second interrupt.

  • Very good suggestion. 

    I am not sure how to check for the source of the interrupt?

    Check interrupt flag and set break-points?

    What I tried though was the following:

    • Sync/phase-loading at CTR=PERIOD --> still same behavior (but since I am using only up-counter I guess it is the same event as CTR=Zero
    • Sync/phase-loading at CTR=COMPA -->still  same behavior
    • Completely disable Sync/phase-loading --> still same behavior

  • You only generate interrupts on CTR=ZERO?

    And you are sure that no other interrupt is using this ISR Handler?

    You get two CTR=ZERO withing microseconds?

  • Yes, only at CTR = Zero.

    Here is the overview of registered ISR in my program:

        Interrupt_register(INT_EPWM2, &epwm2ISR);
        Interrupt_register(INT_EPWM7, &epwm7ISR); // burst timer
        Interrupt_register(INT_EPWM1_TZ, &epwm1TZISR);
        Interrupt_register(INT_EPWM2_TZ, &epwm2TZISR);
        Interrupt_register(INT_EPWM3_TZ, &epwm3TZISR);
        Interrupt_register(INT_ECAP1, &ecap1ISR);
        Interrupt_register(INT_ECAP2, &ecap2ISR);
        Interrupt_register(INT_ECAP3, &ecap3ISR);
        Interrupt_register(INT_ADCA1, &adcA1ISR);  
     

    ADC is triggered via EPWM2 and is the only peripheral interrupt with higher priority. However, I tried deactivating the ADC EOC interrupt and the program still had the same behavior.

    I am also sure that the GPIO (from the picture) is only written at the beginning and end of epwm2ISR.

    Can it be that enabling the interrupt EPWM_enableInterrupt(EPWM2_BASE) causes it to be triggered right away? 

  • Two things we can do to check "Can it be that enabling the interrupt EPWM_enableInterrupt(EPWM2_BASE) causes it to be triggered right away?".

    1. Clear all the interrupt flags for EPWM2 before enabling the interrupt. 

    2. If the value of the CTR in the EPWM2 is equal to ZERO, then it could be triggering the interrupt once you enable it. Can you check to see the value? if that is the case, update the CTR to be 1 instead.

    Nima

  • I tried both suggestions but unfortunately it did not resolve the issues at all.

    It is quite clumsy but I am using a counter which I decrement t every new cycle before I start setting the compare registers. 

    It helps to keep the number of pulses constant. 

    Naturally, the whole thing only works if no interrupt with higher priority for instance ADCA1 is triggered.

  • This is definitely a coding issue. But I'm running out of ideas on how to debug this. 

    Are you maybe changing the period?

     

  • Did you make any progress on this?

  • The period register is updated (using shadowing) just before the interrupt is enabled. 

    Note, the problem also occurs when I am not changing the frequency, i.e. the same value as before is written to the period register.

    So far I couldn't resolve the issue, perhaps I have to think of an alternative way on how to realize this burst mode type operation.

    Please tell me if you know of a consultant who could help to resolve the issue.

  • Have you taken a look at the CLB? you should be able to implement this functionality in the CLB.

    But in general, there must be a very simple mistake in the code which we are missing.

    Maybe try setting the interrupt EVENT count to the number of pulses you want then disable the PWM in the interrupt?