I have two STM32 boards connected via a CAN bus. They periodically transmit a message to each other.
For some transmissions however, HAL_CAN_Transmit
returns with a timeout HAL_TIMEOUT
. Similarly, sometimes the CAN receive interrupt does not get fired. There is not a real pattern when it works and when not. However, resetting a device seems to induce timeouts more often.
When investigating the signals with a scope, they appear to be fine. The receiving transceiver acknowledges the signal as well even when the CAN receive interrupt is not fired.
What could be the problem in this case?
This is the code to transmit a message. It is called by the main loop.
void send_can_message_handler(void* task)
{
hcan.pTxMsg->StdId = 0x321;
hcan.pTxMsg->ExtId = 0x01;
hcan.pTxMsg->RTR = CAN_RTR_DATA;
hcan.pTxMsg->IDE = CAN_ID_STD;
hcan.pTxMsg->DLC = 2;
hcan.pTxMsg->Data[0] = can_messages_sent;
hcan.pTxMsg->Data[1] = 0xAD;
HAL_StatusTypeDef status = HAL_CAN_Transmit(&hcan, 500);
can_messages_sent = can_messages_sent + 1;
if (status == HAL_OK) {
uint8_t data[2] = { 79, 75 };
HAL_UART_Transmit(&huart1, data, 2, 100);
}
else if (status == HAL_ERROR) {
uint8_t data[2] = { 69, 82 };
HAL_UART_Transmit(&huart1, data, 2, 100);
}
else if (status == HAL_BUSY) {
uint8_t data[2] = { 66, 85 };
HAL_UART_Transmit(&huart1, data, 2, 100);
}
else if (status == HAL_TIMEOUT) {
uint8_t data[2] = { 84, 73 };
HAL_UART_Transmit(&huart1, data, 2, 100);
}
}
This is the interrupt code.
void USB_LP_CAN1_RX0_IRQHandler(void)
{
/* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */
/* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
HAL_CAN_IRQHandler(&hcan);
/* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
FillBuffer(&canBuffer1.State, hcan);
// Enable receiving again.
if (HAL_CAN_Receive_IT(&hcan, CAN_FIFO0) != HAL_OK)
{
// Handle error.
}
/* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */
}
FillBuffer
simply copies the data to a buffer.
void FillBuffer(CanBufferState* state, CAN_HandleTypeDef hcan)
{
for (size_t i = 0; i < 1; i++)
{
state->Buffer[state->WriteIndex] = hcan.pRxMsg->Data[i];
state->WriteIndex = (state->WriteIndex + 1) != BUFFER_SIZE ? state->WriteIndex + 1 : 0;
}
}