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.

TMS320F280049: ADC interrupt not entering when ADCINTOVF is set

Part Number: TMS320F280049

Hi expert,

My customer implementing both ECAP and ADC interrupt and both of their ISR are quite long with no nesting and preempting. The encountered problem when running for sometime, both ADC and ECAP IFR are not set and ADCINTOVF corresponding bits are set (set attached file).

I find there are little explanation for ADC interrupt overflow circumstance. Could you help me with more details of possibilities/examples in which this issue will occur?

Thanks

Sheldon

registers.zip

  • Hi Sheldon,

    In the ADC ISR routines, can you check if the interrupts are cleared after being serviced? Seems like the interrupts are not cleared, causing overflow flags to be set, as reflected in ADCOVF.

    Regards,

    Joseph

  • Hi Joseph,

    I will provide more details and need more help on this issue for my customer have to explain to their end customer.

    In simple words, they are running two ISR without nesting, the ECAP ISR and the ADC ISR. they indicates the timing of these two ISR by toggling GPIOs. high voltage level indicates the ISR is funning.

    In lower part of below graph, green line indicates ECAP ISR and blue line indicates ADC ISR. You can see that the ADC ISR should start at "one" but delayed and the next ADC ISR should start at "two". In the circumstance, the delayed ADC ISR is still running, will this cause an interrupt overflow? For ADC ISR is not triggered any more.

    In another situation.

    This case also gets a delay in ADC ISR but following ADC ISR are triggered normally. Why this situation didn't get an interrupt overflow? Are there anything to do with the running of last ADC ISR and newly raise ADC interrupt?

    Sheldon

    Thanks

  • Hi Sheldon,

    Thanks for sending the sequence of events through the GPIO toggle but unfortunately, I cannot make any generalizations from it without looking at the ISR, setup,  and conversion codes.  If it is possible to share a snippet of these please do so as it may help us understand why code is producing interrupt overflows.

    Regards,

    Joseph

  • Hi Joseph,

    Below is ADC setup code:

    void Adc_Init(void)
    {
        // Interrupts that are used in this example are re-mapped to ISR functions
        // found within this file.
        Interrupt_register(INT_ADCA1, &adcA1ISR);
    
        // Setup VREF as external 3V
        ADC_setVREF(ADCA_BASE, ADC_REFERENCE_EXTERNAL, ADC_REFERENCE_3_3V);
        ADC_setVREF(ADCB_BASE, ADC_REFERENCE_EXTERNAL, ADC_REFERENCE_3_3V);
        ADC_setVREF(ADCC_BASE, ADC_REFERENCE_EXTERNAL, ADC_REFERENCE_3_3V);
    //    ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
    //    ADC_setVREF(ADCB_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
    //    ADC_setVREF(ADCC_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
    
        // Set ADCCLK divider to /4
       ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
        ADC_setPrescaler(ADCB_BASE, ADC_CLK_DIV_4_0);
        ADC_setPrescaler(ADCC_BASE, ADC_CLK_DIV_4_0);
    
        // Set pulse positions to late
        ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
        ADC_setInterruptPulseMode(ADCB_BASE, ADC_PULSE_END_OF_CONV);
        ADC_setInterruptPulseMode(ADCC_BASE, ADC_PULSE_END_OF_CONV);
    
        // Power up the ADC and then delay for 1 ms
        ADC_enableConverter(ADCA_BASE);
        ADC_enableConverter(ADCB_BASE);
        ADC_enableConverter(ADCC_BASE);
        DEVICE_DELAY_US(1000);
    
        // Configure the SOC to occur on the first up-count event
        EPWM_setADCTriggerSource(EPWM7_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
    //    EPWM_setADCTriggerSource(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
        EPWM_setADCTriggerSource(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_PERIOD);
    //    EPWM_setADCTriggerSource(EPWM7_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
    //    EPWM_setADCTriggerSource(EPWM2_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
    
        EPWM_setADCTriggerEventPrescale(EPWM7_BASE, EPWM_SOC_A, 1);
        EPWM_setADCTriggerEventPrescale(EPWM2_BASE, EPWM_SOC_A, 1);
    
        // Configure SOC0 of ADCA/ADCC to convert pin XX with a sample window of 10
        // SYSCLK cycles. The EPWM7SOCA signal will be the trigger.
        ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN10, 10);
        ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN2, 10);
        ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN0, 10);
        ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN6, 10);
    
        ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN0, 10);
        ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN4, 10);
        ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN2, 10);
        ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM7_SOCA, ADC_CH_ADCIN1, 10);
    
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN8, 10);
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN4, 10);
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN3, 10);
        ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM2_SOCA, ADC_CH_ADCIN2, 10);
    
        // Start ePWMx, enabling SOCA
        EPWM_enableADCTrigger(EPWM7_BASE, EPWM_SOC_A);
        EPWM_enableADCTrigger(EPWM2_BASE, EPWM_SOC_A);
    
        // Set SOC0 to set the interrupt 1 flag. Enable the interrupt and make
        // sure its flag is cleared.
        //
        ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER2);
        ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
       ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    
        // Enable ADC interrupt
        Interrupt_enable(INT_ADCA1);
    }
    

    Below is ECAP setup code:

    void Init_Capture(void)
    {
        EALLOW;
        InputXbarRegs.INPUT15SELECT = 13;         // Set eCAP1 source to GPIO-pin
        ECap1Regs.ECCTL0.bit.INPUTSEL = 14;
        EDIS;
    
        Interrupt_register(INT_ECAP1, &Capture_Process);
    
        EALLOW;
            /****************** eCap1 config ************************/
            ECap1Regs.ECEINT.all = 0x0000;        /* Disable all capture interrupts */
            ECap1Regs.ECCLR.all = 0xFFFF;         /* Clear all CAP interrupt flags */
            ECap1Regs.ECCTL1.bit.CAPLDEN = 0;     /* Disable CAP1-CAP4 register loads */
            ECap1Regs.ECCTL2.bit.TSCTRSTOP = 0;   /* Make sure the counter is stopped */
            ECap1Regs.ECCTL2.bit.CONT_ONESHT = 0; /* continuous mode */
            ECap1Regs.ECCTL2.bit.STOP_WRAP = 0;   /* Wrap after Capture Event 1 */
            ECap1Regs.ECCTL1.bit.CAP1POL = 1;     /* Falling edge */
            ECap1Regs.ECCTL1.bit.CAP2POL = 0;     /* Rising edge */
            ECap1Regs.ECCTL1.bit.CAP3POL = 1;     /* Falling edge */
            ECap1Regs.ECCTL1.bit.CAP4POL = 0;     /* Rising edge */
            ECap1Regs.ECCTL1.bit.CTRRST1 = 1;     /* Difference operation */
            ECap1Regs.ECCTL1.bit.CTRRST2 = 1;     /* Difference operation */
            ECap1Regs.ECCTL1.bit.CTRRST3 = 1;     /* Difference operation */
            ECap1Regs.ECCTL1.bit.CTRRST4 = 1;     /* Difference operation */
            ECap1Regs.ECCTL2.bit.SYNCI_EN = 1;    /* Enable sync in */
            ECap1Regs.ECCTL2.bit.SYNCO_SEL = 0;   /* Pass through */
            ECap1Regs.ECCTL1.bit.CAPLDEN = 1;     /* Enable capture units */
            ECap1Regs.ECCTL2.bit.TSCTRSTOP = 1;   /* Start Counter */
            ECap1Regs.ECEINT.bit.CEVT1 = 1;       /* 1 events = __interrupt */
    
    
         EDIS;
         SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ECAP1);
         //ECAP_enableInterrupt();
         Interrupt_enable(INT_ECAP1);
    
    
    }
    

    Below are the two ISRs:

    Thanks

    Sheldon

  • Hi Josph,
    I guess the risk is when new ADC interrupt comes after "AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;" or at some point other than that.
    Could you confirm this for me?
    Thanks
    Sheldon
  • Hi Joseph,

    Could you help me check if this understanding is right or not?

    BTW, based on our application, could you explain a situation or corner case which can produce an interrupt overflow flag?

    Thanks

    Sheldon

  • Hi Sheldon,

    ADC interrupt overflow will occur whenever another ADC interrupt occurs while there is an active ADC interrupt that is not yet cleared. The proper way to manage this is to clear the current interrupt after it is serviced, check for ADCINTOVF for any overflow flags and clear the corresponding overflow in ADCINTOVFCLR and ensure there are no other pending ADC interrupts.

    Based on the code snippet, it looks like 4 SOCs per ADC (SOC0 to SOC3) are triggered by only one event which is EPMW7SOCA. It also looks like only ADCINT1 is being used and it is being triggered once SOC2 finishes conversion. I think this is fine but better to configure ADCINT1 to be triggered by the last SOC (SOC3) instead.

    Lastly, I do not know how fast is EPWM7SOCA is running with respect to the SH (ACQPS). The above ADC setup will work with 4 SOCs running in series as long as all the combined SH (ACQPS) and tLAT of the 4 SOCs are well under the period of EPWM7SOCA otherwise you may get interrupt overflows if EPWM7SOCA is running faster that the sum of the 4 SOC's SH (ACQPS) and tLAT. I'd recommend looking at the ADC timing diagram in the TRM if you get the chance as this clearly illustrates the events from SOC to the end of conversion. Also the ISR code seems pretty straightforward - no unnecessary code that will cause extra timing issues that would may throw off the sequence of events.

    Let me know if you still have any questions on this topic.

    Regards,
    Joseph
  • Hi Joseph,

    Customer removed any use code in the ISR so it seems straight forward :)

    I still have some questions on details regarding your comment: ADC interrupt overflow will occur whenever another ADC interrupt occurs while there is an active ADC interrupt that is not yet cleared.

    We have two situation who both have another ADC interrupt occurs when there is still ADC ISR running. Please check my attached PPT for details on this!

    Thanks!

    Sheldon

    8741.ADC.zip

  • OR you can see these pictures directly for our question.

  • Hi Joseph,

    I really need your help on this. Thanks!

    Sheldon