cancel
Showing results for 
Search instead for 
Did you mean: 

How to clear FDCAN error callback?

MLang.7
Associate III

Hello,

I would like to use the error callback of the FDCAN module on the STM32H743ZI and so far I got it working. Once an error (e.g protocol error) occured the callback keeps getting called. According to the reference manual an interrupt flag can be cleared by either reseting the module or writing a 1 to the particular bit in the FDCAN_IR register.

I tried using the functions __HAL_FDCAN_CLEAR_IT and/or __HAL_FDCAN_CLEAR_FLAG but it didn't work. Even by directly setting the bits didn't stop calling the handler.

So, I would be very thankful for an advice how to properly handle this interrupt.

4 REPLIES 4
TDK
Guru

Flags are cleared within HAL_CAN_IRQHandler. Your interrupt should be calling HAL_CAN_IRQHandler to handle (and clear) the relevant interrupt flags.

If you feel a post has answered your question, please click "Accept as Solution".
MLang.7
Associate III
/* USER CODE BEGIN 4 */
void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hfdcan)
{
	if(hfdcan == &hfdcan1)
	{
		uint32_t error_code = HAL_FDCAN_GetError(hfdcan);
		if((error_code & FDCAN_FLAG_ARB_PROTOCOL_ERROR) != RESET)
		{
			hfdcan->Instance->IR |= error_code;
 
			/** also tried */
			//__HAL_FDCAN_CLEAR_IT(hfdcan, FDCAN_IT_ARB_PROTOCOL_ERROR);
			//__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_ARB_PROTOCOL_ERROR);
		}
	}
}

That is the interrupt handler provided by HAL. But somehow the flag doesn't seem to be cleared as it is continously called once the flag is set.

TDK
Guru

Isn't it possible the bit keeps getting set? If there's a protocol error, find the source of the error and fix that, rather than trying to clear the flag.

The HAL library doesn't appear to set that error code anywhere, so I'm not sure how you would be seeing error_code = FDCAN_FLAG_ARB_PROTOCOL_ERROR:

https://github.com/STMicroelectronics/STM32CubeH7/search?q=FDCAN_FLAG_ARB_PROTOCOL_ERROR

https://github.com/STMicroelectronics/STM32CubeH7/search?q=FDCAN_IR_PEA

If you feel a post has answered your question, please click "Accept as Solution".
MLang.7
Associate III

I have another CAN-Tool connected to the same network and it shows no further errors, hence why I conclude that the flag isn't reset by the HAL.

Why do you come to think the error code is set the by the HAL? The error is the very error flag as set in the hardware register and is passed through to the interrupt (line 27, 28 in stm32h7xx_hal_fdcan.c):

void HAL_FDCAN_IRQHandler(FDCAN_HandleTypeDef *hfdcan)
{
  uint32_t ClkCalibrationITs;
  uint32_t TxEventFifoITs;
  uint32_t RxFifo0ITs;
  uint32_t RxFifo1ITs;
  uint32_t Errors;
  uint32_t ErrorStatusITs;
  uint32_t TransmittedBuffers;
  uint32_t AbortedBuffers;
  uint32_t TTSchedSyncITs;
  uint32_t TTTimeMarkITs;
  uint32_t TTGlobTimeITs;
  uint32_t TTDistErrors;
  uint32_t TTFatalErrors;
  uint32_t SWTime;
  uint32_t SWCycleCount;
 
  ClkCalibrationITs = (FDCAN_CCU->IR << 30);
  ClkCalibrationITs &= (FDCAN_CCU->IE << 30);
  TxEventFifoITs = hfdcan->Instance->IR & FDCAN_TX_EVENT_FIFO_MASK;
  TxEventFifoITs &= hfdcan->Instance->IE;
  RxFifo0ITs = hfdcan->Instance->IR & FDCAN_RX_FIFO0_MASK;
  RxFifo0ITs &= hfdcan->Instance->IE;
  RxFifo1ITs = hfdcan->Instance->IR & FDCAN_RX_FIFO1_MASK;
  RxFifo1ITs &= hfdcan->Instance->IE;
  Errors = hfdcan->Instance->IR & FDCAN_ERROR_MASK;
  Errors &= hfdcan->Instance->IE;
  ErrorStatusITs = hfdcan->Instance->IR & FDCAN_ERROR_STATUS_MASK;
  ErrorStatusITs &= hfdcan->Instance->IE;
 
  /* High Priority Message interrupt management *******************************/
  if (__HAL_FDCAN_GET_IT_SOURCE(hfdcan, FDCAN_IT_RX_HIGH_PRIORITY_MSG) != 0U)
  {
    if (__HAL_FDCAN_GET_FLAG(hfdcan, FDCAN_FLAG_RX_HIGH_PRIORITY_MSG) != 0U)
    {
      /* Clear the High Priority Message flag */
      __HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_RX_HIGH_PRIORITY_MSG);
 
#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1
      /* Call registered callback*/
      hfdcan->HighPriorityMessageCallback(hfdcan);
#else
      /* High Priority Message Callback */
      HAL_FDCAN_HighPriorityMessageCallback(hfdcan);
#endif /* USE_HAL_FDCAN_REGISTER_CALLBACKS */
    }
  }

Further down the code from line 5505 onwards is where the magic happens. If there are any errors, they are cleared by the HAL via the function __HAL_FDCAN_CLEAR_FLAG():

if (Errors != 0U)
  {
    /* Clear the Error flags */
    __HAL_FDCAN_CLEAR_FLAG(hfdcan, Errors);
 
    /* Update error code */
    hfdcan->ErrorCode |= Errors;
  }

__HAL_FDCAN_CLEAR_FLAG() itself resets the instances error register

#define __HAL_FDCAN_CLEAR_FLAG(__HANDLE__, __FLAG__)             \
do{                                                              \
    ((__HANDLE__)->Instance->IR) = ((__FLAG__) & FDCAN_IR_MASK); \
    FDCAN_CCU->IR = (((__FLAG__) & CCU_IR_MASK) >> 30);          \
  }while(0)

But still, the error codes are preserved in the variable "Errors" which is added to the modules variable "ErrorCode" (hfdcan->ErrorCode). Further down the line the user's error callback is finally invoked. Please note, that the callback is invoked if there is any error stored in "ErrorCode". Keep in mind, that the module's handle is the only argument passed.

{
...
  if (hfdcan->ErrorCode != HAL_FDCAN_ERROR_NONE)
  {
#if USE_HAL_FDCAN_REGISTER_CALLBACKS == 1
    /* Call registered callback*/
    hfdcan->ErrorCallback(hfdcan);
#else
    /* Error Callback */
    HAL_FDCAN_ErrorCallback(hfdcan);
#endif /* USE_HAL_FDCAN_REGISTER_CALLBACKS */
  }
}

As mentioned before, I used the function HAL_FDCAN_GetError() to retreive the error code. In fact, this method just returns the module's "ErrorCode"

uint32_t HAL_FDCAN_GetError(FDCAN_HandleTypeDef *hfdcan)
{
  /* Return FDCAN error code */
  return hfdcan->ErrorCode;
}

I don't know if this behaviour is intended that way it is, but hfdcan->ErrorCode is never reset on normal operation, but the errors are rather accumulated in hfdcan->ErrorCode.  Since the mechanism is now dismanteled, the solution is quite easy:

if((error_code & FDCAN_FLAG_ARB_PROTOCOL_ERROR) != RESET)
{
    ui_set_warning(UI_WARNING_ERROR);
    hfdcan->ErrorCode &= ~ FDCAN_FLAG_ARB_PROTOCOL_ERROR;
}

Maybe the guys from ST should add a wrapper funtion for this, as manipulating mambers of this structure feels utterly wrong.