This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

A possible solution for PACKED data structures in StarterWare USB

On various threads we've been discussing problems caused by the PACKED data structures in the StarterWare USB package. (These packed structures occur in the file usblib.h. If there are others, hidden within other files somewhere, then that might blow a hole in my solution.)

I discovered a possible solution that does not require a special compiler. I want your opinion.

Here is the solution: 

  1. Examine each data structure defined in usblib.h. 
  2. Identify the longest data type in the data structure (The longest is either short or int)
  3. When you declare that data structure, align it to that data type.
  4. (Or, the lazy way is to simply align them all to int.)
  5. With the TI C compiler, that is done like this:

#pragma DATA_ALIGN   ( my_structure, 4 ) // This aligns to a 4 byte boundary

It so happens that, (by chance, or was it by somone's design?...) -- for the many particular structures defined in usblib.h -- this simple alignment procedure will avoid all unaligned data accesses. The processor can access each member of each structure with one simple access (rather than two or more accesses). No special compiler required.

Two data structures in usblib.h require a slightly special handling: tConfigHeader and tUSBBuffer. These must be padded by three bytes ahead of the data structure, and aligned to an int. Then once again, there are no unaligned data accesses.

Here is a simplified example of why it works.

typedef struct
{
    char
    char
    short
    char
    char
    char
    char
    short
    short
    short
    char
    char
    char
    char
}
PACKED tDeviceDescriptor;

It so happens that each short is preceeded by an EVEN NUMBER of chars. Therefore, if the structure is aligned to a short, then each short will likewise be aligned for easy access.

==================================================================

I'm puzzled why some structures were declared as "PACKED" when they are comprised of nothing but chars, and therefore automatically have no unaligned accesses. Examples:

tDescriptorHeader
tInterfaceDescriptor
tStringDescriptor

 Likewise I'm puzzled why the two problematic structures --  tConfigHeader and tUSBBuffer -- were NOT declared as packed.  

???

 

  • I'm here adding some further explanation to my previous post.

    The usblib.h file correctly describes a PACKED data structure with this example:

    //   typedef struct _PackedStructName
    //   {
    //      unsigned int ulFirstField;
    //      char cCharMember;
    //      unsigned short usShort;
    //   }
    //   PACKED tPackedStructName;

    It is impossible to place that data structure into memory while avoiding unaligned accesses.  This data structure is "packed" in such a manner as to make that impossible. However, we can avoid that problem by re-arranging the members:

    //   typedef struct _NonPackedStructName
    //   {
    //      unsigned int ulFirstField;
    //      unsigned short usShort;
    //      char cCharMember;

    //   }
    //   tNonPackedStructName;

    This structure carries the exact same data, but is not packed.  All the data structures in usblib.h are of this latter type, that is, they are not packed, they merely need proper alignment, and you're good.  No accessing problems.  No compiler problems.  Just simple, fast, efficient data access. 

    [Side note:  I believe the TI compilers ALREADY AUTOMATICALLY ALIGN the data structures (if possible) so as to avoid accessing problems (please correct me if I'm wrong on that).  But if you want to make your code extra bullet-proof, then you can explicitly request a specific alignment, as described in my previous post.]

    As already stated, none of the many data structures in usblib.h is packed (they merely need proper alignment). So I'm still puzzled why TI declared them as packed, which caused further problems.

    I'm saying this entire issue of "PACKED" data structures may reduce to an easily solved non-issue. I hope TI will clarify this matter, as my project is on hold because of it.

  • Not familiar with Starterware but I have seen packed structures used as a quick and dirty way to define data for a stream. The data is expected at the far end in a certain sequence and format. Reordering the structure would change both.

    Technically compilers are allowed to reorder fields in structure. They can also insert bytes between fields such that fields are naturally aligned. For example, the sizeof() on a structure will rarely be equal to sum of the sizeof() on individual fields. The packed attribute forces the compiler to retain order and not add any padding between fields.

    Ideally, an incoming array of bytes would be manually unpacked into unpacked structure. An outgoing unpacked structure would be manually packed into array of bytes. All at the point of tranmission or reception. The rest of the code would use unpacked sturctures. The cost is extra processing in possible byte reordering to handle endianess and byte copying to handle alignment. You might gain that back with more efficient access to unpacked access in the rest of the code. Another cost is that each structure must be handled individually. More effort to code. The gain is more portable code.

    The think the question should be why does the code use PACKED on structures that are not used "on the wire". I'm assuming the structures you noted are not directly sent or received on the USB port. Or do the structures cross libraries or processors?

  • Norman,

    Thanks for your post.  It clarifies everything, and (sadly) shows why my proposed "solution" is not a solution. For benefit of others, I'll explain (while eating a healthy serving of humble-pie). 

    Norman Wong said:
    Technically compilers are allowed to reorder fields in a structure. They can also insert bytes between fields such that fields are naturally aligned. For example, the sizeof() on a structure will rarely be equal to sum of the sizeof() on individual fields. The packed attribute forces the compiler to retain order and not add any padding between fields.

    That explains why a special compiler is required. Basically, we need to TURN OFF a feature of the compiler. That is, the compiler ordinarily has the freedom to reorder/pad any structure (I didn't know that!), and we need to temporarily deny that freedom.  That makes sense now.  (Yet it also seems easy to build that into a compiler, since we are turning off a feature of the compiler.)

    That also explains why some structures in usblib.h are declared as "packed" while others are not. The difference is that some structures must be transmitted/received exactly as prescribed in the structure, and cannot tolerate any reordering/padding, and thus must be declared as packed.  While structures that are not transmitted/received can be freely reordered/padded by the compiler without causing problems. 

    Thanks for the insight Norman.

     

    P.S.  So I must now await confirmation from the TI guys on whether or not compiler TMS470 v4.9.1 can handle packed structures. Or whether I must divert to the GCC compiler.

  • Is this issue resolved?  TI seems silent here.

  • Hi All,

    TMS470 v4.9.1 compiler cannot handle packed data structures. Please install the latest TMS470 v5.0.1. This compiler supports packed data structures and enables the USB stack ( and ethernet drivers )to run on platforms without inherent hardware support for unaligned access .


    To install the latest compiler :  select help option in CCS window -> install new software-> In "work with" drop down menu -> select code generation tools updates -> TI compiler updates ->ARM compiler tools 5.0.1

    Regards

    Vineeth