problem with union in Teensy 3.5

Status
Not open for further replies.

Lorenzo

Well-known member
Hello forum!

I have a little problem with an union in Teensy 3.5. I am sending binary data packages from a Teensy 3.2 to a Teensy 3.5 via Serial communication.
I am using a union structure to unpack and extract data from the received packages.
My problem is that, if I use this structPacket:

Code:
struct structPacket
{
  uint8_t Start_bytes[3];
  uint8_t timestamp[4];
  uint8_t cycles[4];
  uint8_t encoder_1_pos[2];
  uint8_t encoder_2_pos[2];
  uint8_t encoder_1_omega[2];
  uint8_t encoder_2_omega[2];
  uint8_t load_cell_1[2];
  uint8_t load_cell_2[2];
  uint8_t pot_pos[2];
  uint8_t pot_punto[2];
  uint8_t Stop_bytes[3];
};

union unionIncoming
{
  uint8_t vData[BYTE_SERIAL_INCOMING_PACKET];
  structPacket Raw;
}
SERIAL_Incoming_Data;

and I extract data with this function:

Code:
void extractData(structPacket Raw)
{
  TIMER = *(unsigned long *)&Raw.timestamp;
  CYCLES = *(unsigned long *)&Raw.cycles;
  ENC_1_pos_raw = *(int16_t *)&Raw.encoder_1_pos;
  ENC_2_pos_raw = *(int16_t *)&Raw.encoder_2_pos;
  ENC_1_omega_raw = *(int16_t *)&Raw.encoder_1_omega;
  ENC_2_omega_raw = *(int16_t *)&Raw.encoder_2_omega;
  LC_1_raw = *(int16_t *)&Raw.load_cell_1;
  LC_2_raw = *(int16_t *)&Raw.load_cell_2;
  POT_pos_raw = *(int16_t *)&Raw.pot_pos;
  POT_punto_raw = *(int16_t *)&Raw.pot_punto;
}

everything works. But I think this is not a really good way to use the union.

Otherwise, if I use the following structPacket and extractData function, I can not read the correct values.


Code:
struct structPacket
{
  uint8_t Start_bytes[3];
  unsigned long timestamp;
  unsigned long cycles;
  int16_t encoder_1_pos;
  int16_t encoder_2_pos;
  int16_t encoder_1_omega;
  int16_t encoder_2_omega;
  int16_t load_cell_1;
  int16_t load_cell_2;
  int16_t pot_pos;
  int16_t pot_punto;
  uint8_t Stop_bytes[3];
};

Code:
ENC_1_pos_raw = (int16_t)Raw.encoder_1_pos;
ENC_2_pos_raw = (int16_t)Raw.encoder_2_pos;
ENC_1_omega_raw = (int16_t)Raw.encoder_1_omega;
ENC_2_omega_raw = (int16_t)Raw.encoder_2_omega;
LC_1_raw = (int16_t)Raw.load_cell_1;
LC_2_raw = (int16_t)Raw.load_cell_2;
POT_pos_raw = (int16_t)Raw.pot_pos;
POT_punto_raw = (int16_t)Raw.pot_punto;


What is it happening?

Thank you for any suggestion! :)
 
There are more C/C++ compiler people here, but I am pretty sure it all has to do with how the data is packed.

That is in your first example all of the variables are 8 bit values, whose natural alignment is on byte boundaries so there is no problems...

However in your second case, the 2nd variable is an unsigned long value (4 bytes) who wants to be aligned to a 4 byte boundary so by default there will be a gap of 1 byte after Start_bytes[3] to get it back in alignment.

There are ways around it. You properly align all of your variables on their natural positions. One way is to order the items in your structure from largest to smallest... Or add in pad variables.

Or you can tell the compiler to pack your structure. I believe you can do it with attributes, but the typical way I have done it looks something like:

Code:
#pragma pack(push, 1)
struct structPacket
{
  uint8_t Start_bytes[3];
  unsigned long timestamp;
  unsigned long cycles;
  int16_t encoder_1_pos;
  int16_t encoder_2_pos;
  int16_t encoder_1_omega;
  int16_t encoder_2_omega;
  int16_t load_cell_1;
  int16_t load_cell_2;
  int16_t pot_pos;
  int16_t pot_punto;
  uint8_t Stop_bytes[3];
};
#pragma pack(pop)

Or if lazy and I want everything to be packed I just do:
Code:
#pragma pack(1)
 
It works with #pragma pack(push, 1) and #pragma pack(pop) ! :D

Thank you very much for the suggestion KurtE!
 
Status
Not open for further replies.
Back
Top