2024-07-17 12:22 AM - last edited on 2024-07-17 03:56 AM by SofLit
Hi,
i need help with a strange behaviour of the FDCAN RX interrupt. I have 2 controllers which communicate with each other over CAN bus (Classic CAN). The first (my problem mcu) sends a command message and the second answers with 3 messages. The problem is, that on the first MCU the RX interrupt is only called twice and the third message stucks in the fifo until I send a new message.
I have made some debug output which shows my problem a little bit clearer:
106 CAN TX: 0E 07 00
107 CAN RX: 01 0A 02 FF FF FF FF FF
108 CAN RX: 02 08 00 00 01 0E 00 EB
FIFO: 1
1118 CAN TX: 0E 07 00
1119 CAN RX: 03 08 FF FF FF FF FF FF
1120 CAN RX: 01 0A 02 FF FF FF FF FF
FIFO: 2
2130 CAN TX: 0E 07 00
2131 CAN RX: 02 08 00 00 01 0A 00 F8
2132 CAN RX: 03 FA FF FF FF FF FF FF
FIFO: 3
3142 CAN TX: 0E 07 00
3143 CAN RX: 01 0A 02 FF FF FF FF FF
3144 CAN RX: 02 08 00 00 01 0C 00 FB
FIFO: 4
4154 CAN TX: 0E 07 00
4155 CAN RX: 03 FB FF FF FF FF FF FF
4156 CAN RX: 01 0A 02 FF FF FF FF FF
FIFO: 5
5166 CAN TX: 0E 07 00
5167 CAN RX: 02 08 00 00 01 0E 00 FC
5168 CAN RX: 03 FC FF FF FF FF FF FF
The number at the beginning of the lines are the timestamps.
The first byte in the RX messages is the id of the message counting from 1 to 3.
The CAN Rx... messages are printed out in the IRQ.
The data in the messages is correct, so the bit timing matches on both mcu sides.
As you can see, if I send a message the RX interrupt is only called twice and the third response message stays in the FIFO until I send another message.
I have verified that the second controller is sending its 3 messages within a few milliseconds (Debug message outputs and logic analyser for the CAN bus). So the problem is not on that side.
My intializing code looks like:
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Peripheral clock enable
__HAL_RCC_FDCAN_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**FDCAN1 GPIO Configuration
PA11 ------> FDCAN1_RX
PA12 ------> FDCAN1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
can->Instance = FDCAN1;
can->Init.FrameFormat = FDCAN_FRAME_CLASSIC;
can->Init.Mode = FDCAN_MODE_NORMAL;
can->Init.AutoRetransmission = ENABLE;
can->Init.TransmitPause = DISABLE;
can->Init.ProtocolException = ENABLE;
can->Init.NominalPrescaler = 4;
can->Init.NominalSyncJumpWidth = 5;
can->Init.NominalTimeSeg1 = 14;
can->Init.NominalTimeSeg2 = 5;
can->Init.MessageRAMOffset = 0;
can->Init.StdFiltersNbr = 0;
can->Init.ExtFiltersNbr = 0;
can->Init.RxFifo0ElmtsNbr = 6;
can->Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
can->Init.RxFifo1ElmtsNbr = 0;
can->Init.RxBuffersNbr = 0;
can->Init.TxEventsNbr = 0;
can->Init.TxBuffersNbr =0;
can->Init.TxFifoQueueElmtsNbr = 1;
can->Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
can->Init.TxElmtSize = FDCAN_DATA_BYTES_8;
if (HAL_FDCAN_Init(can) != HAL_OK) {
return RESULT_INIT;
}
HAL_FDCAN_ActivateNotification(can, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
// Enable interrupts
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
if(HAL_FDCAN_Start(can) != HAL_OK) {
return RESULT_INIT;
}
The RX interrupt handler:
void FDCAN1_IT0_IRQHandler() {
HAL_FDCAN_IRQHandler(can);
}
/**
* \brief Receive callback from HAL. Takes the received CAN packet and puts it in the protocol stack
* \param hcan Pointer to the CAN handle typedef
*/
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef* hcan, uint32_t RxFifo0ITs) {
HAL_StatusTypeDef result;
FDCAN_RxHeaderTypeDef header;
tCANFrame rxF;
result = HAL_FDCAN_GetRxMessage(hcan, FDCAN_RX_FIFO0, &header, rxF.data);
rxF.msgId = header.Identifier;
rxF.size = ((header.DataLength>>16)>8)?8:(header.DataLength>>16);
logd("%d CAN RX: ", HAL_GetTick());
for(uint8_t i=0; i<rxF.size; i++) {
logd("%02X ", rxF.data[i]);
}
lognl("");
}
And the test loop where I send the messages to the second controller:
FDCAN_TxHeaderTypeDef header;
uint8_t data[3];
data[0] = 0x0E;
data[1] = 0x07;
data[2] = 0x00;
header.IdType = FDCAN_EXTENDED_ID;
header.Identifier = 0x11C;
header.DataLength = FDCAN_DLC_BYTES_3;
header.TxFrameType = FDCAN_DATA_FRAME;
header.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
header.BitRateSwitch = FDCAN_BRS_OFF;
header.FDFormat = FDCAN_CLASSIC_CAN;
header.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
header.MessageMarker = 0;
while(1) {
uint32_t mailbox;
// Check if TX queue is full
if((can->Instance->TXFQS&FDCAN_TXFQS_TFQF)) {
break;
}
logd("%d CAN TX: ", HAL_GetTick());
for(uint8_t i=0; i<3; i++) {
logd("%02X ", data[i]);
}
lognl("");
HAL_FDCAN_AddMessageToTxFifoQ(can, &header, data);
// Wait some time until interrupts could be handled
HAL_Delay(10);
// Show remaining message count from FIFO
lognl("FIFO: %d", HAL_FDCAN_GetRxFifoFillLevel(can, FDCAN_RX_FIFO0));
HAL_Delay(1000);
}
Maybe someone have a hint what's wrong with my code?
Solved! Go to Solution.
2024-07-17 04:53 AM - edited 2024-09-24 05:04 AM
You set the number of filters to 0. You need to set it to at least 1.
can->Init.StdFiltersNbr = 0;
can->Init.ExtFiltersNbr = 0;
What if you increase this delay from the transmit side?
// Wait some time until interrupts could be handled
HAL_Delay(10)
let's say 100ms.
2024-07-17 03:55 AM
Hello,
Avoid using printf in the interrupts (in the callbacks).
2024-07-17 04:48 AM
Even if I do not have any outputs in the interrupt, the problem exists.
2024-07-17 04:53 AM - edited 2024-09-24 05:04 AM
You set the number of filters to 0. You need to set it to at least 1.
can->Init.StdFiltersNbr = 0;
can->Init.ExtFiltersNbr = 0;
What if you increase this delay from the transmit side?
// Wait some time until interrupts could be handled
HAL_Delay(10)
let's say 100ms.