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.

TMS320F280025: CAN interrupt generation for message objects

Part Number: TMS320F280025

Hi all,

I am unsure about how the CAN interrupt works if there are more than one message objects are marked for interrupt. Unfortunately all CAN samples are quite simplistic with only one message object per direction.

We have disable interrupts in our program flow, so it can happen than the interrupt routine for CAN0INT will be serviced after multiple message objects were sent. In the service routine the flags for the latest object (interrupt cause INT0ID) and the service routine are cleared:

    CAN_clearInterruptStatus(CANIF_CAN_BASE, intCause);

    CAN_clearGlobalInterruptStatus(CANIF_CAN_BASE, CAN_GLOBAL_INT_CANINT0);
    
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

Is it then expected that the ISR will be called again, as other message object will keep CAN0INT high? Or do we need to loop until INT0ID return 0?
I would expect the ISR to be called again according to Figure 3-2. Interrupt Propagation Path and Figure 21-8. CAN Interrupt Topology 2 (both in tech ref of F28002x).

Thanks a lot,

Andreas

  • Hi Andreas,

    You are correct.  The CAN examples only use one receive and one transmit message object and the ISR is shown only to service one of these objects at a time.  You can however expand the example to use all 32 message objects and these can be a combination or receive or transmit objects.  There are two interrupt lines to use.  Either you can choose INT0ID or INT1ID line.  The examples use INT01D line,  If you look up the definition of CAN_INT register, INT1ID will display interrupt causes from each of the 32 mailboxes.  INT0ID will display the interrupt cause from each of the 32 mailboxes as well as error and status register.

    All the examples use INT0ID so they both trigger an ISR whenever there are messages received that match the mailbox definition as well as when status and error flags have been triggered.  If you want message objects to trigger INT01D line, you need to specify this in the object creation, for instance:

    	#define MSGOBJ0		0
    	#define MSGOBJ1		1
    	#define MSGOBJ2		2
    	#define MSGOBJ3		3
    	:
    	:
    	:
    	#define MSGOBJ29	29
    	#define MSGOBJ30	30
    	#define MSGOBJ32	31
    	
        CAN_setupMessageObject(CANA_BASE, MSGOBJ0, 0x12345,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
        CAN_setupMessageObject(CANA_BASE, MSGOBJ1, 0x23456,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
        CAN_setupMessageObject(CANA_BASE, MSGOBJ2, 0x789AB,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
    						   :
    						   :
    	CAN_setupMessageObject(CANA_BASE, MSGOBJ29, 0x789AB,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_TX, 0,
                               CAN_MSG_OBJ_TX_INT_ENABLE, MSG_DATA_LENGTH);
    

    In your CAN ISR, you can service the interrupts as follows:

        //
        // Read the CAN-B interrupt status to find the cause of the interrupt
        //
        status = CAN_getInterruptCause(CANA_BASE);
    	
    	if(status == MSGOBJ0)
    	{
            //
            // Get the received message
            //
            CAN_readMessage(CANA_BASE, MSGOBJ0, rxMsgData1);
    
            //
            // Getting to this point means that the RX interrupt occurred on
            // message object 1, and the message RX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANA_BASE, MSGOBJ0);	
    	}
    	if(status == MSGOBJ1)
    	{
            //
            // Get the received message
            //
            CAN_readMessage(CANA_BASE, MSGOBJ1, rxMsgData2);
    
            //
            // Getting to this point means that the RX interrupt occurred on
            // message object 1, and the message RX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANA_BASE, MSGOBJ1);		
    	}
    	if(status == MSGOBJ2)
    	{
            //
            // Get the received message
            //
            CAN_readMessage(CANA_BASE, MSGOBJ2, rxMsgData3);
    
            //
            // Getting to this point means that the RX interrupt occurred on
            // message object 1, and the message RX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANA_BASE, MSGOBJ2);		
    	}
    	
    	//
        // Clear the global interrupt flag for the CAN interrupt line
        //
        CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
    
        //
        // Acknowledge this interrupt located in group 9
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    

    The ISR will be called each time a matching CAN message that qualifies the definition of any of the message object is received.

    Hope above example clarifies how message objects and interrupts are handles.

    Best regards,

    Joseph

  • Thank you for you reply, Joseph.

    This part we've got basically already working.

    As you said, the ISR will be called each time a message object is received or sent. In our case, we are just sending messages. Regarding the behaviour of INT0ID ("interrupt cause") it is stated:

    If several interrupts are pending, the CAN Interrupt Register will point
    to the pending interrupt with the highest priority.
    Note: The CANINT0 interrupt line remains active until INT0ID
    reaches value 0 (the cause of the interrupt is reset) or until IE0 is
    cleared.

    In our case, this can happen, as we must disable interrupts globally for some other code of our application, so multiple message object will complete being sent on the CAN bus during interrupts being disabled.

    As you see above, we are not clearing IE0, so CANINT0 should remain active.

    We are observing, that if we only read and clear one object ("interrupt cause") in the ISR - as you do aswell with CAN_clearInterruptStatus - that the interrupt will not be called again, although CAN0INT should remain active because there are still message objects present that have "Transmit OK" set.

    Is this behaviour expected? Does CAN0INT needs to have a rising edge to actually trigger the interrupt? I didn't find anything about that in the documentation.
    Of course, another option is to loop in the interrupt routine until INT0ID is zero.

    Overall, I would like to know what is exactly (not) happening so I understand the implications when implementing any possible solution.

    Thank you,
    Andreas

  • Hi Andreas,

    Sorry, I missed the part where you are just sending messages.  In that case, when defining the transmit message object, you do not have to enable the interrupt so when message it sent, code will not go to the ISR.  This way there would be no need to clear the interrupt flags.  Example code below:

    	#define MSGOBJ0		0
    	#define MSGOBJ1		1
    	#define MSGOBJ2		2
    	#define MSGOBJ3		3
    	:
    	:
    	:
    	#define MSGOBJ29	29
    	#define MSGOBJ30	30
    	#define MSGOBJ32	31
    	
        CAN_setupMessageObject(CANA_BASE, MSGOBJ0, 0x12345,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
        CAN_setupMessageObject(CANA_BASE, MSGOBJ1, 0x23456,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
        CAN_setupMessageObject(CANA_BASE, MSGOBJ2, 0x789AB,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_RX, 0,
                               CAN_MSG_OBJ_RX_INT_ENABLE, MSG_DATA_LENGTH);
    						   :
    						   :
    	CAN_setupMessageObject(CANA_BASE, MSGOBJ29, 0x789AB,
                               CAN_MSG_FRAME_EXT, CAN_MSG_OBJ_TYPE_TX, 0,
                               CAN_MSG_OBJ_NO_FLAGS, MSG_DATA_LENGTH);

    Transmit message object MSGOBJ29 definition uses CAN_MSG_OBJ_NO_FLAGS which means that sending this object will not trigger the interrupt and will not go into ISR to be serviced and cleared of the flags and acknowledged.  CANITN0 interrupt line is still active and can be triggered by message objects that will use it.

    Let me know if this will work for you.

    Regards,

    Joseph

  • Hi Joseph,

    we do want to be notified on a successful transmit of all message objects. That's why we've enabled the interrupts in the first place.

    My question is still the expected behaviour of the interrupt. Will the ISR be called again (immediately) , if there are still message object left with a pending interrupt?
    According to the documentation I would say yes, however we do not see this happening. As I said, maybe CAN0INT would need some kind of rising edge?

    That's why I assume we must loop within the ISR until INT0ID is 0. Unfortunately the documentation seems not to be clear here and I would like this to be confirmed if so intended.

    Thanks again,

    Andreas

  • Hi Andreas,

    F280025 does not support nested interrupts, hence anytime an interrupt occurs it has to be serviced first, cleared of the cause and acknowledged for the other pending interrupts to take place.

    Regards,

    Joseph