memcpy() destination buffer sporadically empty?

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I'm putting together a very basic MCAN class on a SAME70Q21B, the relevant code of which aligns with the ASF Quick Start 'qs_mcan_basic.c' NEW_MESSAGE interrupt approach as follows:

 

if (status & MCAN_RX_FIFO_0_NEW_MESSAGE) {

	mcan_clear_interrupt_status(&mcan_instance, MCAN_RX_FIFO_0_NEW_MESSAGE);
	mcan_get_rx_fifo_0_element(&mcan_instance, &rx_element_fifo_0,
			standard_receive_index);
	mcan_rx_fifo_acknowledge(&mcan_instance, 0,
			standard_receive_index);
	standard_receive_index++;
	if (standard_receive_index == CONF_MCAN0_RX_FIFO_0_NUM) {
		standard_receive_index = 0;
	}

	printf("\n\r Standard message received in FIFO 0. The received data is: \r\n");
	for (i = 0; i < rx_element_fifo_0.R1.bit.DLC; i++) {
		printf("  %d",rx_element_fifo_0.data[i]);
	}
	printf("\r\n\r\n");
}

 

I won't focus too much on the above, as my MCAN configuration (I'm using MCAN0) works as expected, and the NEW_MESSAGE interrupt is fired when I send a CAN packet from the remote CAN device as expected. The very first CAN packet received is processed correctly (i.e. the DLC count is correct, as are the Data bytes), however, for any packets sent after the first one, the packet might be correctly processed, or the packet might be completely empty. I have my oscilloscope connected to the bus, and can confirm that the packets are being sent correctly.

 

In the above code, the ASF function where the received data is read from the FIFO is:

 

mcan_get_rx_fifo_0_element(&mcan_instance, &rx_element_fifo_0,
			standard_receive_index);

The mcan_get_rx_fifo_0_element function reads the received CAN data out of the pre-configured FIFO array at the provided index into the provided 'mcan_rx_element_fifo_0' struct (rx_element_fifo_0 in the above code):

 

 

Nothing unexpected here, it simply checks whether the MCAN instance is MCAN0 or MCAN1, then uses memcpy() to copy the FIFO data from the current mcan0_rx_fifo_0 index into the mcan_rx_element_fifo_0 struct pointer.

 

I've stepped through the code with my debugger, and have identified this function as the cause of the issue I'm seeing. I've included screenshots of my Atmel Studio interface below to highlight the issue.

 

I've stopped the debugger on the memcpy() function and added watches on the index value, as well as on the mcan0_rx_fifo_0 array at the index value. Note that this is the second packet received (i.e. index value 1), where the first packet received (i.e. index value 0) is always processed correctly. As you can see, there are 8 bytes of data in mcan0_rx_fifo_0 at index 1 (each packet sent has the same Arbitration ID and the same 8 incrementing bytes of data).

 

 

In the next screenshot, I've advanced the debugger by a single step, such that the memcpy() operation has been executed. I've added watches on each of the struct components of the rx_element struct; R0, R1 and data. As you can see, all struct variables are 0x00.

 

 

How is this possible? From the first screenshot we can clearly see that the source for the memcpy() function is valid, yet the destination buffer is completely empty after the memcpy() function has executed?

 

As mentioned earlier, whether this memcpy() execution results in a correct rx_element struct or an empty one seems to be random. I've sent several hundred packets (all with the same Arbitration ID, DLC and data bytes), and the resultant rx_element struct is sporadically full or empty.

 

Any thoughts on this would be greatly appreciated as always!

 

This topic has a solution.
Last Edited: Sat. Jan 22, 2022 - 05:53 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there any DMA involved? Could be a cache problem if so.

https://community.atmel.com/foru...

/Lars

 

Last Edited: Fri. Jan 21, 2022 - 09:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your input as always Lars.

 

The MCAN class doesn't make use of any DMA; I had initially considered coherency because it certainly presents as such, but as far as I can tell (i.e. I haven't explicitly used XDMAC with MCAN) none of the MCAN-related data structures should be involved with DMA.

 

EDIT: I've just amended the instantiation of the mcan_rx_element_fifo_0 struct so that the struct is stored in my 'ram_nocache' memory region as follows:

 

__attribute__((section("ram_nocache"))) static struct mcan_rx_element_fifo_0 rx_element_fifo_0;

This didn't have any effect; the sporadic full/empty struct issue remains.

Last Edited: Sat. Jan 22, 2022 - 12:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It seems I'm making some progress.

 

Instead of copying the received CAN data (from the preconfigured mcan0_rx_fifo_0 buffer at the specified array, as per the mcan_get_rx_fifo_0_element() ASF function) using memcpy():

 

 

I've instead directly assigned each component element of the rx_element struct:

 

 

The above code still results in the rx_element struct being either correctly filled with data, or empty. What is most interesting, is if I don't try and access the mcan0_rx_fifo_0

.data array, the R0 and R1 struct elements are correctly filled with data 100% of the time. I.e. if I only access R0 and R1, the data is 100% correct; if I touch the data element, the entire struct is compromised.

 

 

The above code provides the correct R0 and R1 data; why would accessing the struct 'data' array cause the entire rx_element struct to be compromised?

Last Edited: Sat. Jan 22, 2022 - 05:16 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I've come to a solution.

 

For some reason, it appears that this issue occurs when the full size of the mcan_rx_element_buffer struct is copied to the rx_element struct pointer. I've modified the original memcpy() function to the below:

 

 

This memcpy() now works perfectly; every single packet received and processed is correct. Instead of copying the full size of mcan_rx_element_buffer (as shown in the original MCAN1 memcpy() function in the screenshot above), I only copy the amount of data actually received:

  1. The mcan_rx_element_buffer 'R0' and 'R1' unions. These elements are each 8 bytes long (a 4 byte bit-field and a uint32_t) and are always populated.
  2. The length of data actually received. As shown above, I read the DLC element from the R1 bit-field.

 

I won't be using the ASF library for this interface moving forward, so I'll bear this in mind when it comes to putting together my own implementation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just revisiting this in case anyone comes across a similar MCAN issue in the future.

 

It should come as no surprise that Lars was absolutely correct with his initial suspicion. I was having further issues with reading the received MCAN data, and found that it was indeed a cache coherency issue. Before accessing the data I invalidate the address of the current FIFO buffer and then the data is read correctly as expected.