Skip to main content
Visitor II
September 18, 2024
Solved

CAN Auto Bus-Off Recovery Not Happening on STM32G474RE MCU

  • September 18, 2024
  • 3 replies
  • 3938 views

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!

    This topic has been closed for replies.
    Best answer by mƎALLEm

    Hello,

    There is no auto bus off recovery on FDCAN like what was in bxCAN:

    From RM0440

    SofLit_0-1726648165918.png

    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.

    3 replies

    Graduate II
    September 18, 2024

    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.

     

    mƎALLEmAnswer
    Technical Moderator
    September 18, 2024

    Hello,

    There is no auto bus off recovery on FDCAN like what was in bxCAN:

    From RM0440

    SofLit_0-1726648165918.png

    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.

    Visitor II
    September 18, 2024

    Hi @MHoll.2@mƎALLEm 

    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!

    Technical Moderator
    September 18, 2024

    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:

    SofLit_1-1726648679805.png