2024-09-17 10:55 PM - last edited on 2024-09-18 02:32 AM by Andrew Neil
Hello everyone,
I'm currently working with the STM32G474RE MCU and using a CANopen stack. I'm facing an issue where the Auto Bus-Off recovery isn't happening as expected.
When there's a fault on the CAN bus, it correctly transitions to the warning state, then passive, and finally Bus-Off. However, after the fault is resolved, the bus should recover by moving from Bus-Off to passive, warning, and finally back to error-active, but this recovery is not occurring. The Bus-Off state remains even after the fault is restored.
I am monitoring the protocol status using the HAL_FDCAN_GetProtocolStatus function from the HAL library, but the error counter doesn't decrement, and the flags aren't resetting as they should.
Below is my CAN bus initialization and configuration routine:
void MX_FDCAN1_Init(void)
{
/* FDCAN1 parameter configuration */
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = ENABLE;
hfdcan1.Init.TransmitPause = DISABLE;
hfdcan1.Init.ProtocolException = ENABLE;
hfdcan1.Init.NominalPrescaler = 12;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 13;
hfdcan1.Init.NominalTimeSeg2 = 2;
hfdcan1.Init.DataPrescaler = 12;
hfdcan1.Init.DataSyncJumpWidth = 1;
hfdcan1.Init.DataTimeSeg1 = 13;
hfdcan1.Init.DataTimeSeg2 = 2;
hfdcan1.Init.StdFiltersNbr = 0;
hfdcan1.Init.ExtFiltersNbr = 0;
hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
{
Error_Handler();
}
}
/* CAN filter configuration */
FDCAN_FilterTypeDef sFilterConfig;
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x0000;
sFilterConfig.FilterID2 = 0x0000;
if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
{
DebugPrint("Failed to config filter.");
}
/* Configure global filter to accept all frames */
if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
DebugPrint("Failed to config global filter.");
}
/* Clearing Error Flags */
__HAL_FDCAN_CLEAR_FLAG(&hfdcan1, FDCAN_FLAG_ERROR_PASSIVE | FDCAN_FLAG_BUS_OFF);
/* Start the FDCAN module */
if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
{
DebugPrint("Failed to start FDCAN.");
}
/* Activate notifications */
if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_ERROR_PASSIVE | FDCAN_IT_BUS_OFF, 0) != HAL_OK)
{
DebugPrint("Failed to activate notifications.");
}
I'm not sure if I'm missing a step or misconfiguring something. If anyone has suggestions or possible solutions for why the Bus-Off state isn't recovering, I'd greatly appreciate the help.
“Even the best fall down sometimes,” but I'd love to get this one sorted out soon. Thank you in advance!
Solved! Go to Solution.
2024-09-17 11:35 PM - edited 2024-09-18 01:30 AM
Hello,
There is no auto bus off recovery on FDCAN like what was in bxCAN:
From RM0440
So you need to recover from Bus-Off by software:
HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0); /* Activate Bus off notification interrupt */
void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
if((ErrorStatusITs & FDCAN_IT_BUS_OFF) != 0) /* If Bus-Off error occured */
{
hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; /* Recover from Bus-Off */
}
}
See also this thread: https://community.st.com/t5/stm32-mcus-products/stm32h7-fdcan-has-lost-the-automatic-bus-off-recovery-mechanism/m-p/646807
Hope I answered your question.
2024-09-17 11:31 PM
The FDCAN controller on the STM32G4xx is entering INIT state when detecting bus-off.
So You have to "re-init" the Controller to exit bus-off.
I'm clearing directly the INIT bit in FDCAN_CCCR in side the HAL_FDCAN_ErrorStatusCallback() handler.
*
* Error handling callback
*
*/
void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hfdcan);
// TODO handle error state
if(ErrorStatusITs & FDCAN_IR_EP)
{
// handle Error Passive Mode
}
if(ErrorStatusITs & FDCAN_IR_EW)
{
// handle Error Warning
}
if(ErrorStatusITs & FDCAN_IR_BO)
{
// handle Bus Off state
// check state
if(hfdcan->Instance->PSR & FDCAN_PSR_BO)
{
// reset CCCR.INIT
CLEAR_BIT(hfdcan->Instance->CCCR, FDCAN_CCCR_INIT);
}
}
}
Further the FDCAN controller needs to receive valid Messages to decrement the error counter.
2024-09-17 11:35 PM - edited 2024-09-18 01:30 AM
Hello,
There is no auto bus off recovery on FDCAN like what was in bxCAN:
From RM0440
So you need to recover from Bus-Off by software:
HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0); /* Activate Bus off notification interrupt */
void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
if((ErrorStatusITs & FDCAN_IT_BUS_OFF) != 0) /* If Bus-Off error occured */
{
hfdcan->Instance->CCCR &= ~FDCAN_CCCR_INIT; /* Recover from Bus-Off */
}
}
See also this thread: https://community.st.com/t5/stm32-mcus-products/stm32h7-fdcan-has-lost-the-automatic-bus-off-recovery-mechanism/m-p/646807
Hope I answered your question.
2024-09-17 11:58 PM
Thank you for the solution! With your approach, the CPU is indeed able to recover whenever the Bus-Off condition occurs.
However, I'm facing a situation where the fault physically persists on the bus, yet the error counters (REC & TEC) remain at 0 (due to clearing CCCR.INIT bit).
To explain this further, imagine CAN_H and CAN_L are short-circuited. In this case, the Bus-Off flag gets set, but the code immediately resets it by clearing the CCCR.INIT bit. Physically, though, the CAN lines are still shorted.
Given that the bus is still in fault condition (shorted), how can I prevent this immediate recovery and ensure that the controller properly handles the ongoing physical issue?
Could you suggest a way to handle this kind of situation?
Thank you again for your help!
2024-09-18 01:38 AM
Hello,
I think the original question has bee already answered.
But regarding your last question. I'm not sure I understood what you mean by:
@omkarprayag wrote:
how can I prevent this immediate recovery and ensure that the controller properly handles the ongoing physical issue?
Simply: before recovering from the bus-off, after detecting the bus off you do what you want to do then recover from bus off by resetting CCCR.INIT bit.
But recovering from bus off state depends on if the node detects 129 occurrences of bus idle (129x11 consecutive recessive bits). Refer to the reference manual:
2024-09-18 02:04 AM
If the error persists, the FDCAN controller will re-set the Bus-off erroflag, so if You whant to detect this, You can simply count when You enter the Error Status callback function, and do what You think is best in Your application.