CAN Interrupt handling - finding the Interrupt source

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello,

I try to find a easy solution for determining the interrupt source of the MCAN module of an XMC4500. The module has 8 Interrupt lines to which 3x4 Node Interrupt and 64x2 message object Interrupts (total 140 sources) can be connected. But I havent found a register which tells me what was the cause for the Interrupt. There are a lot of registers (MSPND[0..7], MCR.MPSEL, MOIPR[0-63] and MOSTAT[0..63] alone for the message Objects) but if I have to do the complex calculation (searching MSPND[0..7] which is dependent to the interrupt Line (0..7) and MCR.MPSEL) to extract the message Object which was the cause for the interrupt I can't respond very quickly to the interrupt. And to configure one interrupt line for one source is not really possible because 8 interrupt lines for 3 CAN-buses is not enough by far.
Can anybody post a solution for determining the source?

Thanks in advance,

best regards

Mario
0 Likes
5 Replies
Travis
Employee
Employee
First solution authored Welcome! 500 replies posted
Hi MarioW,

Step 1: Determine the IRQ number
- Set a break point at your CAN interrupt function
- When the software breaks, check on the ICSR (Interrupt Control and State register)

607.attach

Example:
If ICSR.VECTACTIVE = 0x05C = 92

Therefore IRQ number = 92 - 16 = 76

So IRQ76 correspond to CAN_SR00.
610.attach

Step 2: Check DAVE3 Resource Mapping Information
- Click on the "Resource Mapping Information" icon >> Signal Assignment tab. (See picture below)
- Run your mouse pointer to the "Interrupt Node" which show you the IRQ number = 76. This simply means that this node is assigned to IRQ76 or CAN SR00 and the corresponding Interrupt function is Node_B_ISR.
- Then run your mouse pointer to the Logical message object correspond to the IRQ number 76. For this case is "LM01 Receive Interrupt". You shall see that Message Object 0 is being assigned for received interrupt.

609.attach

Step 3: Check Message Object Transmit and Receive status within interrupt function
- Now you have a clear picture regarding your interrupt resources and mapping. Such that Message Object 0 is tasked for receive interrupt which is channeled to Interrupt function Node_B_ISR.
- There might be cases when many message objects transmit or receive are being shared to the same Interrupt function Node_B_ISR, hence you have to use the software to check the Message Object status register and clear the status as shown below.

Example:
void Node_B_ISR(void)
{

if (CAN_MO0->MOSTAT & 0x00000001) // Check RXPND (Receive Pending)
{
// Message Object 00 Receive Interrupt
CAN_MO0->MOCTR &= 0x00000001; //Clear RXPND
}
}
0 Likes
Not applicable
Hi Travis,

thanks for your detailed answer!
The goal for my question was mainly your Step 3, the steps before are fortunately fixed (it is not a interrupt handler handling the requests of all peripheral modules). Moreover I do not use Dave at all, I write bare C/C++ code.
I am writing a generic interrupt handler for an application which handles the TX/RX Interrupts for 0..63 Message objects.
My actual solution is to set the Message pending Registers (MSPND[0..7]/MSID[0..7] in the following way:
MCR.MPSEL = 0 -> MOIPR.TXINP/RXINP (Interrupt request line 0..7 of MCAN0) have no influence on MSPND
MOIPR.MPN Bits 0..5 are for the message object index
MOIPR.MPN Bits 6..7 is the CAN node index the message object is assigned to
MSIMASK = all bits set

-> within the interrupt I can read the message object index from MSPND[0,1] (MSID[0,1] for node 0 and so on.
-> The only thing the handler must determine is the type of the interrupt (TX/RX) to handle it...

Message Objects with no interrupt enabled set the Bits 6..7 in MOIPR.MPN to 0b11 -> CAN node index 3 (not existing, MSPND[6..7]/MSID[6..7]) so that they do not disturb the MSPND[0..5]/MSID[0..5] registers.

If there is a better solution for this, I am looking forward to see your ideas...

Best regards,

Mario
0 Likes
Travis
Employee
Employee
First solution authored Welcome! 500 replies posted
MarioW wrote:
Hi Travis,

thanks for your detailed answer!
The goal for my question was mainly your Step 3, the steps before are fortunately fixed (it is not a interrupt handler handling the requests of all peripheral modules). Moreover I do not use Dave at all, I write bare C/C++ code.
I am writing a generic interrupt handler for an application which handles the TX/RX Interrupts for 0..63 Message objects.
My actual solution is to set the Message pending Registers (MSPND[0..7]/MSID[0..7] in the following way:
MCR.MPSEL = 0 -> MOIPR.TXINP/RXINP (Interrupt request line 0..7 of MCAN0) have no influence on MSPND
MOIPR.MPN Bits 0..5 are for the message object index
MOIPR.MPN Bits 6..7 is the CAN node index the message object is assigned to
MSIMASK = all bits set

-> within the interrupt I can read the message object index from MSPND[0,1] (MSID[0,1] for node 0 and so on.
-> The only thing the handler must determine is the type of the interrupt (TX/RX) to handle it...

Message Objects with no interrupt enabled set the Bits 6..7 in MOIPR.MPN to 0b11 -> CAN node index 3 (not existing, MSPND[6..7]/MSID[6..7]) so that they do not disturb the MSPND[0..5]/MSID[0..5] registers.

If there is a better solution for this, I am looking forward to see your ideas...

Best regards,

Mario



Hi Mario,

This is an interrupt routine which I channelled all the Message Objects Tx/Rx to a single Interrupt Request line.



void INTERRUPT (CAN_SRN0INT) CAN_viSRN0(void)
{


// USER CODE BEGIN (SRN0,2)

// USER CODE END

CAN_MSIMASK.U = 0x00000007; // set message index mask register
while (CAN_MSID0.U != 0x00000020)
{
switch(CAN_MSID0.U){

case 0: // message object 0 interrupt

if(CAN_MOSTAT0.B.RXPND) // if message object 0 receive interrupt
{

if(CAN_MOSTAT0.B.NEWDAT) // if NEWDAT is set
{

if (CAN_MOSTAT0.B.MSGLST) // if MSGLST is set
{
// Indicates that the CAN controller has stored a new
// message into this object, while NEWDAT was still set,
// ie. the previously stored message is lost.

CAN_MOCTR0.U = CAN_MOCTRm_CTR_RESMSGLST_MASK; // reset MSGLST

// USER CODE BEGIN (SRN0_OBJ0,1)

// USER CODE END
}
else
{
// The CAN controller has stored a new message
// into this object.

// USER CODE BEGIN (SRN0_OBJ0,2)

// USER CODE END
}

CAN_MOCTR0.U = CAN_MOCTRm_CTR_RESNEWDAT_MASK; // reset NEWDAT
}

CAN_MOCTR0.U = CAN_MOCTRm_CTR_RESRXPND_MASK; // reset RXPND
} // End of RXPND0

if(CAN_MOSTAT0.B.TXPND) // if message object 0 transmit interrupt
{

// The CAN controller has send a remote frame
// with identifier and control of this object.

// USER CODE BEGIN (SRN0_OBJ0,6)

// USER CODE END

CAN_MOCTR0.U = CAN_MOCTRm_CTR_RESTXPND_MASK; // reset TXPND

} // End of TXPND0

CAN_MSPND0.U = ~0x00000001; // reset PND bit

// USER CODE BEGIN (SRN0_OBJ0,7)

// USER CODE END

break;


case 1: // message object 1 interrupt

if(CAN_MOSTAT1.B.RXPND) // if message object 1 receive interrupt
{

if(CAN_MOSTAT1.B.NEWDAT) // if NEWDAT is set
{

if (CAN_MOSTAT1.B.MSGLST) // if MSGLST is set
{
// Indicates that the CAN controller has stored a new
// message into this object, while NEWDAT was still set,
// ie. the previously stored message is lost.

CAN_MOCTR1.U = CAN_MOCTRm_CTR_RESMSGLST_MASK; // reset MSGLST

// USER CODE BEGIN (SRN0_OBJ1,1)

// USER CODE END
}
else
{
// The CAN controller has stored a new message
// into this object.

// USER CODE BEGIN (SRN0_OBJ1,2)

// USER CODE END
}

CAN_MOCTR1.U = CAN_MOCTRm_CTR_RESNEWDAT_MASK; // reset NEWDAT
}

CAN_MOCTR1.U = CAN_MOCTRm_CTR_RESRXPND_MASK; // reset RXPND
} // End of RXPND1

if(CAN_MOSTAT1.B.TXPND) // if message object 1 transmit interrupt
{

// The CAN controller has send a remote frame
// with identifier and control of this object.

// USER CODE BEGIN (SRN0_OBJ1,6)

// USER CODE END

CAN_MOCTR1.U = CAN_MOCTRm_CTR_RESTXPND_MASK; // reset TXPND

} // End of TXPND1

CAN_MSPND0.U = ~0x00000002; // reset PND bit

// USER CODE BEGIN (SRN0_OBJ1,7)

// USER CODE END

break;


case 2: // message object 2 interrupt

if(CAN_MOSTAT2.B.RXPND) // if message object 2 receive interrupt
{

if(CAN_MOSTAT2.B.NEWDAT) // if NEWDAT is set
{

if (CAN_MOSTAT2.B.MSGLST) // if MSGLST is set
{
// Indicates that the CAN controller has stored a new
// message into this object, while NEWDAT was still set,
// ie. the previously stored message is lost.

CAN_MOCTR2.U = CAN_MOCTRm_CTR_RESMSGLST_MASK; // reset MSGLST

// USER CODE BEGIN (SRN0_OBJ2,1)

// USER CODE END
}
else
{
// The CAN controller has stored a new message
// into this object.

// USER CODE BEGIN (SRN0_OBJ2,2)

// USER CODE END
}

CAN_MOCTR2.U = CAN_MOCTRm_CTR_RESNEWDAT_MASK; // reset NEWDAT
}

CAN_MOCTR2.U = CAN_MOCTRm_CTR_RESRXPND_MASK; // reset RXPND
} // End of RXPND2

if(CAN_MOSTAT2.B.TXPND) // if message object 2 transmit interrupt
{

// The CAN controller has send a remote frame
// with identifier and control of this object.

// USER CODE BEGIN (SRN0_OBJ2,6)

// USER CODE END

CAN_MOCTR2.U = CAN_MOCTRm_CTR_RESTXPND_MASK; // reset TXPND

} // End of TXPND2

CAN_MSPND0.U = ~0x00000004; // reset PND bit

// USER CODE BEGIN (SRN0_OBJ2,7)

// USER CODE END

break;

default:

// USER CODE BEGIN (SRN0,3)

// USER CODE END

break;

} // end switch

// USER CODE BEGIN (SRN0,7)

// USER CODE END

} // end of while CAN_MSID


// USER CODE BEGIN (SRN0,15)

// USER CODE END

} // End of function CAN_viSRN0




0 Likes
Not applicable
Hi Travis,

thanks again for your detailed answer! I have thougt I have overseen some possibility to do the task of handling my interrupt very efficiently, but when I look at your code I see that there is no way to do this without a lot of code and wasting a lot of time within the interrupt... Because of this the response to a message with my generic handler will take a while, perhaps I have to use seperate Interrupt lines (if 8 are enough) for the time critical handlers...

Best regards,

Mario
0 Likes
Travis
Employee
Employee
First solution authored Welcome! 500 replies posted
MarioW wrote:
Hi Travis,

thanks again for your detailed answer! I have thougt I have overseen some possibility to do the task of handling my interrupt very efficiently, but when I look at your code I see that there is no way to do this without a lot of code and wasting a lot of time within the interrupt... Because of this the response to a message with my generic handler will take a while, perhaps I have to use seperate Interrupt lines (if 8 are enough) for the time critical handlers...

Best regards,

Mario


Hi Mario,

Yes, there are 8 Interrupt Request line which you may want to divide them among your message boxes Tx/Rx to make it more systematic or efficient.

Thanks for the very nice sharing and good luck to you.

Best Regards
Travis
0 Likes