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.

TMS320F28388D: the synchronization between AD and ePWM

Part Number: TMS320F28388D


Dear Mr./Ms.

I am doing some testing on TMS320F28388D.

I am trying to configure the ePWM1 module to work in the "count-up-down" mode, and generate a ePWM1 interrupt at the CTR=PRD every 5 events, and also generate a SOCA signal at the CTR=PRD every 5 events.

From my understanding, the counter values of ETSOCPS[SOCACNT2] and  ETINTPS[INTCNT2] should be the same, because they are counting according to the same signals from the TB module.

But actually, when I read the values when the ePWM interrupt is generated, they are really different.  why does this happen?

I also want to reload the CMP values at the point when the ePWM1 interrupt is generated, which means at the point of CTR=PRD every 5 events. So I used the global reload function. How can I make sure the global reload counter is synchronized with the counter of ETINTPS[INTCNT2]?


Looking forward to  your reply!

  • ETSOCPS[SOCACNT2] is 2 and ETINTPS[INTCNT2 is 0 when the ePWM1 interrupt is generated

  • Yes from what I know they should be the same, unless one is also allowing another event to increment it.

    For the global load, are you just updating CMPA? If yes, you dont need the global load feature. That is if your are updating an enormous amount of register and would like all of them to be updated at the same exact time.

    Share the code for your INTPRD and SOCPRD as text not images, just the small snippet and let me see them more clearly!

    Nima

  • Hi, Nima,Thanks for your reply. The code is following:

    EPWM_enableInterrupt(EPWM1_BASE);//enable ePWM1 interrupt in the peripheral level
    EPWM_setInterruptSource(EPWM1_BASE,EPWM_INT_TBCTR_PERIOD);
    EPWM_setInterruptEventCount(EPWM1_BASE,5U);

    EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
    EPWM_setADCTriggerSource(EPWM1_BASE,EPWM_SOC_A,EPWM_SOC_TBCTR_PERIOD);
    EPWM_setADCTriggerEventPrescale(EPWM1_BASE,EPWM_SOC_A,5U);

    And I just found that when I change the code sequence of the initialization for ADC module and ePWM module, the results will be different.

    When I initialize ADC module first and then ePWM module, the counter value for SOC event and int event will be the same, and if ePWM first and then ADC module, the counter values will be different. the following are the code I initialize the ADC and ePWM module for your reference:

    void init_epwm(void)
    {
    //
    // Disable sync (freeze clock to PWM as well)
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    ==================some code here

    //
    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    }

    void init_adc(void){

    configure_adc_module(ADCA_BASE);

    configure_adc_soc(ADCA_BASE);

    }

    static void configure_adc_module(uint32_t adc_base)
    {


    ADC_setPrescaler(adc_base, ADC_CLK_DIV_4_0);


    ADC_setMode(adc_base, ADC_RESOLUTION, ADC_INPUT_MODE);


    ADC_setInterruptPulseMode(adc_base, ADC_PULSE_END_OF_CONV);


    ADC_enableConverter(adc_base);

    //
    // Delay for 1ms to allow ADC time to power up
    //
    DEVICE_DELAY_US(1000);
    }


    static void configure_adc_soc(uint32_t adc_base)
    {
    uint16_t i;
    for(i=0; i < ADCB_CH_NO; i++)
    {
    ADC_setupSOC(adc_base, (ADC_SOCNumber)i, ADC_TRIGGER_EPWM1_SOCA,//ADC_TRIGGER_SW_ONLY,//TODO select the trigger source
    (ADC_Channel)chsel_soc_adc[i],((ADC_RESOLUTION == ADC_RESOLUTION_16BIT) ? SH_WIN_16BIT : SH_WIN_12BIT));
    }

    //set the last SOC to trigger interrupt 1
    // flag. Enable the interrupt and make sure its flag is cleared.
    //
    ADC_setInterruptSource(adc_base, ADC_INT_NUMBER1, (ADC_SOCNumber)(ADCB_CH_NO-1));
    ADC_enableInterrupt(adc_base, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(adc_base, ADC_INT_NUMBER1);
    }

    So I wonder if the power up for the ADC module has some effect on this. Do you have any ideas?

    Another question, to reload the CMPA, if global load is not used, how can I update it in synchronization with the point of the EPWM1 interrupt, because I just find that it can be reload on the CTR=0 or CTR=PRD and so on , there is no pre-scale settings, right?

    look forward to your reply and thank you again.

  • Perfect I think you found the root cause. You need to initialize the ADC first, because if the EPWM is running, and the SOC events are occuring but the ADC is not initialized yet, the events seem to get ignored.

  • Another question, to reload the CMPA, if global load is not used, how can I update it in synchronization with the point of the EPWM1 interrupt, because I just find that it can be reload on the CTR=0 or CTR=PRD and so on , there is no pre-scale settings, right?

    Well yes but that is fine. It keeps in sync with the last value. When you update CMPA, on the next CTR=PRD or 0, it gets updated to the new one. The extra updates are not going to affect anything. No prescale is needed in this scenario.

  • Hi, Nima, thank you!

    I can get what you mean, you mean if the CMPA is not changed, then the extra updates will have no effects.

    But I will calculate the CMPA in the EPWM1 interrupt ISR, so the CMPA will be updated during this time.

    I am configuring like this to realize a scenario where the control frequency is different from the switch frequency, such as the latter one is 5 times the former one, so the CMPA should be updated every 5 ePWM cycles, do I have to use the global load function or do you have any other suggestions to realize this?

    Thank you!

  • Please do you calculation in a different SW register, and when ready for the update, every x period counts, then put the value in CMPA.

    Nima

  • Do you mean this: If I use a SW register to count the period events, then I should configure the epwm module to generate the interrupt at every CTR=PRD, and then count the events in the ISR, then my code in service routine can not be completed in such short time.

    I can think of two methods: 1. to separate my code to 5 sections and execute each section each time go into the interrupt

                                                2. to use 2 different interrupt, one is generated on every period event to count, the other one is generated every 5                  period events to execute the code

    Am I right? or do you have any other suggestions?

  • No none of this is needed. When you do your calculation for what CMPA need to be, use a SW register that is uint32_t sw_CMPA = calculation;

    When ready to update, CMPA = sw_CMPA.

    Nima