CAN problem with XMC4400 (XMC_CAN_STATUS_BUSY).

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

cross mob
User13835
Level 1
Level 1
Hi!

I have a problem with the sending CAN messages on the XMC4400. Everything seams ok (sends CAN messages) until I
provoke the communication errors by putting a 10uF capacitor between CAN HIGH and CAN LOW.
When provoking bus the error counters counts up as expected but when removing the capacitor the
XMC_CAN_MO_Transmit() function always exits with status busy (XMC_CAN_STATUS_BUSY).

Is there any flags I need to clear or something else?

Best regards,
Mats Loman
0 Likes
1 Solution
DRubeša
Employee
Employee
First solution authored First like received
Hi Mats,

the "XMC_CAN_MO_Transmit()" function return "XMC_CAN_STATUS_BUSY" due to the fact that bit TXRQ is sent in the message object you´re trying to send. That means that the previous transmission is ongoing and you cannot send the new message which is stated with the busy status. Why does this happen? Well, when you wanted to simulate the bus error I suspect it caused the bus off event. After the bus event occurred the node with try to do the bus recovery sequence which is also mentioned in the User Manual.
Once the bus recovery is succesfull finished the bit BOFF will be cleared (for this reason you don´t see it in the print statement above...it already has been cleared by the hardware). But one thing still prevents to continue with the CAN traffic and that is the fact that once the bus off event occurs, the node will be set to initialized state by the hardware itself meaning a bus cannot participate in the ongoing CAN communication. Erroneous node could prevent others working nodes from working properly, so you need to have a mechanism to remove the erroneous node from the CAN communication and you do it by setting the INIT bit.

To enable the node to participate in the CAN communication once again you need to reset the INIT bit of that node. What I would suggest to you is the following...due to the fact you have already the ALERT interrupt implemented, you could check the status of the BOFF and EWRN registers and once you see that the bus off and error warning status is 0 then reset the init bit of the node 1 (this will allow node 1 participation on the network).

Best regards,
Deni

View solution in original post

0 Likes
6 Replies
User13835
Level 1
Level 1
#include "scheduler.h"
#include "debug_uart.h"
#include "alarm.h"

#include "xmc_can.h"
#include "xmc_gpio.h"

#include

#define CAN_BAUDRATE (1000 * 1000) // 1000 kbit

#define CAN_SR_TX 6
#define CAN_SR_RX 7
#define CAN_SR_ERR 5

#define MCU_FREQ 120000000

// MO2 receive
static XMC_CAN_MO_t g_rx_msg_obj = {
.can_mo_ptr = (CAN_MO_TypeDef *)CAN_MO2,
.can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
.can_id_mask = (uint32_t)0,
.can_id_mode = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS,
.can_identifier = (uint32_t)0,
.can_data_length = (uint8_t)8,
.can_mo_type = XMC_CAN_MO_TYPE_RECMSGOBJ,
.can_data = {0x0, 0x0},
};

// MO4 Transmit
/*static*/ XMC_CAN_MO_t g_tx_msg_obj = {
.can_mo_ptr = (CAN_MO_TypeDef *)CAN_MO4,
.can_priority = XMC_CAN_ARBITRATION_MODE_IDE_DIR_BASED_PRIO_2,
.can_identifier = 0,
.can_id_mask = 0,
.can_ide_mask = 0, // (uint32_t)
.can_id_mode = XMC_CAN_FRAME_TYPE_EXTENDED_29BITS,
.can_data_length = (uint8_t)8,
.can_mo_type = XMC_CAN_MO_TYPE_TRANSMSGOBJ,
};

void init_can()
{
/*CAN Bit time*/
static const XMC_CAN_NODE_NOMINAL_BIT_TIME_CONFIG_t can_baud = {
.can_frequency = MCU_FREQ,
.baudrate = CAN_BAUDRATE,
.sample_point = (75 * 100), // 75 %
.sjw = 1, // Set and tested using the Kvaser Leaf
};

XMC_GPIO_CONFIG_t rx_can_config;
XMC_GPIO_CONFIG_t tx_can_config;

/* initialize CAN module */
XMC_CAN_Init(CAN, MCU_FREQ);

/* configure CAN receive pin */
rx_can_config.mode = XMC_GPIO_MODE_INPUT_TRISTATE;

XMC_GPIO_Init(P1_4, &rx_can_config);

/* configure CAN transmit pin */
tx_can_config.mode = XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2;
tx_can_config.output_level = XMC_GPIO_OUTPUT_LEVEL_HIGH;
tx_can_config.output_strength =
XMC_GPIO_OUTPUT_STRENGTH_STRONG_SOFT_EDGE;
XMC_GPIO_Init(P1_12, &tx_can_config);

/* define baudrate */
XMC_CAN_NODE_NominalBitTimeConfigure(CAN_NODE1, &can_baud);

/* enable configuration changes and keep the node disconnected from the
* bus */
XMC_CAN_NODE_EnableConfigurationChange(CAN_NODE1);
XMC_CAN_NODE_SetInitBit(CAN_NODE1);

/* set receive input */
XMC_CAN_NODE_SetReceiveInput(CAN_NODE1,
XMC_CAN_NODE_RECEIVE_INPUT_RXDCD);

/* allocate message object to node list */
XMC_CAN_AllocateMOtoNodeList(CAN, 1, 4); // MO4

/* allocate message object to node list */
XMC_CAN_AllocateMOtoNodeList(CAN, 1, 2); // MO2

// const uint32_t can_id_mask = 0x8f30000;
XMC_CAN_MO_SetAcceptanceMask(&g_rx_msg_obj, (uint32_t)0);

/* configure message object*/
XMC_CAN_MO_Config(&g_tx_msg_obj);

/* configure message object*/
XMC_CAN_MO_Config(&g_rx_msg_obj);

/* set interrupt node pointer */
XMC_CAN_MO_SetEventNodePointer(&g_rx_msg_obj,
XMC_CAN_MO_POINTER_EVENT_RECEIVE, 7);

XMC_CAN_MO_SetEventNodePointer(&g_tx_msg_obj,
XMC_CAN_MO_POINTER_EVENT_TRANSMIT, 6);

XMC_CAN_NODE_SetEventNodePointer(CAN_NODE1, XMC_CAN_NODE_EVENT_ALERT, 5);

/* define interrupt trigger event */
XMC_CAN_MO_EnableEvent(&g_rx_msg_obj, XMC_CAN_MO_EVENT_RECEIVE);
XMC_CAN_MO_EnableEvent(&g_tx_msg_obj, XMC_CAN_MO_EVENT_TRANSMIT);
XMC_CAN_NODE_EnableEvent(CAN_NODE1, XMC_CAN_NODE_EVENT_ALERT);

/* setting interrupt priority */
NVIC_SetPriority(CAN0_7_IRQn, NVIC_EncodePriority(
NVIC_GetPriorityGrouping(), 63U, 0U));
NVIC_SetPriority(CAN0_6_IRQn, NVIC_EncodePriority(
NVIC_GetPriorityGrouping(), 63U, 1U));
NVIC_SetPriority(CAN0_5_IRQn, NVIC_EncodePriority(
NVIC_GetPriorityGrouping(), 63U, 2U));

/* enable interrupt */
NVIC_EnableIRQ(CAN0_7_IRQn);
NVIC_EnableIRQ(CAN0_6_IRQn);
NVIC_EnableIRQ(CAN0_5_IRQn);

/* reset CCE and INIT bit NCR for node configuration */
XMC_CAN_NODE_DisableConfigurationChange(CAN_NODE1);
XMC_CAN_NODE_ResetInitBit(CAN_NODE1);
}

void CAN0_7_IRQHandler(void)
{
printf("RX IRQ\r\n");
}

void CAN0_6_IRQHandler(void)
{
printf("TX IRQ\r\n");
}

void CAN0_5_IRQHandler(void)
{
printf("ALERT IRQ\r\n");
}

static inline int transmit(unsigned cnt)
{
XMC_CAN_MO_Config(&g_tx_msg_obj);
XMC_CAN_MO_SetIdentifier(&g_tx_msg_obj, 0x12345678l);

g_tx_msg_obj.can_data_byte[0] = (cnt >> 24) & 0xFF;
g_tx_msg_obj.can_data_byte[0] = (cnt >> 16) & 0xFF;
g_tx_msg_obj.can_data_byte[0] = (cnt >> 😎 & 0xFF;
g_tx_msg_obj.can_data_byte[0] = cnt & 0xFF;
g_tx_msg_obj.can_data_length = 4;

if (XMC_CAN_MO_UpdateData(&g_tx_msg_obj) == XMC_CAN_STATUS_SUCCESS) {
XMC_CAN_STATUS_t s;
if ((s=XMC_CAN_MO_Transmit(&g_tx_msg_obj)) ==
XMC_CAN_STATUS_SUCCESS) {
XMC_CAN_MO_ResetStatus(&g_tx_msg_obj, XMC_CAN_MO_RESET_STATUS_TX_PENDING);
printf("Transmitt successful.\r\n");
return 1;
}else{
printf("Transmitt failed: 0x%X\r\n", s);
}
}

return 0;
}

static void print_status()
{
extern XMC_CAN_MO_t g_tx_msg_obj;

uint32_t s = XMC_CAN_NODE_GetStatus(CAN_NODE1);
uint8_t re = XMC_CAN_NODE_GetReceiveErrorCounter(CAN_NODE1);
uint8_t te = XMC_CAN_NODE_GetTransmitErrorCounter(CAN_NODE1);

printf("RE: %d, TE: %d, 0x%08lX -- ",re,te, (uint32_t) ((g_tx_msg_obj.can_mo_ptr->MOSTAT) & CAN_MO_MOSTAT_TXRQ_Msk) >> CAN_MO_MOSTAT_TXRQ_Pos);
printf("%s -- %s -- %s\r\n",
(s & XMC_CAN_NODE_STATUS_ALERT_WARNING) ? "ALERT WARNING" : "",
(s & XMC_CAN_NODE_STATUS_ERROR_WARNING_STATUS) ? "ERROR WARNING" : "",
(s & XMC_CAN_NODE_STATUS_BUS_OFF) ? "BUS OFF" : ""
);
}


void test_wait()
{
TIMER_t tmr;

tmr_start(&tmr);

while(tmr_elapsed(&tmr) debug_uart_process_buffer();
alarm_wdt_feed();
}
}



void run_can_tests()
{
unsigned cnt = 0;

init_can();
while(1){
test_wait();
print_status();
transmit(cnt++);
}

}



When the CAN controller locks up the error counters are set to 0 and the XMC_CAN_MO_Transmit() function returns busy.


Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2
RE: 0, TE: 0, 0x00000001 -- ALERT WARNING -- --
Transmitt failed: 0x2


Best regards,
Mats Loman
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hi Mats,

the "XMC_CAN_MO_Transmit()" function return "XMC_CAN_STATUS_BUSY" due to the fact that bit TXRQ is sent in the message object you´re trying to send. That means that the previous transmission is ongoing and you cannot send the new message which is stated with the busy status. Why does this happen? Well, when you wanted to simulate the bus error I suspect it caused the bus off event. After the bus event occurred the node with try to do the bus recovery sequence which is also mentioned in the User Manual.
Once the bus recovery is succesfull finished the bit BOFF will be cleared (for this reason you don´t see it in the print statement above...it already has been cleared by the hardware). But one thing still prevents to continue with the CAN traffic and that is the fact that once the bus off event occurs, the node will be set to initialized state by the hardware itself meaning a bus cannot participate in the ongoing CAN communication. Erroneous node could prevent others working nodes from working properly, so you need to have a mechanism to remove the erroneous node from the CAN communication and you do it by setting the INIT bit.

To enable the node to participate in the CAN communication once again you need to reset the INIT bit of that node. What I would suggest to you is the following...due to the fact you have already the ALERT interrupt implemented, you could check the status of the BOFF and EWRN registers and once you see that the bus off and error warning status is 0 then reset the init bit of the node 1 (this will allow node 1 participation on the network).

Best regards,
Deni
0 Likes
User13835
Level 1
Level 1
Hi!

Thanks for you input! I will try to implement it as you suggest, but I have one more problem. I never get the ALERT interrupt, i do not understand why.

Best regards,
Mats Loman
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hi,

well check during execution of the code once you try to provoke the bus error is the ALERT bitfield set. If this bitfield is not set, then the interrupt will not be called even if everything else is properly set.
Due to the fact your print shows the "ALERT WARNING" statement I assume that ALERT bitfield is set in the node status register.

If there is an ALERT bit field set then check if ALIE bitfiled in NCR register is set...I assumed so while I see this function call "XMC_CAN_NODE_EnableEvent(CAN_NODE1, XMC_CAN_NODE_EVENT_ALERT);" but nevertheless, check once again. Maybe if you know that for example TX interrupt work then swap the ISR handler just to verify the ALERT interrupt is getting called.

Let me know how it went and then we can take the next necessary steps.

Best regards,
Deni Rubeša
0 Likes
User13835
Level 1
Level 1
Hi!

It looks like the ALERT event always executes the CAN0_0_IRQHandler even if I configure it to trigger something else.

Best Regards,
Mats Loman
0 Likes
User13835
Level 1
Level 1
Hi,

I got it working now! Thanks!

Best regards,
Mats Loman
0 Likes