Page 1 of 1

Question about uint32_t data type

Posted: Tue Apr 26, 2022 2:59 pm
by Patrick54
Hi,

I am playing with several ESP32s linked together via a CAN bus. The simple prototype I have made is working well with 3 nodes, they are exchanging messages successfully. For the ones who don't know about CAN, the frames exchanged can contain a maximum of 8 bytes of data.
For one specific type of frame that contains instructions to activate a stepper motor, the 8 bytes of data are composed like this:
  1. typedef struct {
  2.   uint8_t dir;            // 'F' = CW, 'R' = CCW
  3.   uint32_t rev;           // number of revolutions
  4.   uint8_t filler[3];      // filler
  5. } stepper_data_t;
In the node that is sending the frame, I set dir to 'R', and rev to 2. The length of the message is also set to 5, so the last 3 bytes are not sent. The receiving node understands the frame correctly and spins the stepper motor backwards for 2 revolutions.

Then I decided the plug my oscilloscope to the CAN bus to decode the frames, and for this specific frame, I have the following data (in hex):
0x52 79 11 01 02

0x52 is correct, as it corresponds to 'R'. But the next 4 bytes are a mystery for me, I was expecting to find 00 00 00 01. Is this linked to the way ESP32 is implementing uint32_t?

Re: Question about uint32_t data type

Posted: Tue Apr 26, 2022 8:41 pm
by ESP_igrr
The issue you are running into is related to alignment of struct members (https://en.cppreference.com/w/c/languag ... #alignment)

Here's an example which prints the offsets of members of your struct: https://ideone.com/7ksmU4
As you can see from the output, the offset of 'uint32_t rev' member is 4 bytes, not 1. This is because the minimal alignment of a 4-byte uint32_t type is 4 bytes. Compilers add padding to structures to ensure that every member is appropriately aligned and there is no unaligned access.

Sometimes we need to represent structures where members are not aligned. This is possible by adding "attribute packed" to the structure definition. Here's an example: https://ideone.com/mmZEPR
As you see, with that attribute the 'uint32_t rev' member is placed without extra padding. However, access to this member will be implemented by the compiler using several instructions, since the value can no longer be accessed in an aligned manner. This might not matter in your application, but can lead to race conditions due to read-modify-write operations. So packed structures should be used with care.

Re: Question about uint32_t data type

Posted: Wed Apr 27, 2022 8:02 am
by Patrick54
Thanks a lot for these very detailed explanations! Now I understand what I see, and realise that my experiment was working only because: 1) ESP32 uses little endian 2) I was only using small values for rev.

In that case, I simply changed the positions of my fields in the struct, putting the int first, and everything is fine. I am happy I checked this with my oscilloscope, otherwise I would never have been aware of the issue, and would have faced inexplicable issues with other frames or values.