2025-03-28 4:09 AM - last edited on 2025-03-28 4:13 AM by mƎALLEm
Hello
I use CAN FD and have a functioning communication with 3 participants. Now I want to activate the interrupt that notifies me when the device has lost the arbitration contest.
I forward each of the four NVIC interrupts in stm32h7xx_hal_fdcan:
void FDCAN2_IT0_IRQHandler(void)
{
HAL_FDCAN_IRQHandler(&hfdcan2);
}
When initializing CAN, I activate the interrupt:
retVal = HAL_FDCAN_ActivateNotification(m_Fdcan2Handle, FDCAN_IT_ARB_PROTOCOL_ERROR, 0);
and set the CallbackHandle beforehand:
retVal = HAL_FDCAN_RegisterTxEventFifoCallback(m_Fdcan2Handle, MyCallback);
SYSM_ASSERT_STOP(retVal == HAL_OK, retVal);
retVal = HAL_FDCAN_RegisterErrorStatusCallback(m_Fdcan2Handle, MyCallback);
SYSM_ASSERT_STOP(retVal == HAL_OK, retVal);
retVal = HAL_FDCAN_RegisterTxBufferAbortCallback(m_Fdcan2Handle, MyCallback);
SYSM_ASSERT_STOP(retVal == HAL_OK, retVal);
retVal = HAL_FDCAN_RegisterTxEventFifoCallback(m_Fdcan2Handle, MyCallback);
SYSM_ASSERT_STOP(retVal == HAL_OK, retVal);
Despite arbitration collisions, I do not end up in my callback “MyCallback”.
What have I overlooked?
Best regards
Solved! Go to Solution.
2025-04-14 10:27 PM
Hallo, as a workaround I made it work with the FiFo size of 1 and the FiFoEmpty-Interrupt:
void CCan::txFifoEmptyCallback(FDCAN_HandleTypeDef *hfdcan)
{
uint32_t TXBRP = hfdcan->Instance->TXBRP;
uint32_t TXBFC = hfdcan->Instance->TXBCF;
uint32_t TXBTO = hfdcan->Instance->TXBTO;
/* Arbitration loss or frame transmission disturbed? */
if ((TXBFC & ~TXBTO) != 0 && !TXBRP)
{
/* Check if there was an error in the data or arbitration phase.
* Lost arbitration is not rated as error (See FDCAN_PSR.LEC). */
bool dataPhaseError = hfdcan->Instance->IR & FDCAN_FLAG_DATA_PROTOCOL_ERROR;
bool dataArbError = hfdcan->Instance->IR & FDCAN_FLAG_ARB_PROTOCOL_ERROR;
if(dataPhaseError == false && dataArbError == false )
{
/* Retransmit the Message */
HAL_StatusTypeDef retVal;
if(hfdcan->Instance == FDCAN1)
{
retVal = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &latestCanMessage[0].txHeader, latestCanMessage[0].dataWithSerial);
SYSM_ASSERT_NO_STOP(retVal == HAL_OK, hfdcan->ErrorCode);
}
else if(hfdcan->Instance == FDCAN2)
{
retVal = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &latestCanMessage[1].txHeader, latestCanMessage[1].dataWithSerial);
SYSM_ASSERT_NO_STOP(retVal == HAL_OK, hfdcan->ErrorCode);
}
else
{
SYSM_ASSERT_STOP(0, hfdcan->Instance);
}
}
}
}
There are still some cases, in which an error in the arbitration-phase is evaluated as arbitration loss (See FDCAN_PSR.LEC), but since it will only occure rarely, its fine for my SW.
Best regards
Manuel
2025-03-28 4:26 AM - edited 2025-03-28 8:48 AM
Hello,
First, please use </> button to share your code. See this link. (I've edited your post).
Second, according to the description of the PEA bit it might be not intended to signal a lost of arbitration but to signal a protocol error that occurred during the arbitration phase:
I may ask internally and get back to you as soon as I have an answer. Internal ticket 206406 has been submitted (not accessible by the community users).
2025-03-28 4:26 AM
Hello @MFrie.7
For better debugging, please ensure that the return value retVal is equal to HAL_OK when calling the HAL functions.
retVal = HAL_FDCAN_ActivateNotification(m_Fdcan2Handle, FDCAN_IT_ARB_PROTOCOL_ERROR, 0);
if (retVal != HAL_OK)
{
// Error handler
}
2025-03-31 4:34 AM - edited 2025-03-31 4:35 AM
Hello,
Thank you for your reply and opening an internal ticket.
In the reference manual I see an other possible solution for this problem, but I can't get it to work:
I check TXBTO and TXBFC for a lost of the arbitration contest like this:
if (TXBFC & ~TXBTO)
{
...
The problem with this is, that I now count to much lost of arbitration contest. Perhaps I need to trigger TXBRP from 1 to 0? I have not found a way (Interrupt) for that.
2025-04-02 1:48 AM
I don't think this is an efficient way as it's not exclusively to signal the loss of the arbitration but also an issue in transmission.
2025-04-14 10:27 PM
Hallo, as a workaround I made it work with the FiFo size of 1 and the FiFoEmpty-Interrupt:
void CCan::txFifoEmptyCallback(FDCAN_HandleTypeDef *hfdcan)
{
uint32_t TXBRP = hfdcan->Instance->TXBRP;
uint32_t TXBFC = hfdcan->Instance->TXBCF;
uint32_t TXBTO = hfdcan->Instance->TXBTO;
/* Arbitration loss or frame transmission disturbed? */
if ((TXBFC & ~TXBTO) != 0 && !TXBRP)
{
/* Check if there was an error in the data or arbitration phase.
* Lost arbitration is not rated as error (See FDCAN_PSR.LEC). */
bool dataPhaseError = hfdcan->Instance->IR & FDCAN_FLAG_DATA_PROTOCOL_ERROR;
bool dataArbError = hfdcan->Instance->IR & FDCAN_FLAG_ARB_PROTOCOL_ERROR;
if(dataPhaseError == false && dataArbError == false )
{
/* Retransmit the Message */
HAL_StatusTypeDef retVal;
if(hfdcan->Instance == FDCAN1)
{
retVal = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &latestCanMessage[0].txHeader, latestCanMessage[0].dataWithSerial);
SYSM_ASSERT_NO_STOP(retVal == HAL_OK, hfdcan->ErrorCode);
}
else if(hfdcan->Instance == FDCAN2)
{
retVal = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &latestCanMessage[1].txHeader, latestCanMessage[1].dataWithSerial);
SYSM_ASSERT_NO_STOP(retVal == HAL_OK, hfdcan->ErrorCode);
}
else
{
SYSM_ASSERT_STOP(0, hfdcan->Instance);
}
}
}
}
There are still some cases, in which an error in the arbitration-phase is evaluated as arbitration loss (See FDCAN_PSR.LEC), but since it will only occure rarely, its fine for my SW.
Best regards
Manuel