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.

TMS320F280049C: CPU vectors outside ePIE peripheral core priority orders and ignores group clearACK noticed inside while for loops of core vectors

Guru 55913 points
Part Number: TMS320F280049C
Other Parts Discussed in Thread: C2000WARE

Hello,

I notice an issue with C2000 not behaving like ARM type CPU inside interrupt handlers. Seemingly race to instruction prefetch execution prior to termination by ( } ) syntax. The C++ compiler eabi.lib versions do not have this issue with ARM CPU only noticed in C2000. Perhaps the legacy COFF output format with TI v18.12.2.LTS has something to do with this odd CPU behavior?

Mostly noticed (for) and (while) loops process outside the functions last return and during increment count execution sequence. That is not proper behavior for next function to execute prior in either loop in clause variable count shown below. The loops shown below must complete prior to executing the outside and next function.


volatile uint32_t timeWaitCnt = 0;

/* Wait for a while */
while(timeWaitCnt < 500000)
{
  timeWaitCnt++;
}
/* Executes this function inside (while) loop */
SCIprintf(">>Text Output \n");

//2nd example:

for(timeWaitCnt=0;timeWaitCnt < 500000;timeWaitCnt++)
{
}
/* Executes this function inside (for) loop */
SCIprintf(">>Text Output \n");

//3rd Example:

/* Wait 200ms  */
SysCtl_delay(100000000 / 5);
//
SCIprintf(">> EntersFunction \n");

  • GI,

    I wonder if this is an effect of optimization.  If you disable optimization in the compiler do things work normally?

    Best,

    Matthew

  • Hi Matthew,

    Project is set to use global optimizations but the compiler symbol (__interrupt void) added top of functions states to save certain items on the stack. It seems the volatile keyword added to (timeWaitCnt) declaration is not being saved on the stack and even being preempted in the middle of ISR execution.

    Also tried no, local optimizations and the ADC continuous errata patch would halt CPU execution with no optimizations set. As I mentioned this issue is not present in ARM Cortex MCU with NVIC interrupt controller. I can't believe the amount of time spent trying to get 4 interrupts to work seamlessly then this issue occurs. 

    3.5.4.2 Handling Interrupts
    ISRs are similar to normal functions, but must do the following:
    1. Save and restore the state of certain CPU registers (if used).
    2. Clear the PIEACK bit for the interrupt group.
    3. Return using the IRET instruction.
    Requirements 1 and 3 are handled automatically by the TMS320C28x C compiler, if the function is defined using the __interrupt keyword. For information on this keyword, see the Keywords section of the TMS320C28x Optimizing C/C++ Compiler v6.2.4 User's Guide. For information on writing assembly code to handle interrupts, see the Standard Operation for Maskable Interrupts section of the TMS320C28x CPU and Instruction Set Reference Guide.

  • GI, is it possible to share the source project or smaller snippet project so we can try to reproduce locally? 

    Can you clarify a bit if you think this is a issue effecting program execution or one that effects the state of watched variables during debug when BPs are inserted in the code?  The reason I mentioned the optimization is I have seen some behavior when debugging  C source vs the actual ASM, meaning that the line in C doesn't always line up to the ASM that has been/will be executed.

    Best,

    Matthew

  • Can you clarify a bit if you think this is a issue effecting program execution or one that effects the state of watched variables during debug when BPs are inserted in the code?

    Condition occurs without inserted break points or CCS real time debug being enabled. 

    Oddly my UART peripheral application with modifications for SCIB use the same (for/while) loops that work correctly via TM4C1294 though have major issues with C++ functions via x49c. Mostly relative to SCIB RX/TX FIFOs versus UART FIFO's of the TM4C1294 ARM cortex that have no such issues with stopping forward processing of C++ syntax after the function ( } ). The examples of the for while SysCtl_delay() were posted above to insert into added PIE interrupts of group1/9 with Instaspin SDK (FOC) being loaded.

    Only do we see debug single stepping (F5) cursor jump to the next function after the last functions return ( } ) mnemonic. The actual firmware (*.out) during debug (RUN) mode should never behave this way especially when break points were not set. So it could be the XDC110 debug emulation doing this jump as I think you seem to be suspecting?

  • GI,

    Let me loop in a few more folks here, I think we are getting to the root of the issue(your last paragraph). 

    Should I be able to see this if I use one of our C2000Ware examples for SCI, or could you try this on one of those examples and see if you can replicate and then let me know the lines to set the BP, etc?

    Best,

    Matthew

  • Hi Matthew,

    Sorry for delay our internet was down since Monday, a bad storm took many trees down. 

    Should I be able to see this if I use one of our C2000Ware examples for SCI,

    Supposedly it was occurring inside any ePIE interrupt handler. The TRM text states SCI RX FIFO is 10 bitwise read (23.13.1) but Fig 23-2 (Pg 2188) shows FIFO as being 8 bit wide?

    Oddly RX FIFO read bits via a (for) loop with (for) call timeout outer loop has very strange behavior. If you setup SCIA without interrupt or FIFO to do SCIprintf() as to indicate SCIB array[i] playback in the loop there is no ASCII data printed only header text appears 32 times putty USB3 virtual COM.

    Also the ePIE INT3 RX FIFO (SCIB) locks up after asserting RX serial command for CPU to send 32 bytes TX data via CPUTimer0. Alternatively calling executing below code (for loop) FIFO read function from inside TX interrupt handler. So it does the round robin transaction but locks the RX FIFO after issuing INTERRUPT_ACK_GROUP9 while ADCA1 interrupt errata set to continuous or not.

    Many (while) calls made from SCIB TXD call handler function that interrupt ADCA1. Include various sample sources SOC_NUMBER_0, 1, 2 via INT source ADC_INT_NUMBER1 Group 1. The same (for, while) loop method on TM4C1294 MCU does not cause odd problems.

    while(!(NexSendCmd("vis p10,1", 0, 0, 0)));//stop red led
    while(!(NexSendCmd("vis n12,0", 0, 0, 0)));//start green led

    Code snip of nested (for) loops issue: 

    //global defines
    
    //********************************************************
    //
    // Buffer for SCIB commands
    //
    #define UART_NRX_BUF_SIZE            33
    
    /* SCIB RX command input buffer */
    unsigned char UartRxBuff[UART_NRX_BUF_SIZE] = {};
    
    /********************************************************/
    
    /********************************************************
    *!
    *! Nextion Control SCIB TX/RX interrupt handler
    *! This funciton checks the MIS bits to determine the
    *! interrutp source from the enabled IS flags.
    *!
    *********************************************************/
    __interrupt void
    NexSCIbRxISR(void)
    {
    	int i;
        volatile static uint32_t ui32IntStatus = 0;
        uint32_t ui32RxErrorStatus = 0;
    
        //
        // Save group1 IER register on stack
        //
        volatile uint16_t tempPIEIER = HWREGH(PIECTRL_BASE + PIE_O_IER1);
    
    
    	// Set "global" priority
        IER |= M_INT3;
        IER &= M_INT3;
        //
        EINT;
    
        volatile uint16_t TempPIEIER;
    
        /* Load the RX error status bits */
        ui32RxErrorStatus = (SCI_RXSTATUS_WAKE|SCI_RXSTATUS_PARITY|
    							SCI_RXSTATUS_OVERRUN|SCI_RXSTATUS_FRAMING |
    								SCI_RXSTATUS_BREAK|SCI_RXSTATUS_READY |
    													SCI_RXSTATUS_ERROR);
    
    
        /* Get SCIB interrupt flag status */
        ui32IntStatus = SCI_getInterruptStatus(SCIB_BASE);
    
        /* Check interrupt Flags UARTICR bits RXINT  */
        if(ui32IntStatus &SCI_INT_RXERR || ui32IntStatus &SCI_INT_FE ||
        		ui32IntStatus &SCI_INT_OE || ui32IntStatus &SCI_INT_PE ||
    				ui32IntStatus &SCI_INT_RXRDY_BRKDT)
        {
            /* Durring interrupt check the RSR/ECR register for
             * RX errors: OE, BE, PE, FE  */
            if(ui32RxErrorStatus &= SCI_getRxStatus(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);
            	/* Clear all ECR error bits and return */
        		SCI_clearInterruptStatus(SCIB_BASE, ui32RxErrorStatus);
    
                /* Has Rx FIFO overflowed ? true */
                if(SCI_getOverflowStatus(SCIB_BASE))
                {
                	/* Clear Rx overflow status */
                	SCI_clearOverflowStatus(SCIB_BASE);
                	 /* SCIA Prints error event message */
                	SCIprintf("\n>> ClearRxFIFO-OVF \n");
                }
    
                /* Print the error event message */
                SCIprintf("\n>> RxError: %x\n", ui32RxErrorStatus);
    
            	/* Flush the RX buffer */
                for(i=0; i == 31; i++)
                {
                	CcRxBuff[i] = 0;
                }
                
                // Acknowledge interrupt from PIE group 9
                Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
                //
                // Disable interrupts and restore registers saved:
                //
                DINT;
                HWREGH(PIECTRL_BASE + PIE_O_IER1) = TempPIEIER;
                //
                return;
            }
        }
    
    	/* TX FIFO level interrupt 8/16th full?  */
    	if(ui32IntStatus  &SCI_INT_TXFF) //||&SCI_INT_TXFF ui32IntStatus
    	{
    		/*  The TXFF interrupt is cleared by performing
    		 *  a single read of the INT status, or by clearing
    		 *   the interrupt by writing a 1 to the TXIC bit. */
    		SCI_clearInterruptStatus(SCIB_BASE, ui32IntStatus);
    
    		/* If the TX FIFO 8/16's full, enable the transmit interrupt .*/
    		if((HWREG(SCIB_BASE + SCI_O_FFTX &SCI_FFTX_TXFFST_M) != SCI_FIFO_TX0))
    		{
    			/* Enable the transmit interrupt */
    			SCI_enableInterrupt(SCIB_BASE, SCI_INT_TXFF);//SCI_INT_TXRDY SCI_INT_TXFF
    		    /* Enable SCIB FIFO PIEIERx interrupt */
    		    Interrupt_enable(INT_SCIB_TX);
    		}
    	}
    
    	/* RX FIFO level interrupt, 8/16th full? */
    	if(ui32IntStatus &SCI_INT_RXFF)
    	{
    		/*  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);
    
    	    /* Stop CPU-TM0 for Nextion vars updates */
    	    CPUTimer_stopTimer(CPUTIMER0_BASE);
    
    		SCIprintf("\n>> INT3.9-RxFIFO \n");
    		/* Process SCIB RX commands limit
    		 * by a 31 MAX count timeout */
    		while(NexGetCmd(31));
    
    		/* Flush the RX buffer */
    		//for(i=0; i == 31; i++)
    		{
    			//CcRxBuff[i] = 0;
    		}
    	}
        // Acknowledge interrupt from PIE group 9
    	Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
        
        // Disable interrupts and restore registers saved:
        DINT;
        HWREGH(PIECTRL_BASE + PIE_O_IER1) = tempPIEIER;
    }
    
    /****************************************************
    *
    * Configure Nextion SCIB (RXD) for callBack.
    * Handles SCIB Receive input string data.
    * Passes 32 bit strings into command interpreter
    *
    * @param buffer - save input string data.
    *
    * @param timeout - set timeout time.
    *
    * \bReturn:0=FIFO empty, CMD error-1,-2,-3,-4
    * \bReturn:1=FIFO filling
    *
    ******************************************************/
    int
    NexGetCmd(uint32_t timeout)//unsigned char *buffer,
    {
        volatile static uintptr_t i;
        signed int ret = 0;
        static uint32_t Timeout;
    
    	//
    	// Enter a loop to read characters from the UART
    	// Note: Buffer 32 bytes then check for commands
        //
    
    	/* Timeout MAX count for getting RXD FIFO bytes */
    	for(Timeout = 0; Timeout < timeout; Timeout++)
    	{
    		/* Load RX data elements */
    		for(i = 0; i <= 32; i++)
    		{
    			/* Check if receiver is Not full, NonBlocking
    			 * characters are received into FIFO */
    		
    			/* Blocking checks FIFO space filled */
    			//if(SCI_getRxFIFOStatus(SCIB_BASE) <= SCI_FIFO_RX4)
    			{
    				CcRxBuff[i] = (unsigned char)(HWREG(SCIB_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
    
    				//SCIprintf("RX: %c\n", CcRxBuff[i]);
    
    			   /* FIFO filling */
    			    ret = 1;
    			}
    			/* The RX FIFO is full command success */
    			if (i == 32) //32
    			{
    				/* Scan the argument buffer for commands
    				 * and process only valid command/s */
    				ret = CheckNexCommands();
    
    				/* Error (-1,-2,-3,-4) */
    				if(ret == -1 || ret == -2 || ret == -3 || ret == -4)
    				{
    					ret = 0;
    				}
    				return(ret);
    			 }
    		}
    	}
    
        return (ret);
    }
     

  • GI,

    Would it be possible to use either of these examples:

    C:\ti\c2000\C2000Ware_4_01_00_00\driverlib\f28004x\examples\sci\ either the ex4_echoback or ex3 that uses the FIFO and also echobacks and note where setting/single stepping gives un-expected behavior?  I think we are going to have to get a common project so we can duplicate this here to understand exactly what is happening vs what should happen.

    Best,

    Matthew

  • Hi Matthew,

    You can add this SCIB code above to the Motor control SDK (FOC) on x49c launchpad, or I can do a project export share.  All you need is another launch pad to use for XDC110 SCIB circular prints via TXD called time loop. Can you get supervisor to ok purchase Nextion 3.5" LCD (500mA Max) sold on eBAY for $39.00, then load a binary of similar LCD pages via XDC110 Tx/Rx J101 header pins removed? 

    Then we are talking the same scenario that locks SCIB RX FIFO immediately after TX round robin event. Recall above I stated this same nested for loop RX/TX round robin works without issue TM4C1294 MCU.

    Otherwise please load the SCIB ISR functions above into CCS so it becomes easier to read, syntax in color. Let me know if you see any odd syntax SCIB RX FIFO 10 bit reads into UNSIGNED CHAR (conversion) and load of MyArray[i] via nested for loop. Why might that lock RX FIFO after group 9 clear ACK.  Why no comment of RX FIFO 10 bit not shown Fig.23.2 SPRUI33D – NOVEMBER 2015 – REVISED SEPTEMBER 2020? Is that a misprint?

    23.13 6. Buffers. Transmit and receive buffers are supplemented with two 16-level FIFOs. The transmit FIFO registers are 8 bits wide and receive FIFO registers are 10 bits wide.

  • Would it be possible to use either of these examples

    Most the FIFO examples use blocking, the RX FIFO is interrupt driven. Basically code only checks for free TX buffer space being longer data strings output to LCD. The total size of longest RX command is only 8 serial bytes but some like (cfaults) are 7 bytes (sent twice), second set immediately after the first. That has more to do with C+ array transfers of data sent to the command interpreter for analysis. 

  • Hi Matthew,

    I think we are going to have to get a common project so we can duplicate this here to understand exactly what is happening vs what should happen.

    Below example is part of TI motor control SDK (hal.c) (for loop) used to configure 3 ePWM and SOC ADC trigger sources. Count values (5) for each CMPD are missing when [for cnt++] count via Base_Address[cnt] asserts. Versus peripheral Base_Address[0] (explicit) being put into the same (for) count loop, does load ePWM1A CMPD count (5) via CCS real time debug register view.

    I added two SysCtlDelay(10) later several 100 loop ASM dealy to slow (for loop) but still failed to load 3 ePWM CMPD register values. The TI FE who designed this part of ePWM module configuration opted to use Base_Address[0] in the SOCA via CMPD count triggers. Yet all three ePWM-A generators SOCA can be used to trigger ADCA, ADCB, ADCC peripherals if R3 silicon or SW compiled *.bin files are doing as C+ syntax mandates.

    #if (BOOST_to_LPD == BOOSTX_to_J5_J6)
        // initialize PWM handles for Motor 1
        obj->pwmHandle[0] = EPWM1_BASE;       //!< the PWM handle, GPIO0/GPIO1
        obj->pwmHandle[1] = EPWM4_BASE;       //!< the PWM handle, GPIO6/GPIO7
        obj->pwmHandle[2] = EPWM2_BASE;       //!< the PWM handle, GPIO2/GPIO3
        
    #endif
    
    
    
     // begin HAL_setupPWMs() SOC ADC trigger for CMPD count functions
       
        for(cnt=0;cnt<3;cnt++)
        {
    
        SysCtl_delay(10);
    
        // setup the Event Trigger Selection Register (ETSEL)
        // COMPD-DN=5 or SOC_TBCTR=0
        EPWM_disableInterrupt(obj->pwmHandle[cnt]);//0
        // set EPWM1 trigger pulse, TBCTR=50µs*5 250µs or 25µs*1 CMPD-D
        EPWM_setADCTriggerSource(obj->pwmHandle[cnt],//0
                                 EPWM_SOC_A,
    							 EPWM_SOC_TBCTR_D_CMPD);
        //EPWM_SOC_TBCTR_ZERO, EPWM_SOC_TBCTR_PERIOD, EPWM_SOC_TBCTR_D_CMPD
    
        // Enable EPWM1 to trigger ADCA,ADCB,ADCC sample event
        EPWM_enableADCTrigger(obj->pwmHandle[cnt], EPWM_SOC_A);//0
    
        // setup the Event Trigger Prescale Register (ETPS)
        if(numPWMTicksPerISRTick > 15)
        {
            EPWM_setInterruptEventCount(obj->pwmHandle[cnt], 15);//0
            EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt], EPWM_SOC_A, 15);//0
        }
        else if(numPWMTicksPerISRTick < 1)
        {
            EPWM_setInterruptEventCount(obj->pwmHandle[cnt], 1); //0
            EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt], EPWM_SOC_A, 1);//0
        }
        else
        {
            EPWM_setInterruptEventCount(obj->pwmHandle[cnt], numPWMTicksPerISRTick);//0,0
            EPWM_setADCTriggerEventPrescale(obj->pwmHandle[cnt],
                                            EPWM_SOC_A,
                                            numPWMTicksPerISRTick);
        }
    
        SysCtl_delay(10);
    
        // setup the Event Trigger Clear Register (ETCLR)
        EPWM_clearEventTriggerInterruptFlag(obj->pwmHandle[cnt]);//0
        EPWM_clearADCTriggerFlag(obj->pwmHandle[cnt], EPWM_SOC_A);//0
    
    
        // write value for ADC trigger (20KHz SOC_Int*5TBCTR=250µs, 1period=50µs)
        EPWM_setCounterCompareValue(obj->pwmHandle[cnt],
    								EPWM_COUNTER_COMPARE_D,
                                    5); //5
    
        // enable the ePWM module time base clock sync signal
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
    
        return;
    }  // end of HAL_setupPWMs() function
      

  • Matthew,

    Finally noticed SCIB RX FIFO is generating OV error on the 2nd Rx/Tx round robin every time. Error is only visible under CCS debug register view and not vectoring RX handler to read SCIB RX Error status register. That is why it seemed like the SCIB RX for loop locks up each 2nd time during TX/RX round robins.

    The code I wrote above checks the RX status register only if ePIE generates an IRQ in group 9 and actually vectors CPU into SCIB Rx IRQ handler. It appears group1 ADCA1 (13KHz IRQ rate) is keeping lower order core pends from vectoring only on a 2nd round robin. Only rarely do I get SCIAprintf() error 90. According to subject matter the ePIE interrupt vector control is not properly configured in TI examples. Below text Table 23.13; CCS debug Real Time Silicon emulation is not vectoring into SCIB INT9.3 to services the RX error event, a lower group priority than ADCA1 group 1. Perhaps why (for, while, SysCtldelay) loops behave oddly.   

    Part of the peripheral IRQ MASK and core priory order require a file, (DSP28_SWPrioritizedIsrLevels.h) left out of C2000 DSP folder, never being compiled with newer C2000 examples. Seemingly the ePIE silicon is passing un-restrained priority MASKED IRQ's up to the CPU. Oddly I am the only person on planet earth to report such insane ePIE peripheral behavior. 

    SCI overrun-error flag.
    The SCI sets this bit when a character is transferred into registers SCIRXEMU and SCIRXBUF before the previous character is fully read by the CPU or DMAC. The previous character is overwritten and lost. The OE flag bit is reset by an active SW RESET or by a system reset.
    Reset type: SYSRSn
    0h (R/W) = No overrun error detected
    1h (R/W) = Overrun error detected

        

  • Hi GI,

    Matt is out for the week so I will be helping in the meantime. Please give me some time to look into this and I will respond back by tomorrow.

    Best Regards,

    Marlyn

  • Why no comment of RX FIFO 10 bit not shown Fig.23.2 SPRUI33D – NOVEMBER 2015 – REVISED SEPTEMBER 2020? Is that a misprint?

    23.13 6. Buffers. Transmit and receive buffers are supplemented with two 16-level FIFOs. The transmit FIFO registers are 8 bits wide and receive FIFO registers are 10 bits wide.

    GI, the 10-bit receive FIFO will still only contain 8-bits of data, the extra 2 bits are to store extra information regarding errors.

    Part of the peripheral IRQ MASK and core priory order require a file, (DSP28_SWPrioritizedIsrLevels.h) left out of C2000 DSP folder, never being compiled with newer C2000 examples. Seemingly the ePIE silicon is passing un-restrained priority MASKED IRQ's up to the CPU. Oddly I am the only person on planet earth to report such insane ePIE peripheral behavior. 

    I need to consult with other team members on issues related to the ePIE. Please wait for a reply on this point.

    Best Regards,

    Marlyn

  • Hi Maryln,

    the 10-bit receive FIFO will still only contain 8-bits of data, the extra 2 bits are to store extra information regarding errors.

    Might that need to be add into the TRM SCI section as to stop confusion. Oddly the RX error codes below are more than two bits wide. Might explain RX error 90 and why RX FIFO locks up on the second round robin.

    /* Load the RX error status bits */
    ui32RxErrorStatus = (SCI_RXSTATUS_WAKE|SCI_RXSTATUS_PARITY |
    SCI_RXSTATUS_OVERRUN | SCI_RXSTATUS_FRAMING |
    SCI_RXSTATUS_BREAK|SCI_RXSTATUS_READY |
    SCI_RXSTATUS_ERROR);


    /* Get SCIB interrupt flag status */
    ui32IntStatus = SCI_getInterruptStatus(SCIB_BASE);

    /* Check interrupt Flags UARTICR bits RXINT */
    if(ui32IntStatus &SCI_INT_RXERR || ui32IntStatus &SCI_INT_FE ||
    ui32IntStatus &SCI_INT_OE || ui32IntStatus &SCI_INT_PE ||
    ui32IntStatus &SCI_INT_RXRDY_BRKDT)
    {
    /* Durring interrupt check the RSR/ECR register for
    * RX errors: OE, BE, PE, FE */
    if(ui32RxErrorStatus &= SCI_getRxStatus(SCIB_BASE))

    need to consult with other team members on issues related to the ePIE.

    In my other c2000 post FE thinks the header files are a CPU timer example for x49c, located on my computer [C:\ti\C2000Ware_3_04_00_00\driverlib\f28004x\examples\interrupt]. I don't believe the DSP28 file is an CPUtimer example.

  • Hi GI,

    Might that need to be add into the TRM SCI section as to stop confusion. Oddly the RX error codes below are more than two bits wide. Might explain RX error 90 and why RX FIFO locks up on the second round robin.

    Agreed, we can add more information within the TRM about the 10-bits. Not all error codes are stored within the 2-bits. I will reach out to our design team for more clarification on this. However, when you read the RX FIFO, you should still only be able to read the 8-bits of data. 

    In my other c2000 post FE thinks the header files are a CPU timer example for x49c, located on my computer [C:\ti\C2000Ware_3_04_00_00\driverlib\f28004x\examples\interrupt]. I don't believe the DSP28 file is an CPUtimer example.

    Can you please link the other post here?

    Best Regards,

    Marlyn

  • Part of the peripheral IRQ MASK and core priory order require a file, (DSP28_SWPrioritizedIsrLevels.h)

    Please check my understanding.

    • The project is using software prioritized interrupts.  i.e. it is allowing some interrupts to be interrupted using the scheme found in this example: C:\ti\c2000\C2000Ware_4_01_00_00\driverlib\f28004x\examples\interrupt
    • At some point, the code goes into an interrupt that is not expected.  (ADC1?) which is the first interrupt within group 1.

    If this is true, then I suggest checking the guidelines listed in this topic:

    In the Technical Reference Manual (TRM):

    • section 3.5.4.2 Handling Interrupts
    • section 3.5.4.3 Disabling Interrupts
    • And very importantly 3.5.4.4 Nesting Interrupts

    For the last section there is detailed information here: https://software-dl.ti.com/C2000/docs/c28x_interrupt_nesting/html/index.html

    If the guidelines for modifying the PIEIER registers is not followed then the CPU can take the first interrupt within a PIE group.

    Specifically:

    If I've misunderstood the issue, please let me know.  

    Regards,

    Lori

  • If the guidelines for modifying the PIEIER registers is not followed then the CPU can take the first interrupt within a PIE group.

    Specifically:

    Yet there are no nested interrupts in my code and ADCA1 (Instaspin ISR) is running over lower built in ePIE peripheral core priority order group 9.  That is bad silicon behavior, guessing group 1 core priority PIEIER switch is locked in the set state. That explains why lower core priority ePIE pends do not wait for built in higher core priority Interrupts and seem to ignore group clear ACK's. My SW modification of PIEIER or masking INTx.x within same group should not even be required, since there is no nesting within my ISR groups.

    The R3 silicon needs review prior to returning to production runs. The ePIE behavior goes against TRM section of peripheral core priority and the example of CPU Timers and no nesting INTx.x within the same group CPU Timer 0. Yet CPU Timer1 and Timer 2 are not ePIE interrupts so Interrupt.c example is nonsense. The other example I2C, SPI, SCIA core priority ePIE order does NOT interact with INTx.x of group 1, why not? It would behoove TI support to test x49c group 1 PIEIER extensively as I have.

  • GI, 

    Thank you for the reply. 

    My SW modification of PIEIER or masking INTx.x within same group should not even be required, since there is no nesting within my ISR groups.

    I am confused.  Why is there modification of PIEIER registers and masking at the CPU level if nested interrupts are not needed?

    The other example I2C, SPI, SCIA core priority ePIE order does NOT interact with INTx.x of group 1, why not?

    Most of our examples do not nest interrupts.  If nesting is not needed then there is no reason to modify other 1 enables.

    I apologize if this has already been discussed.  If we can get a simple example that shows the issue it would help. 

    My understanding now is:

    • You are not software nesting interrupts
    • Somehow the code ends up in an unexpected interrupt (ADC1?)   

    Is this correct?

    Regards

    Lori

  • I am confused.  Why is there modification of PIEIER registers and masking at the CPU level if nested interrupts are not needed?

    Indeed why should that even be required if GroupN core priorities pending states are actually being cleared by driverlib calls to ePIE. I first attempted to nest Group1 ADCA1 with CPU Timer0, ADCA1 was being overrun. Alternatively disabled Timer 0 and used SCIB ISR to call the serial data export from TX-FIFO. It also could indicate the object code Lab07 (below) does not actually clear ACK ADCA1 PIEIER core priority, inferring compiler is not linking the handle to the ADCA1 base address.   

    So both methods are failing to clear ACK ADCA1 ISR prior to ePIE un-pending SCIB ISR, hence an IRQ over-run occurs via slower ISR of SCIB. As a result (for, while, SysCtldelay) loops behave erratically in both ISR's. Where SCIAprintf() was being asserted prior to said loop counts ever being matched likely dire to ISR overruns. 

    // Acknowledge interrupt from PIE group 9
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    //
    // Instaspin motor contrlo SDK Lab07 acknowledge the ADC interrupt
    //
    HAL_ackADCInt(halHandle, ADC_INT_NUMBER1);

    // **************************************************************************
    // the function prototypes

    //! \brief Acknowledges an interrupt from the ADC so that another ADC
    //! interrupt can happen again.
    //! \param[in] handle The hardware abstraction layer (HAL) handle
    //! \param[in] adcIntNum The interrupt number
    static inline void
    HAL_ackADCInt(HAL_Handle handle,const ADC_IntNumber adcIntNum)
    {
    HAL_Obj *obj = (HAL_Obj *)handle;

    #if (BOOST_to_LPD == BOOSTX_to_J5_J6)
    // clear the ADCA interrupt flag
    // BoostXL-8320RS ADCC1 J7-pin66, DC inverter ADCA1 J3-pin30
    ADC_clearInterruptStatus(obj->adcHandle[0], adcIntNum); // ADCC/RC2

    // Acknowledge interrupt from PIE group 1
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);

  • // Acknowledge interrupt from PIE group 9
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    When an interrupt is taken, the ACK from that group is set.  This will hold off interrupts from that group until ACK is cleared.  This is typically done at the end of an ISR in group9.  Note that it does not clear any flags in the peripheral or otherwise except for ACK.

    It is shown here outside of an ISR.  Not sure if that was your intent.

    does not actually clear ACK ADCA1 PIEIER core priority, inferring compiler is not linking the handle to the ADCA1 base address.

    ACK and PIEIER are two different registers.  Neither are in the ADC register base. They are both in the PIE registers. 

    So both methods are failing to clear ACK ADCA1 ISR prior to ePIE un-pending SCIB ISR, hence an IRQ over-run occurs via slower ISR of SCIB

    It sounds like the rate of interrupts coming in on group 1 is such that it blocks lower interrupts.  This doesn't mean ACK wasn't cleared but instead it was reset immediately after being cleared in order to take the pending interrupt.  Does the ADC ISR actually exit before another group 1 interrupt is flagged?

    The C2000 Academy includes a module related to interrupts.  You can find it here - refer to module 3, deep dive, interrupts.

    https://dev.ti.com/tirex/explore/node?node=AShlIdPSbbegVCNX9MVcSw__jEBbtmC__LATEST

  • It is shown here outside of an ISR.  Not sure if that was your intent.

    It was assumed you understood there are two ISR's each with _interrupt(void). So the compiler should be inserting (ireturns) bottom each ISR. Though SCIB RX INT9.3 checks for errors and does early Clear ACK return from ISR, prior to going further into the ISR it exists. The C2000 compiler does not seem to add (ireturn) in the error check subroutine to replace the early (return) statement.

    Does the ADC ISR actually exit before another group 1 interrupt is flagged?

    No there are only two interrupts ADCA1 INT1.1 and SCIB INT9.4 that assert in round robin. SCIB RX INT9.3 is configured and enabled but only occurs when TX INT9.4 is not active. 

    It sounds like the rate of interrupts coming in on group 1 is such that it blocks lower interrupts

    Actually in CCS debug register view ADCA1 ACK is randomly toggling but SCIB ACK bit is staying 0x0100 it never toggles clear. That seems to explain how SCIB being 30ms ISR overruns faster ADCA1 125µs. Even configuring ADCA1 for 375µs ISR made no difference other than SCIB over runs slow down. 

  • The C2000 Academy includes a module related to interrupts.  You can find it here - refer to module 3, deep dive, interrupts.

    Interrupt_initModule(); Interrupt_initVectorTable();

    Above functions are external exports inside (interrupt.h) of the motor control SDK driverlib folder but are not being linked to any such function. That is if you hover over the call, hold CTRL key then click on the function name CCS9.3 IDE only brings up interrupt.h file. If you then do the same hover hold CTRL click on either export name (interrupt.h) nothing happens. Since (pievect.c) is not being modified by registering these two ISR's there is no way to determine if ePIE vector table was actually modified for the driverlib call after registering both ISR's. Hence, both ISR's appear to be running wild horses without a corral. 

    interrupt.h calls:

    //*****************************************************************************
    //
    //! Initializes the PIE control registers by setting them to a known state.
    //!
    //! This function initializes the PIE control registers. After globally
    //! disabling interrupts and enabling the PIE, it clears all of the PIE
    //! interrupt enable bits and interrupt flags.
    //!
    //! \return None.
    //
    //*****************************************************************************
    extern void
    Interrupt_initModule(void);

    //*****************************************************************************
    //
    //! Initializes the PIE vector table by setting all vectors to a default
    //! handler function.
    //!
    //! \return None.
    //
    //*****************************************************************************
    extern void
    Interrupt_initVectorTable(void);

  • So the compiler should be inserting (ireturns) bottom each ISR.
    The C2000 compiler does not seem to add (ireturn) in the error check subroutine to replace the early (return) statement.

    Thank you for the clarification.  For the interrupt return (IRET instruction) - will be visible in the disassembly window .  The compiler doesn't insert it into the .c source. 

    assert in round robin

    I think you are referring to the source of the interrupt - but I do want to make sure it is clear so we are on the same page. The PIE itself won't service interrupts in a round robin fashion.  Highest enabled interrupt will be serviced first.  

    Actually in CCS debug register view ADCA1 ACK is randomly toggling but SCIB ACK bit is staying 0x0100 it never toggles clear.

    There is a refresh rate associated with the display - so often a brief change may not be observed.  If I want to see how often an ISR is serviced then I will use a GPIO pin toggle in that ISR (ex: high at the start, low at the end) and view it on a oscilloscope.   If ACK is never cleared there will only be one interrupt.  If it is cleared then you will see the toggle for each.  This will also allow you to observe the execution timing as it relates to the ADC interrupt. 

    It does sound like a timing problem.  If the SCI interrupt is very long it will block the faster ADC interrupt.  If the ADC interrupt needs to interrupt the SCIB then the nesting interrupt software scheme should be implemented. 

  • If the ADC interrupt needs to interrupt the SCIB then the nesting interrupt software scheme should be implemented. 

    No it only gets the ADC data that was pervious sample to export via SCIB to serial display LCD. SCIB is in group9 there is no nesting only core priority order between the two groups 1 & 9.

    If I want to see how often an ISR is serviced then I will use a GPIO pin toggle in that ISR (ex: high at the start, low at the end) and view it on a oscilloscope

    It seems like the vector table was not modified and the ISR are not registered though they are enabled PIEIFRn are not toggling debug register view and PIEIFR7 0x8000 has not even been configured. If the vector table is not actually configured with the two registered ISR's ePIE would not be setting the PIEIFRn bits. The ISR might appear to work but the peripheral core priority order would not be constrained by clear ACK's.    

  • there is no way to determine if ePIE vector table was actually modified for the driverlib call after registering both ISR's

    The PIE interrupt vector table can be viewed in the memory window to confirm it is setup correctly.

  • Hi Lori,

    Working Saturday is not just for mowing the lawn anymore Joy.

    I captured a more useful decimation of both groups. Notice SCIB is invading ADCA1 as it seems to be more than a single 125-250µs cycle. Each commutation period of Instaspin is defined user.h for 5 CMPD period counts of 50µs or 250µs/2 = 125µs each red pulse. Somehow Instaspin is out of sync with ADC interrupts like the priority of ADCA1 is being ignored at times.

    The PIE interrupt vector table can be viewed in the memory window to confirm it is setup correctly.

    ADCA1 INT1 is memory mapped as TRM 3.5.6 Table 3.4 as Segment: 0x0000.0D02: offset: DE0B.99CA 03C5.904F.

    SCIB INT9 is not being mapped, Segment 0x0000.0D12: offset: 0008.33A8  0008.33A8. Oddly EMUINT 17 0x0000.0D22 2 CPU Emulation Interrupt is mapped likely for debug interrupt.

       

  • Seemingly the call used to register PIE interrupt handlers is doing something odd. Using the HEX calculator to express the register function (below) INT2.x TZ is being registered for ePWM group2 seemingly as the vector for SCIB INT9.4 handler. Trip zone INT might explain CH1, 25µs wide pulses that should be minimum of 125µs wide. Yet ePWM module is not configured for trip zone INT's, rather OSHT trip event. And how SCIB 30ms wide pulse (CH2 decimation) invades Instaspin (CH1 decimation) times prior to Clear ACK that should be 3x ISR ticks 125µs. The ePWM is configured to force an OSHT trip event or else clears all TZ flags, including TZ interrupt sources prior to Instaspin runtime. 

    // enable debug events
    ERTM;

    Debug Emulation is registered differently: #define  ERTM   __asm(" clrc DBGM")

      

  • I captured a more useful decimation of both groups. Notice SCIB is invading ADCA1 as it seems to be more than a single 125-250µs cycle. Each commutation period of Instaspin is defined user.h for 5 CMPD period counts of 50µs or 250µs/2 = 125µs each red pulse. Somehow Instaspin is out of sync with ADC interrupts like the priority of ADCA1 is being ignored at times.

    Lets go back to SW nesting vs not nesting - to make sure we are on the same page:

    Without interrupt nesting:

    • SCIB ISR is asserted
    • hardware disables interrupts
    • ADC1 will be ignored, even though it has a higher priority, until SCIB ISR completes. 
    • When the SCIB ISR completes, are re-enabled by the context restore, highest flag interrupt will be taken

    With interrupt nesting

    • SCIB ISR is asserted
    • hardware disables interrupts
    • user re-enables interrupts using the nesting scheme
    • ADC1 ISR can be taken and interrupts the SCIB ISR
    • ADC1 ISR completes
    • SCIB completes, interrupts are re-enabled by the context restore, highest flag interrupt will be taken
  • The highlighted vector is not used.  It is likely populated with the default ISR for debug purposes. Refer to this table in the Technical Reference Manual.

    SCIB RX and TX vectors are found in group 9, memory address 0xDC4, oxDC6

    The address of the interrupt service routine(s) can be found in the linker generated .map file.  This can be checked against what is loaded into the PIE vector table.  Alternatively you can place a breakpoint in the ISR, run and once you are there, check the address. 

    Regards

    Lori

  • The address of the interrupt service routine(s) can be found in the linker generated .map file.

    So the one printed above was not used and further down memory was group 9. I used the other dot method to register all the interrupts. Yet ADCA1 was still being interrupted by SCIB TX INT in the middle of commutation when there is so much free time on either side of Instaspin ISR pulses. Curious that I thought Group9 address (0x0000.0d12) was needed for the peripheral core vector 13 being un-nested. Seemingly Group 9 INT9.4 (30ms) priority 13 should be chopped up not ADCA1 INT1.1 priority (5).

    Again the automated peripheral core priorities 13 and 5 are not working, so the CPU has no perception of priority order. 

    Somehow Instaspin decimation time is not consistent with documented behavior for the number of ISR ticks to trigger ADCA1 EOC pulse interrupt. Perhaps priority 5 is being lost due to much faster 25µs run time decimation of ADCA1. 

    Without interrupt nesting:

    • SCIB ISR is asserted
    • hardware disables interrupts
    • ADC1 will be ignored, even though it has a higher priority, until SCIB ISR completes. 
    • When the SCIB ISR completes, are re-enabled by the context restore, highest flag interrupt will be taken

    Hardware disables via DINT/EINT on exit made no difference to stop over runs of INT1.1 by INT9.4. Point again (without nesting) the peripheral core priority order 5 and 13, PIE controls the interrupts according to TRM 3.5.6 Table 3-5. In effect you are suggesting there are no peripheral core priorities shown in these tables. The TRM section on PIE seems to scrub out peripheral priority behavior for silicon defects rather than fixing them in Rev1 silicon.

  • The PIE interrupt priority is basically:

    • If more than one interrupt is pending within the PIE at any time, when interrupts are enabled (INTM, IER, PIEIERx) then the vector corresponding to the highest priority enabled interrupt will be passed to the CPU by the PIE.  

    Therefore without nesting:

    • PIE interrupt 5.1 is flagged and enabled
    • A cycle later PIE interrupt 3.2 is flagged and enabled
    • CPU receives interrupt request and asks the PIE for a vector
    • PIE interrupt 3.2 has priority and is given to the CPU
    • CPU executes ISR for 3.2 
    • PIE 1.2 is flagged and enabled while CPU is busy with 3.2  (no nesting so 1.2 is not taken at this time)
    • CPU finishes interrupt 3.2, receives a new interrupt request and asks the PIE for a vector
    • PIE interrupt 1.2 has priority and is given to the CPU
    • etc
    The TRM section on PIE seems to scrub out peripheral priority behavior for silicon defects rather than fixing them in Rev1 silicon.

    So far I've not seen anything described in the tread to point to a defect?  Is this something in the errata?

  • CPU finishes interrupt 3.2, receives a new interrupt request and asks the PIE for a vector

    Where are INT5.1, INT3.2, INT1.2 ever being mentioned in this thread. PIE peripheral Core priorities (5) and (13) are not functional at all. The PIE controller is absolutely defective or C2000 compiler has failed to include code for controlling peripheral core priority order over these two groups. The x49c PIE is so dysfunctional it even truncates INT1.1 decimation time 150µs->25µs before it ever receives Clear ACK group1. During idle INT1.1 decimation drops down to 5µs when the EPWM trigger is configured for 250µs/2 by way of (50MHz PWM clock) interval drives INT1.1 ISR time. 

    The x49c MCU cannot properly handle two interrupts as TM4C ARM cortex NVIC handles the same basic code INT9.4 (40ms Intervals drives 1.2sec UART serial data stream), INT1.1 (330µs) including (12 ISR's) without any of these issues. That is not a promotion for x49c interrupt controller. After more than a month of trying to get PIE to handle two simple interrupts, it simply refuses to behave no matter what control code is being added to software. That is the end of this thread, reads more like an Xfile though Moulder and Skully never came to the rescue. 

  • Where are INT5.1, INT3.2, INT1.2 ever being mentioned in this thread. PIE peripheral Core priorities (5) and (13) are not functional at all.

    This was only a made up example to explain how the PIE priorities work without software nesting. 

    The x49c PIE is so dysfunctional it even truncates INT1.1 decimation time 150µs->25µs before it ever receives Clear ACK group1. During idle INT1.1 decimation drops down to 5µs when the EPWM trigger is configured for 250µs/2 by way of (50MHz PWM clock) interval drives INT1.1 ISR time.

    A timing diagram or a simple example would help this discussion.  

    The x49c MCU cannot properly handle two interrupts as TM4C ARM cortex NVIC

    The PIE was designed many years ago and I agree it does not have the same features as NVIC.  None of our documentation claims that it behaves as the NVIC.  For the PIE, if an interrupt is expected to be taken during another interrupt the SW nesting scheme must be used by the developer. 

    Regards

    Lori 

  • For the PIE, if an interrupt is expected to be taken during another interrupt the SW nesting scheme must be used by the developer.

    Here again two different groups and interrupts are not defined by the word nesting. Yet peripheral core priorities are defined as PIE constraints in the TRM tables. It's not the first-time silicon botches have entered into production though it seems the compiler should be pushing more on the stack than it does!

    The ADC SOC is being triggered by EPWM SOCA match counts via CMPD that are way under the actual period being configured. This is another issue that is affecting both ISR's.

    LAUNCHXL-F280049C: EPWM ADC SOCA trigger counts fail. - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

  • Here again two different groups and interrupts are not defined by the word nesting. Yet peripheral core priorities are defined as PIE constraints in the TRM tables.

    The behavior of the PIE matches the documentation as far as I see.  If you have a specific instance where it does not please let me know so I can get it fixed. 

    the compiler should be pushing more on the stack than it does!

    If you have a case where the compiler has not stored off a register it should, please provide more detail.   

  • There is more going on than just EPIE being dysfunctional peripheral core priority order control. The odd part being there is very little CPU execution time for SCIB or any other peripheral ISR with Instaspin decimation pulse period 5µs to 25µs. EPWM Timebase Submodule is not resetting for CMPD match counts used to trigger ADC module ISR times for Instaspin.

    TMS320F280049C: ePIE core priority groups Instaspin SDK (FOC) - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

  • Thank you for opening new threads with the new topics.  I will go ahead and close this thread.  

    Best regards

    Lori