Alter CAN Message Data, Array to Int
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-25 8:41 AM
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?
Solved! Go to Solution.
- Labels:
-
CAN
-
STM32H7 Series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-25 9:54 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-25 8:58 AM
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-25 9:54 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-25 10:53 AM
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-26 1:04 AM
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)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-27 11:01 AM
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!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-28 5:15 PM
The most universal and recommended way is using a union:
union msg_u {
uint8_t bytes[8];
uint32_t values[2];
} RxData;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-28 5:20 PM
> Assuming RxData is 32-bit aligned
Cortex-M3 and higher supports unaligned accesses.
Endianess can be dealt easily with REV, REV16 and REVSH instruction macros:
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-31 6:52 AM
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2022-10-31 9:05 AM
Yes, you pass an address of the RxData.bytes to the driver, but after that read RxData.values . No additional steps necessary, because it is actually the same memory (8 bytes). Union members just give a different "views" on it. You can put a structure there also, but be aware of a possible alignment/padding issues, which must be solved by structure packing.
