2025-10-14 2:26 AM - edited 2025-10-14 2:27 AM
I am simulating messages to be received via CAN on the STM32F0xx series uC. The hardware FIFO does not overflow as I have activated the overflow interrupt and checked the FIFO level, which never exceeds 1. The current implementation consists of a 128-byte software buffer. Now, the system is able to handle messages sent at 100 ms intervals. When I start sending messages at 10 ms intervals, it begins to overwrite the previous entry in the buffer. It does so once after a long time of sending messages, and does not happen frequently.
The potential issue is that the interrupt fires every 10 milliseconds, while the main message processing happens every 50 milliseconds, so the buffer is cleared/read after 5 messages have already been sent. What I am noticing is that the current index for the ring buffer "resets" to the previous interrupt's counter value, the occurrence of which is low. Hence, when the message counter in the CAN frame is received, due to the current index being "reset", it overwrites the previous entry in the ring buffer.
My question is, since my function is being called inside HAL_CAN_RxFifo0MsgPendingCallback, is it possible that while servicing the interrupt, the same interrupt fires, the indices for looping through the software buffer did not increment, hence I end up with missing counter values?
Code inside the callback is:
bool msg_to_queue(const CAN_MSG* const rx) { bool ret = false; if ((rx->dlc >= 1u) && (rx->dlc <= CAN_PAYLOAD_SIZE)) { const uint32_t curr_rx_buf_inp = rx_buf_inp & (MAX_CAN_RECEIVE_MSG - 1u); const uint32_t next_rx_buf_inp = (curr_rx_buf_inp + 1u) & (MAX_CAN_RECEIVE_MSG - 1u); // is next entry in buffer free if (next_rx_buf_inp != rx_buf_outp) // if next entry not empty (inp+1 == outp), then discard message { rx_buffer[curr_rx_buf_inp] = *rx; /* Move to next entry */ rx_buf_inp = next_rx_buf_inp; retval = true; // Success } else { ++can_receive_error_overrun; } } return ret; }
2025-10-17 6:22 PM
It would help to see what you're also doing in HAL_CAN_RxFifo0MsgPendingCallback
2025-10-18 3:38 AM
Are You really using a ring buffer?
When do You think the condition
if (next_rx_buf_inp != rx_buf_outp) // if next entry not empty (inp+1 == outp), then discard message
becomes false?
2025-10-20 1:48 AM
I wanted to reply to you but ended up responding to myself in the previous comment. Essentially rx_buf_outp is incremented inside the main application where the receiving function loops until the buffer is empty. Hence, if the buffer queues up faster than I'm processing those messages in the buffer, I'll end up overwriting quite a few slots.
2025-10-20 1:50 AM
I'm basically calling HAL_CAN_GetRXMessage(), checking if it returns OK and proceeding with calling this.
2025-10-20 1:54 AM
Nevermind, I found the culprit. I'm calling the same function for looping back my transmitted messages, hence the index rx_buf_inp was not just being incremented in the ISR but also in the loopback functionality. I'm going to proceed with disabling interrupts around that block which will solve the issue that I'm seeing.
2025-10-20 2:44 AM
Basically you're calling HAL_CAN_GetRXMessage to copy the message to a data structure, then you're calling msg_to_queue to point to a queue. That's not very efficient.
Instead, you need to point to your Rx queue and the correct index when you call HAL_CAN_GetRXMessage. That way it's only a one time copy.