cancel
Showing results for 
Search instead for 
Did you mean: 

Can't receive CAN messages fast enough - messages are missing

jgauthier
Senior

Hello,

I've been trying to implement a CAN receiver to capture many (~20) messages in quick succession. I've tried to implement the capture of these messages as efficiently as possible, but it seems that messages are still not received.

I am using an STM32L432 processor. I am sending the data via Python, and I am capturing the data via candump on a raspberry pi. Here are the results of my experiences and code.

First, the data set I am sending as seen on the CAN bus:

 can0  124   [8]  10 8C 31 32 33 34 35 36
 can0  124   [8]  21 37 38 39 41 42 43 44
 can0  124   [8]  22 45 46 47 48 49 4A 4B
 can0  124   [8]  23 4C 4D 4E 4F 50 51 52
 can0  124   [8]  24 53 54 55 56 57 5A 59
 can0  124   [8]  25 5A 31 32 33 34 35 36
 can0  124   [8]  26 37 38 39 41 42 43 44
 can0  124   [8]  27 45 46 47 48 49 4A 4B
 can0  124   [8]  28 4C 4D 4E 4F 50 51 52
 can0  124   [8]  29 53 54 55 56 57 5A 59
 can0  124   [8]  2A 5A 31 32 33 34 35 36
 can0  124   [8]  2B 37 38 39 41 42 43 44
 can0  124   [8]  2C 45 46 47 48 49 4A 4B
 can0  124   [8]  2D 4C 4D 4E 4F 50 51 52
 can0  124   [8]  2E 53 54 55 56 57 5A 59
 can0  124   [8]  2F 5A 31 32 33 34 35 36
 can0  124   [8]  20 37 38 39 41 42 43 44
 can0  124   [8]  21 45 46 47 48 49 4A 4B
 can0  124   [8]  22 4C 4D 4E 4F 50 51 52
 can0  124   [8]  23 53 54 55 56 57 5A 59
 can0  124   [2]  24 5A

I am not using an interrupt.

I am calling this function from the main() while(1) loop:

void process_can_rx(void) {
    uint8_t fill_0=1, fill_1=1, msg_cnt=0;
    uint8_t can_rx_data[CAN_LEN];
    CAN_RxHeaderTypeDef rx_header;
	
    // Get the FIFO levels, this determines a pending mesage
    while (fill_0 || fill_1) {
        fill_0 = HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0);
        fill_1 = HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO1);
 
        // If there is a message waiting, nab it.
        if (fill_0) {
            HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rx_header, can_rx_data);
            msg_cnt++;
        } else if (fill_1) {
            HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO1, &rx_header, can_rx_data);
        }
 
        if (!fill_0 && !fill_1) {
            break;
        }
        // Put this in the queue to be handled
        add_rx_header(&rx_header, can_rx_data);
    }
    // only handle the messages if there are messages.
	if (msg_cnt) {
    	for (struct rx_header_msg *msg = rx_header_list; msg!=NULL; msg=msg->next) {
    		serprintf("%#x\n\r", msg->bytes[0]);
    	}
    	serprintf("\n\r");
    }
}	  

This function repeatedly polls and checks for messages on the CANbus. When there is a message it adds it to a linked list. That code is this:

void add_rx_header(CAN_RxHeaderTypeDef *rx_header, uint8_t *can_rx_data) {
    struct rx_header_msg *rx_header_entry, *prev;
    rx_header_entry = calloc(1, sizeof(struct rx_header_msg));
    
    rx_header_entry->bytes = malloc(rx_header->DLC);
    rx_header_entry->rx_header = *rx_header;
    
    memcpy(rx_header_entry->bytes, can_rx_data, rx_header->DLC);
 
    if (rx_header_list == NULL) {
        rx_header_list = rx_header_entry;
        rx_header_last = rx_header_entry;
    } else {
        // this message
        prev = rx_header_last;
        // assign new msg to the end of the list
        prev->next = rx_header_entry;
        // also assign the last message to this msg
        rx_header_last = rx_header_entry;
    }
    struct rx_header_msg *msg;
 
}

Now, the result I see on the canbus (posted above) is correct.

However, what I am seeing retrieved from the above code is missing messages.

in process_can_rx() after the loop completes (no more can messages)

I dump out the messages that were received (this is for debugging sake, I actually want to send these to another function for processing, but that is disabled while I diagnose this). The loop will show the first byte in the CAN data (it increments) in "groups" of what the function gathered during that loop.

The result is this (with my own commentary) in line:

0x10    <-- first message received
 
0x21    <-- second
 
0x22    <-- these two were collected at the same time 
0x23    <-- in the process_can_rx() loop
 
0x24
0x25
 
0x26    <-- same, but there were 3 messages this time
0x27
0x28
 
0x29
0x2a
0x2b
 
0x2c    <-- 0x2e is missing!
0x2d
0x2f
 
0x20    <-- after 0x2f we looped b ack to 0x20
0x21    <-- but 0x22 and 0x23 are missing
0x24    <-- last message received

I don't know how to proceed. I've implemented code to "get in and get out" as fast as possible to try and reduce any overhead away from getting the actual message with HAL_CAN_GetRxMessage. But now I am stumped on how to continue.

Finally, I am initializing the can interface at 500K like this:

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 8;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_6TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_1TQ;
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = DISABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = ENABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;

Thanks for reading, and I appreciate any advice.

4 REPLIES 4
jgauthier
Senior

The issue here is that the receive FIFO is being filled and the overrun bit is being set.

The Reference Manual says there are two receive FIFOs, however FIFO1 never seems to have anything in it.

FiFOs would be assigned per filter, you'd need different filters with different matching criteria.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I see. That makes it sound like the FIFO isn't active until there is a filter. I didn't assign one to that yet (wide open) I will test!

Also, I am having trouble with filtering as well (https://community.st.com/s/question/0D53W00001UX6JXSA1/bxcan-filtering)

Seems like this is common due to it's complexity.

Appreciate your response!

Is the problem resolved?