2017-03-21 07:31 AM
We are using HAL CAN drivers for STM32 F7 (stm32f7xx_hal_can.c).
During CAN tx/rx stress tests we experienced an issue resulting in CAN receive hang.
The issue is due to a race condition on hcan->State variable between HAL_CAN_Transmit_IT and CAN_Receive_IT.
The issue arises in the following conditions:
HAL_CAN_STATE_BUSY_RX
HAL_CAN_Transmit_IT is called and enters condition
if
(hcan->
State
==
HAL_CAN_STATE_BUSY_RX
)
hcan->
State
=
HAL_CAN_STATE_READY
hcan->
State
=
HAL_CAN_STATE_BUSY_TX_RX
The final result is that when exiting HAL_CAN_Transmit_IT hcan->State is
HAL_CAN_STATE_BUSY_TX_RX
while it should have beenHAL_CAN_STATE_BUSY_TX
. From now on every attempt of further receptions with HAL_CAN_Receive_IT will fail.Has someone experienced this issue before?
Are there avilable solutions to this HAL bug from ST?
2017-05-18 01:49 PM
They also have more rx-tx states and better handling of them , though to me it still seems like band-aid code, just a bit better one
2017-05-22 04:20 AM
I still haven't had a chance to test this new version of the HAL driver, but I can't see how these few extra states will make a difference to this problem, and they seem to be handled in more or less the same way still. As
Synter.Indrek
suggests, a critical section somewhere might help (although the __HAL_LOCK macro is meant to do this to some effect from what I can tell - at least stop the HAL state writes being interrupted.). For my project I've just disabled interrupts around the HAL CAN TX call, although this isn't a good solution in general, but it works in my case.2017-05-22 04:31 AM
I've just realised that the CAN_Receive_IT function doesn't use the __HAL_LOCK macro, which is what's causing the issue. Tricky though, as this function does need to release the CAN state from being busy no matter what. Seems like the way to go is put some critical section around writes to the state variable.
2017-06-15 05:14 AM
I've done it in a much simpler way
No need to lock/unlock anything
My application guarantees fixed rate of incoming messages
I tuned sheduler to launch specific task slightly more often than the said rate
The task merely does the following
if (__HAL_CAN_MSG_PENDING(&hcan, CAN_FIFO0) != 0U)
{ if ( (((&hcan)->Instance->sFIFOMailBox[CAN_FIFO0].RDTR) & 0x0FU) == _VALID_LENGTH) { UpdTimeout(&stRx_TO);DoAllTheseThings(((&hcan)->Instance->sFIFOMailBox[CAN_FIFO0].RDLR), ((&hcan)->Instance->sFIFOMailBox[CAN_FIFO0].RDHR)); } __HAL_CAN_FIFO_RELEASE(&hcan, CAN_FIFO0); }