Skip to main content
KMew
Senior III
October 25, 2022
Solved

Alter CAN Message Data, Array to Int

  • October 25, 2022
  • 3 replies
  • 1849 views

Hello,

This is a mixture of a C question and a CAN communication question, as I want to find the simplest solution for what I'm trying to do. I have an 8 byte CAN message that I successfully receive and store in an array (uint8_t RXData[8]). I am sending part of this data (RxData[0 to 3]) to a display on the STM32H7B3I-EVAL evaluation board.

I want to store the data in a single uint32_t variable (since RxData[0 to 3] represents a single piece of data. Specifically, a voltage). So storing it in pieces of an array makes it difficult to do arithmetic on it (scale the 0-65535 range of uint32_t to represent a voltage range of 0-60V).

What is the simplest way to do this?

This topic has been closed for replies.
Best answer by JPeac.1

Assuming RxData is 32-bit aligned, easiest way is:

NewValue = (uint32_t *) &RxData[4];

otherwise loop from [4] to [7], NewValue |= (NewValue << 8) | RxData[i];

This ignores the CAN protocol being used. It will work for CANopen, which is usually little-endian, but not for other CAN protocols which are big-endian. Not enough information to fully answer the question.

3 replies

KMew
KMewAuthor
Senior III
October 25, 2022

To add an example of what I'm looking for:

uint8_t RxData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88)

End Goal:

uint32_t NewValue = 0x55667788

Javier1
Principal
October 26, 2022

with uint64_t NewValue.

i usually just memcpy(&NewValue,&RxData,sizeof(NewValue))

and then i do all the bitshifting/masking i need.

Using pointers is a nogo for my applications due to RxData fast changes

and multithread (RTOS)

hit me up in https://www.linkedin.com/in/javiermuñoz/
KMew
KMewAuthor
Senior III
October 27, 2022

Memcpy with bit-shifting is likely a better idea for scalability too, I would imagine! That way, I could define how much is bit shifted based on what segment of data is needed. It would require a function call that defines how much to bit shift, but the flexibility would be better.

Thank you for this suggestion too!

JPeac.1
JPeac.1Best answer
Visitor II
October 25, 2022

Assuming RxData is 32-bit aligned, easiest way is:

NewValue = (uint32_t *) &RxData[4];

otherwise loop from [4] to [7], NewValue |= (NewValue << 8) | RxData[i];

This ignores the CAN protocol being used. It will work for CANopen, which is usually little-endian, but not for other CAN protocols which are big-endian. Not enough information to fully answer the question.

KMew
KMewAuthor
Senior III
October 25, 2022

Hello JPeac,

Thank you for the reply! This solution actually works perfectly for me! CANopen is little-endian and works for what I'm trying to do. If I encounter a big endian scenario, I can just flip the direction (i.e. instead of Data[i]. have the for loop be Data[size-i] instead).

Thank you very much!

Piranha
Principal III
October 29, 2022

The most universal and recommended way is using a union:

union msg_u {
	uint8_t bytes[8];
	uint32_t values[2];
} RxData;

KMew
KMewAuthor
Senior III
October 31, 2022

Hello Piranha,

This is an interesting way. By putting the RxData at the end, you are defining the variable name. When reading the CAN message in HAL_FDCAN_GetRxMessage, I'll have to use RxData.bytes in your case, correct? If so, is RxData.values also automatically filled in with the same data, but in the different format? Or is there an additional step?