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.

RM44L520: SPI Slave DMA interrupt stuck

Part Number: RM44L520
Other Parts Discussed in Thread: HALCOGEN

Hi Team

Hope you are doing good.

I have a very strange problem which i m not able to solve. I would be very grateful to you if you could please help me solving the same quickly as it is really very urgent for the project.

I have implemented a SPI slave DMA interrupt on RM44L520. 

Everytime the master sends the data, the interrupt is triggered which is what i expected. 

The problem is... when the master is not sending any data, the slave is stuck at following statement and never exits from here. i am clueless why is this happening.

(*pf_irqFunc)();   /* Execute interrupt routine */

This statement is part of following function

void irqHandler(uint32_t u32VectorIrqIndex)
{
    t_isrFuncPTR pf_irqFunc = NULL; /* Assign Null address */
    /* Check IrqVector Range */
    if ((u32VectorIrqIndex > (uint32_t)0U) && (u32VectorIrqIndex <= U32_VIM_CHAN_MAX) /* index is valid */)
	{
        pf_irqFunc = vimRAM->ISR[u32VectorIrqIndex]; /* Read IRQ Interrupt Vector */

        /* Save VIM REQENASET[0,1,2,3] Registers for later restore */
        uint32 u32BckupREQMASKSET0 = vimREG->REQMASKSET0;
        uint32 u32BckupREQMASKSET1 = vimREG->REQMASKSET1;
        uint32 u32BckupREQMASKSET2 = vimREG->REQMASKSET2;
        uint32 u32BckupREQMASKSET3 = vimREG->REQMASKSET3;

        /* Mask out lower priority IRQs depending on IRQ index */
        if(U32_VIM_CHAN3_OFFSET < u32VectorIrqIndex) /* Channel 97-127*/
        {
            vimREG->REQMASKCLR3 = ((U32_REG_CLRMASK << (u32VectorIrqIndex - 97U)) & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
        }
        else if (U32_VIM_CHAN2_OFFSET < u32VectorIrqIndex) /* Channel 64-96 */
        {
            vimREG->REQMASKCLR2 = ((U32_REG_CLRMASK << (U32_CHAN_REG2_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                                               & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
        }
        else if (U32_VIM_CHAN1_OFFSET < u32VectorIrqIndex) /* Channel 32-63 */
        {
            vimREG->REQMASKCLR1 = ((U32_REG_CLRMASK << (U32_CHAN_REG1_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR1));
            vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
        }
        else if (U32_VIM_CHAN0_OFFSET < u32VectorIrqIndex) /* Channel 2-31 */
        {
            vimREG->REQMASKCLR0 = ((U32_REG_CLRMASK << (U32_CHAN_REG0_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR0));
            vimREG->REQMASKCLR1 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR1));
            vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;

        }
        else    /* FIQ is not executed in this context*/
        {
        	ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
        }


        _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */

        (*pf_irqFunc)();   /* Execute interrupt routine */

        _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */

        /* Restore VIM REQENASET[0,1,2,3] Registers */
        vimREG->REQMASKSET0 = u32BckupREQMASKSET0;
        vimREG->REQMASKSET1 = u32BckupREQMASKSET1;
        vimREG->REQMASKSET2 = u32BckupREQMASKSET2;
        vimREG->REQMASKSET3 = u32BckupREQMASKSET3;

	}
	else /*index is not valid */
	{
		ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
	}
}

and the function pointer itself points to..

/* SourceId : DMA_SourceId_019 */
/* DesignId : DMA_DesignId_016 */
/* Requirements: HL_SR181, HL_SR182 */
void dmaBTCAInterrupt(void)
{
    uint32 offset = dmaREG->BTCAOFFSET;

/* USER CODE BEGIN (6) */
/* USER CODE END */

    if (offset != 0U)
    {
        dmaGroupANotification(BTC, offset - 1U);
    }

/* USER CODE BEGIN (7) */
/* USER CODE END */

}

Kindly let me know if you need any other information on this.

Thank you and have a lovely day..

  • Hello,

    Nested interrupt is strongly not recommended for safety application. In ARM Cortex-R devices, the CPU will automatically disable IRQ as soon as it enters in IRQ mode to avoid nested IRQ. 

    In most cases, nested interrupts are not required. Interrupt service routines (ISR) should be short and only perform highly time critical tasks. Extensive computations should be left for the main routine perhaps with a flag set in the ISR to notify the main loop of new data to process.

  • Hi

    Thanks for your reply

    I dont have any nested interrupt. When the master is not sending any data there is no way interrupt is triggered again

    Please look at the following image and comments in RED, i executed the code step by step with breakpoints to make it clear. I hope i am able to clarify my question. Please let me know if you have any question. 

  • In your previous code, the IRQ is re-enabled and disabled in the IRQ interrupt service routine:

    void irqHandler(uint32_t u32VectorIrqIndex)

    {

        ........

        _enable_IRQ(); /* Enable IRQ, to allow preemption of IRQ routine */

        (*pf_irqFunc)(); /* Execute interrupt routine */

        _disable_IRQ(); /* Disable IRQ, to protect the remainder of the dispatcher from preemption */

       ......

    }

  • The irqHandler(uint32_t u32VectorIrqIndex) is example code in spna219 application note. The ARM Cortex-R4/5 (TMS570, RX4x/5x) core does not support more than one IRQ to be taken at a time. This example is to implement a reentrant IRQ handler with SW.

    Please use the SPI interrupt service routine generated through HALCOGen for your application.

  • Thankyou so much for your inputs.

    At the moment only one interrupt is enabled and that too is triggered only one time as the master is only sending one packet, Could you give me the reason why we are not exiting the irqHandler() function? and why we  always stuck at (*pf_irqFunc)();

    i verifiled by putting a breakpoint at the enterance of the irqHandler() function that the interrupt is triggered only once. 

    Again Thanks a lot.

  • Hello,

    The device supports Hardware vectored interrupts (IRQ only). If this feature is enabled, after one IRQ is received by the CPU, CPU reads the address of ISR directly from the interface with VIC port instead of branching to 0x18 (irqHandler in your case). The CPU will branch directly to the ISR.

    Is VIC enabled in your code? VIC is enabled by calling HAL generated API: 

      /* Enable IRQ offset via Vic controller */
    _coreEnableIrqVicOffset_();

    Using irqHandler may require more stack size. Can you please try bigger stack size?

    Which SPI is used in your code? 

  • Thanks for your inputs and sorry for my late reply as i was trying to see the acutal cause

    Following is the answer to your questions

    1) _coreEnableIrqVicOffset_() is not being called from anywhere

    2) As shown int the figure in my previous post the function for time being is empty and hence it is not the problem of stack.

    what i figure out is following:

    From the following dispatcher

    void irqHandler(uint32_t u32VectorIrqIndex)
    {
        t_isrFuncPTR pf_irqFunc = NULL; /* Assign Null address */
        /* Check IrqVector Range */
        if ((u32VectorIrqIndex > (uint32_t)0U) && (u32VectorIrqIndex <= U32_VIM_CHAN_MAX) /* index is valid */)
    	{
            pf_irqFunc = vimRAM->ISR[u32VectorIrqIndex]; /* Read IRQ Interrupt Vector */
    
            /* Save VIM REQENASET[0,1,2,3] Registers for later restore */
            uint32 u32BckupREQMASKSET0 = vimREG->REQMASKSET0;
            uint32 u32BckupREQMASKSET1 = vimREG->REQMASKSET1;
            uint32 u32BckupREQMASKSET2 = vimREG->REQMASKSET2;
            uint32 u32BckupREQMASKSET3 = vimREG->REQMASKSET3;
    
            /* Mask out lower priority IRQs depending on IRQ index */
            if(U32_VIM_CHAN3_OFFSET < u32VectorIrqIndex) /* Channel 97-127*/
            {
                vimREG->REQMASKCLR3 = ((U32_REG_CLRMASK << (u32VectorIrqIndex - 97U)) & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            }
            else if (U32_VIM_CHAN2_OFFSET < u32VectorIrqIndex) /* Channel 64-96 */
            {
                vimREG->REQMASKCLR2 = ((U32_REG_CLRMASK << (U32_CHAN_REG2_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                                               & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
            }
            else if (U32_VIM_CHAN1_OFFSET < u32VectorIrqIndex) /* Channel 32-63 */
            {
                vimREG->REQMASKCLR1 = ((U32_REG_CLRMASK << (U32_CHAN_REG1_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR1));
                vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
            }
            else if (U32_VIM_CHAN0_OFFSET < u32VectorIrqIndex) /* Channel 2-31 */
            {
                vimREG->REQMASKCLR0 = ((U32_REG_CLRMASK << (U32_CHAN_REG0_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR0));
                vimREG->REQMASKCLR1 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR1));
                vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
    
            }
            else    /* FIQ is not executed in this context*/
            {
            	ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
            }
    
    
            _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */
    
            (*pf_irqFunc)();   /* Execute interrupt routine */
    
            _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */
    
            /* Restore VIM REQENASET[0,1,2,3] Registers */
            vimREG->REQMASKSET0 = u32BckupREQMASKSET0;
            vimREG->REQMASKSET1 = u32BckupREQMASKSET1;
            vimREG->REQMASKSET2 = u32BckupREQMASKSET2;
            vimREG->REQMASKSET3 = u32BckupREQMASKSET3;
    
    	}
    	else /*index is not valid */
    	{
    		ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
    	}
    }

    at following line

    (*pf_irqFunc)();   /* Execute interrupt routine */

    Following function is called

    #pragma CODE_STATE(dmaBTCAInterrupt, 32)
    #pragma INTERRUPT(dmaBTCAInterrupt, IRQ)
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;
    
    /* USER CODE BEGIN (6) */
    /* USER CODE END */
    
        if (offset != 0U)
        {
            dmaGroupANotification(BTC, offset - 1U);
        }
    
    /* USER CODE BEGIN (7) */
    /* USER CODE END */
    
    }

    Since the dmaBTCAInterrupt function is an interrupt function, the compiler is adding following instruction at the end of function

    SUB     lr, lr, #4

    Due to this instruction instead of going to the next instruction of  _disable_IRQ();  in following code, its again going to (*pf_irqFunc)();

     _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */
    
            (*pf_irqFunc)();   /* Execute interrupt routine */
    
            _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */
     

    So what i did is, i made the dmaBTCAInterrupt() function as normal function by commenting following on the top of the function.

    //#pragma CODE_STATE(dmaBTCAInterrupt, 32)
    //#pragma INTERRUPT(dmaBTCAInterrupt, IRQ)

    It seems to be working, but i am not sure would it be the right way to do or not, Could you please guide me.

    Again thankyou so much for your time and support.

    Have a lovely day ahead.

  • It seems to be working, but i am not sure would it be the right way to do or not, Could you please guide me.

    If dmaBTCAInterrupt() is to be called from a different function, rather as an IRQ, then it is correct for it to be defined as a "normal" function, i.e. without the INTERRUPT pragma.

    Looking at the dmaBTCAInterrupt() functions generated by HALCoGen 04.07.01 it is sensitive to the state of the Interrupt Configuration. With the IRQ set to "Vector Mode":

    Then the generated code was had the pragmas for an IRQ handler:

    /** @fn void dmaBTCAInterrupt(void)
    *   @brief DMA Interrupt Handler
    *
    *   Frame transfer complete Interrupt handler for DMA channel routed to Group A
    *
    */
    #pragma CODE_STATE(dmaBTCAInterrupt, 32)
    #pragma INTERRUPT(dmaBTCAInterrupt, IRQ)
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;
    

    If the IRQ was changed to "Dispatch Mode" then the generated code was a normal function:

    /** @fn void dmaBTCAInterrupt(void)
    *   @brief DMA Interrupt Handler
    *
    *   Frame transfer complete Interrupt handler for DMA channel routed to Group A
    *
    */
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;