#pragma pack(4) on AVR

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

I have an include file shared between 8-bit AVR, 32-bit ARM, and Windows projects that defines a common struct for communications between them.  I attempted to ensure the struct was aligned the same on all platforms with:

#pragma pack(push, 4)
struct {
    ...
};
#pragma pack(pop)

I had to uncheck a box in the Atmel Studio compiler optimization properties that added "-fpack-struct"; it caused a warning that pragma pack() would be ignored.  However, the struct still came out packed on the AVR.

 

Is there a way to get the compiler to align a struct the same way regardless of target?

 

I guess my alternative is to put big warning comments in the code to manually maintain alignment if changes are made.

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

 

 

DosMan wrote:
struct for communications between them

Unless it's shared memory, why do you feel the need to maintain packing on the different targets?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The data needs to be in the same place so when it's passed around over the RS-485 comm link that connects them, they each know where it is.  That's what I meant by "common struct for communications".

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

Look at data attributes. I'm pretty sure there's one for alignment of struct members.

 

Or use a data transfer protocol like XML, JSON or Protobufs where architectural alignment does not matter.

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

This is not what 'C' language structs are for.

 

Remember that  'C' language structs are also going to be affected by target endianness, etc ...

 

You need target-specific serialisation & de-serialisation routines - like htons() , ntohs(), et al for converting between "host" and "network" formats

 

https://linux.die.net/man/3/htons

 

https://en.wikipedia.org/wiki/Serialization

 

EDIT

 

In other words, as clawson wrote:
use a data transfer protocol like XML, JSON or Protobufs where architectural alignment does not matter

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Nov 18, 2019 - 08:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The pragma statement sets compiler-specific options, which may be used by your ARM or Windows compiler. I do not think the AVR compiler supports pragmas, so as suggested you would need to use data attributes with your structure, something like:

struct __attribute__ ((packed, aligned(4))) {...};

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

Generally you want the payload on RS485 to be compact, so you don't want to pad as it is inefficient. As the others have suggested, you probably want to use serialise/deserialise functions to ensure a consistent interface across different architectures. The issue then becomes having to write ser/des functions for each packet type you implement. One solution is to use json/xml/yaml to write a packet description that is human readable and write a script in, say, python, to read this and generate the ser/des functions. Benefits of this are that the description text serves as documentation as well and can be used be testing code to validate the system. So, as part of your build process, you run the script that reads the description file and it outputs a C/C++ file that gets compiled into your code.

 

Having worked on projects where there are 100's of different messages, this technique streamlines the whole process. When you have other systems like PCs communicating, you write scripts to generate javascript/php/c# etc all from the same description file. Assuming the scripts are correct, this ensures all devices talk the same - add a new message, all codebases get updated and documented.

 

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

Such pragmas are supported by respective GCC backends.
.
The avr-gcc ABI documentation lists no supported pragmas. And that's up to date.

avrfreaks does not support Opera. Profile inactive.

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

Kartman wrote:
One solution is to use json/xml/yaml to write a packet description that is human readable and write a script in, say, python, to read this and generate the ser/des functions.

Which is, basically, what protobufs does for you ...

 

https://www.avrfreaks.net/forum/protobuf-google-protocol-buffers

 

which followed on from

 

https://www.avrfreaks.net/forum/...

 

 which references some microncontroller - including AVR - implementations ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I transfer structs between PCs and AVRs.  I've been doing this so long, I'm not sure of the details.  I don't use pack.   I think all I do is just make sure the structs won't cause the PC to put holes in them.  For example,  int16, int16, int8, is a good 5 byte struct.  int16, int8, int16, is a bad 6 byte struct.

 

I suppose the read buffer I pass to the Windows ReadFile() must be on the proper boundary.  As I recall, my structs only contain 16 bit ints and 8 bit ints.

 

Alignment means nothing to the AVR because it always accesses data 8 bits at a time.

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

I should mention that the PC and the AVR are effectively both ass backward endian.  I don't remember what the ARM is.

Last Edited: Tue. Nov 19, 2019 - 05:23 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

on some ARMs, it's optional ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Disregarding the unsolicited advice on system architecture, there is valuable information in the mention of alignment attributes. After some testing, I can present a definitive answer to my original question: The pragma pack() directive works if you also have an alignment attribute on each member of the struct. Here is a simple example (although I did not test this exact code):

#define ALIGNED_ATTR(typ) __attribute__((aligned(sizeof(typ))))

#pragma pack(push, 4)

struct data
{
    short   s ALIGNED_ATTR(short);
    long    l ALIGNED_ATTR(long);
};

#pragma pack(pop)

This will add two bytes of padding after the short to align the long on a 4-byte boundary. If the pragma pack is changed to 2, there is no padding. Note that as I mentioned before, the default optimization setting that adds  "-fpack-struct" needs to be disabled.

 

In my case, I already use a macro to define each member, so I can just modify it to include the attribute:

#define ParamData(typ, name, fcn)	typ name ALIGNED_ATTR(typ);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    short   s ALIGNED_ATTR(short);
    long    l ALIGNED_ATTR(long);

Please use int16_t, int32_t, and similar, and you might maintain some compatibility when one side goes "full-64bit."