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.

TMS320F280039C: Interrupt Nesting

Part Number: TMS320F280039C
Other Parts Discussed in Thread: TMS320F28388D

We are experiencing an increase in duty on one of our periodic interrupts (ePWM_ISR) when both SCI and CAN interrupts are enabled.

CAN interrupt is receiving every 50ms

CLA is enabled

ePWM_ISR is set to trigger every ~71us (14kHz)

ADC_ISR is set to trigger every ~7us (140kHz)

Max duty of ePWM_ISR is around 80% without enabling SCI yet.

Max duty of ePWM_ISR reaches 100% when SCI interrupt is enabled even though it is not being triggered.

Is it normal to have an effect on ePWM_ISR by just enabling SCI interrupt even though there is still no data coming through it?

  • Is it normal to have an effect on ePWM_ISR by just enabling SCI interrupt even though there is still no data coming through it?

    Yes, Since SCI + CAN IRQ/ISR pending access ePIE slower rate takes CPU time for TXD/RXD. We need to give ePWM highest global peripheral core priority in SCI and CAN ISR's. There are a few TI Wiki pages outline how to achieve priority order though often see others simply add DINT/ENT in the ISR calls.

    C28x Interrupt Nesting

    (1) [FAQ] My C2000 SCI is not Transmitting and/or Receiving data correctly, how do I fix this? - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

    C2000Tm CLA Software Development Guide — C2000Tm CLA Software Guide

  • It is not clear if you are talking about the duty-cycle of the PWM waveform or the latency in servicing the PWM interrupt. If you are talking about the former, enabling other interrupts should not impact the duty-cycle. If you talking about the latter, increased latency is to be expected when more interrupts are enabled. Having said that, if there is no activity on SCI, interrupts should not be generated and there should be no impact on the PWM operation.

  • Hi Genatco and Hareesh,

    Thanks for your replies

    To give you some additional details, please see waveforms below

    The first waveform receives CAN message every 50ms, SCI is still not initialized. ePWM_ISR is around 80% max duty.

    The second waveform receives CAN message every 50ms, SCI is initialized and enabled interrupt for both TX and RX. But no message coming through the SCI lines. ePWM_ISR reaches 100% max duty.

    Here are some code snippets of the ISRs, maybe you could spot some error or room for improvement. Appreciate the help thanks.

    __interrupt void ADC_ISR(void)
    {
        HWREGH(GPIODATA_BASE + GPIO_O_GPBSET) = 0x01; //GPIO32
        /* clear interrupt */
        HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 1U << (dsp_math_uint16_t)ADC_INT_NUMBER1;
    
        /* user code */
    
        HWREGH(PIECTRL_BASE + PIE_O_ACK) = INTERRUPT_ACK_GROUP1;
        HWREGH(GPIODATA_BASE + GPIO_O_GPBCLEAR) = 0x01; //GPIO32
    }

    __interrupt void EPWM_ISR(void)
    {
        HWREGH(GPIODATA_BASE + GPIO_O_GPBSET) = 0x02; //GPIO33
        volatile dsp_math_uint16_t tempPIEIER1 = HWREGH(PIECTRL_BASE + PIE_O_IER1);
    
        IER |= INTERRUPT_CPU_INT1;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) &= 0x0001;
    
        HWREGH(PIECTRL_BASE + PIE_O_ACK) = 0xFFFFU;
    
        __asm("  NOP");
    
        EINT;
    
        /* clear interrupt */
        HWREGH(EPWM1_BASE + EPWM_O_ETCLR) |= EPWM_ETCLR_INT;
    
        /* user code */
    
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    
        DINT;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER1;
        HWREGH(GPIODATA_BASE + GPIO_O_GPBCLEAR) = 0x02; //GPIO33
    }

    __interrupt void canISR(void)
    {
        HWREGH(GPIODATA_BASE + GPIO_O_GPASET) = 0x800; //GPIO11
        volatile uint16_t tempPIEIER1 = HWREGH(PIECTRL_BASE + PIE_O_IER1);
        volatile uint16_t tempPIEIER3 = HWREGH(PIECTRL_BASE + PIE_O_IER3);
    
        IER |= INTERRUPT_CPU_INT1 | INTERRUPT_CPU_INT3;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) &= 0x0001;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) &= 0x0001;
    
        HWREGH(PIECTRL_BASE + PIE_O_ACK) = 0xFFFFU;
    
        __asm("  NOP");
    
        EINT;
    
        /* user code */
    
        DINT;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER1;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) = tempPIEIER3;
        HWREGH(GPIODATA_BASE + GPIO_O_GPACLEAR) = 0x800; //GPIO11
    }

    __interrupt void sciaTXFIFOISR(void)
    {
        volatile uint16_t tempPIEIER1 = HWREGH(PIECTRL_BASE + PIE_O_IER1);
        volatile uint16_t tempPIEIER3 = HWREGH(PIECTRL_BASE + PIE_O_IER3);
    
        IER |= INTERRUPT_CPU_INT1 | INTERRUPT_CPU_INT3;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) &= 0x0001;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) &= 0x0001;
        HWREGH(PIECTRL_BASE + PIE_O_ACK) = 0xFFFFU;
    
        __asm("  NOP");
    
        EINT;
    
        /* user code */
    
        DINT;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER1;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) = tempPIEIER3;
    }

    __interrupt void sciaRXFIFOISR(void)
    {
        HWREG(GPIODATA_BASE + GPIO_O_GPASET) = 0x800000; //GPIO23
        volatile uint16_t tempPIEIER1 = HWREGH(PIECTRL_BASE + PIE_O_IER1);
        volatile uint16_t tempPIEIER3 = HWREGH(PIECTRL_BASE + PIE_O_IER3);
    
        IER |= INTERRUPT_CPU_INT1 | INTERRUPT_CPU_INT3;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) &= 0x0001;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) &= 0x0001;
        HWREGH(PIECTRL_BASE + PIE_O_ACK) = 0xFFFFU;
    
        __asm("  NOP");
    
        EINT;
    
        /* user code */
    
        DINT;
    
        HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER1;
        HWREGH(PIECTRL_BASE + PIE_O_IER3) = tempPIEIER3;
        HWREG(GPIODATA_BASE + GPIO_O_GPACLEAR) = 0x800000; //GPIO23
    }

  • Hi,
    It seems like you're experiencing a similar issue to what I encountered. When trying to read data via interrupts from four SCI (Serial Communication Interface) lines, I can read all the data without missing any (baud rate: 115200 bits/s). However, when I try to read two CAN (Controller Area Network) communications along with SCI via interrupts, I start missing data on the SCI line. I haven't found a solution yet, but it appears similar to the problem you faced. I'm using C2000: tms320f28388d.

  • Hi,

    Seemingly ePWM/ADC_ISR's should not have any HWREG IER/PIER or EINT/DINT, ePIE nesting of ADC samples is controlled inside SCI and CAN ISR's when nesting between different ISR groups. They each should give peripheral core highest priority order to ADC ISR being SOIC trigger interrupts from ePWM (14KHz (71.43µs)) for the window time starts ADC sampling. The PPB output controls ePWM CMPA up down counts for the PWM duty cycle. 

    The biggest issue we randomly notice SCI_RX_FIFO interrupt causing RX buffer overflows. Also have to test TX PIE_IFR flag bit is set and call to send FIFO data or it locks up ePIE x49c (115,200BPS)  The TXD loop runs round robin below ePWM 20KHz 50µs. 

    	/* TX FIFO level interrupt full or ready status?  */
    	if((ui32IntStatus &SCI_INT_TXFF) || (ui32IntStatus &SCI_INT_TXRDY)) //
    	{
    
            /* Check IFR register flag is not late arriving */
            if(HWREGH(PIECTRL_BASE + PIE_O_IFR9) == PIE_IFR9_INTX4)
            {
                //HWREGH(SCIB_BASE + SCI_O_FFTX) |= SCI_FFTX_TXFFINTCLR;
    
                /* Block TX FIFO FULL status, disable transmit interrupt */
                while((HWREG(SCIB_BASE + SCI_O_FFTX &SCI_FFTX_TXFFST_M) >>
                                            SCI_FFTX_TXFFST_S) >= SCI_FIFO_TX8){}
                                            
                                            
            }
                                            
        
        }

  • Hi,

    When I remove the HWREG IER/PIER or EINT/DINT in ePWM and ADC ISRs, it messes up the ADC timing. Please see waveform below

  • Hi Ronald,

    Seems odd you have two IER flag bits set for RXFIFO and CAN there is only one ISR for each priority group IRQ. Another point UMCSDK don't use ePWM ISR as function PWM hal.c configures the ADC1 trigger source SOC1 ADC1 or what ever ISR you choose in hal.h. Perhaps HALL configuration uses ePWM ISR ? However the sensorless FOC uses ADC trigger source to start SOC sampling, e.g.  HAL_setupPWMs(HAL_MTR_Handle handle). I see they configured ePWM interrupt seemingly for BLDC drive.

    What mode are you using.

    #else   //!(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)
        // setup the Event Trigger Selection Register (ETSEL)
        EPWM_setInterruptSource(obj->pwmHandle[0], EPWM_INT_TBCTR_ZERO);
    
        EPWM_enableInterrupt(obj->pwmHandle[0]);
    
        EPWM_setADCTriggerSource(obj->pwmHandle[0],
                                 EPWM_SOC_A, EPWM_SOC_TBCTR_D_CMPC);
    
        EPWM_enableADCTrigger(obj->pwmHandle[0], EPWM_SOC_A);
    #endif  // !(MOTOR1_ISBLDC || MOTOR1_DCLINKSS)

        /* Get SCIB interrupt flag status */
        ui32IntStatus = SCI_getInterruptStatus(SCIB_BASE);
    
        /* The receive interrupt is cleared by performing
         * a single read of the receive INT status, or by clearing
         * the interrupt by writing a 1 to the RXIC bit. */
        SCI_clearInterruptStatus(SCIB_BASE, ui32IntStatus);
        //
        DINT;
        // Save group1 IER register on stack
        volatile uint16_t tempPIEIER = HWREGH(PIECTRL_BASE + PIE_O_IER1);
    
    	// Set "global" Group 1 priority
        IER |= M_INT1;
        IER &= M_INT1;
    
        /* Give ADCC1 priorty over SCIB RXD ISR */
        HWREGH(PIECTRL_BASE + PIE_O_IER1) &= PIE_IER1_INTX3;
        /* PieCtrlRegs.PIEACK.all = 0xFFFF */
        Interrupt_clearACKGroup(0xFFFFU);
        // Fix for Errata 4.1.1 B2B PIEACK writes.
        __asm("  NOP");
        //
        EINT;
    

  • Hi Genatco,

    There are two IER flag bits, one for ADC and the other one for ePWM. They are both configured as high priority and should preempt the CAN and SCI.

    Interrupt priority should be in the following order. ADC->ePWM->CAN->SCI

    Update: ePWM remains at 80% duty when disabling SCI_TX interrupt. Still have to check for its effects if we convert it to polling instead.

  • Tried converting the SCI_TX to non-interrupt and keep SCI_RX as interrupt.

    The EPWM duty still reaches 100% not as often as before, but still reaches it especially when there are messages coming through SCI lines.

  • Hi Ronald,

    Why is your code servicing the ePWM interrupt source? The fast estimator ISR (FOC) uses motor1CtrlISR() Group-1 ADCn interrupt source. Sorry for any confusion on my part, thought you were adding to the universal motor control example code. If your not actually using ePWM ISR don't configure C code to handle unused ISR. Set the ADC trigger source SOCn for fast estimator to handle PARK transform data to produce sine wave alternating phase current. 

    Using ePWM to trigger the ADC source SOCn, the EOCn pulse interrupt keeps ADC samples synchronous CMPA load value. Thus setting duty cycle for the next cycle often as TBCLK = 0. Yet BLDC with HALL's can shadow global synchronous updates (CMPn x3) via ePWM ISR to avoid spurious PWM pulses from occurring on the DC inverter or half bridge. However the fast estimator library in UMCSDK example code does not seem to configure an ePWM ISR handler since BLDC mode simply sets user_mtr1.h #define USER_M1_MAX_VS_MAG_PU   to create trapezoidal wave form on each phase.   

    //! \brief Set USER_MAX_VS_MAG = 2/3 = 0.6666 to create a trapezoidal
    //! \brief voltage waveform. Current reconstruction will be needed
    //! \brief for this scenario (Lab08).

  • Ronald,

        Has your issue been resolved?

  • Hello Hareesh,

    Found out that the problem is in the interrupt nesting code. When re-enabling higher interrupts, lower interrupts were left unchanged. That's why lower interrupts can unintentionally preempt the higher interrupt (epwm).