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.

Data alignment in MSP430f5419

Other Parts Discussed in Thread: MSP430F5419

Hi, Everyone!

 

I have rather simple code, but it doesn't work correct. I use MSP430f5419 in IAR WorkBench.

 

#define SWAP8(x) (((x&0xFFFFFFFF)<<32)|((x>>32)&0xFFFFFFFF))


unsigned long long TestFun(unsigned long long inValue)

{    return SWAP8(inValue);  }


void SimpleCode(unsigned char *buf, unsigned int len)

{

    unsigned int i;

    unsigned long long *ptr;

    for (i=0; i<len;i+=8)

    {

        ptr = (unsigned long long*)&buf[i];

        *ptr = TestFun(*ptr);

    }

}

....

    unsigned char Packet[512] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};

    unsigned int DataSize = 8;

    SimpleCode(Packet, DataSize)

 

 

I expected such result: 

    Packet = {0x55, 0x66, 0x77, 0x88, 0x11 ,0x22, 0x33, 0x44};

 

But I get this: 

    Packet = {0x55, 0x66, 0x77, 0x00, 0x11 ,0x22, 0x33, 0x88};

 

 

I think the problem is in data alignment. 

For example, if array "Packet" starts with abstract address 0x11, and was not align to 4-multiple address.  Then pointer "ptr" get address 0x10 (Am I right?) here:

    ptr = (unsigned long long*)&buf[i];

Then variable "inValue" is 0x0011223344556677

After SWAP8 will get       0x4455667700112233

Then Packet will have {0x55, 0x66, 0x77, 0x00, 0x11 ,0x22, 0x33, 0x88};

 

If this right, how can I align "Packet" to 4-multiple address?

Or there's some other error?

 

Best Regards, Mikhail.

  • Char arrays are byte-aligned. Any word access, however, requires word alignment. And your SWAP8 macro uses word operations. Even if the generated assembly code seems to be correct, the LSB of any odd address value in a word operation is silently ignored, so your result is exactly what I'd expect if your buffer starts (perfectly valid) at an odd address.
    The problem is that the info about the possibly unaligned char pointer is lost during your typecasting. So teh compiler assumes that the pointer points to an aligned storage place, as word (and long/long long) pointers have to point to a word aligned memory location.
    It is the programmers fault that here a possibly uneven value is cast to a pointer type that requires alignment.

    It is possible that an assignment like ptr = (unsigned long long*)buf; would give a compiler warning (since it is known that buf might be unaligned), but in the current constellation, there is no hint for the compiler that the value might be unaligned.

    Mikhail Antipov said:
    pointer "ptr" get address 0x10 (Am I right?)

    Not exactly. I twill get 0x11, but the LSB is ignored when it comes to the actual operation. So even in debugger view you won't notice what's going wrong.
    Well, you only fall into this trap once.

    Mikhail Antipov said:
    If this right, how can I align "Packet" to 4-multiple address?

    word alignment is good enough. But how to do this is compiler specific. Sometimes a pragma, sometimes an attribute, sometimes something different. Check your compiler documentation.

    An alternative that works with an input stream (whose content will resist any attempt to align it) is to write a macro that combines the long long value from individual bytes.
    You pass the real pointer (a byte pointer) and the macro will pick the bytes from it as appropriate, returning the result. That's how I did it with out RF transmissions which contain packed structs of arbitrary length and type in a huge packet. It is less efficient than word access, but the only way to deal with posibly misaligned data.

  • , thanks for quik responce!

     

    Jens-Michael Gross said:
    An alternative that works with an input stream (whose content will resist any attempt to align it) is to write a macro that combines the long long value from individual bytes.

    I've already done this. But it looks a little bit bulky.

    I'll try to find some ways to align char array in compiler documentation.


  • Mikhail Antipov said:
    I've already done this. But it looks a little bit bulky.

    Indeed. But it has the advantage that it works with unaligned data from a stream and is independent of the processor architecture (little/big endian). Even the macros are identical and therefore portable between two systems with different endianess.
    Expectign an 'INT'at some place, the outcome is different for the same data on different endianess. That's why most systems provide a system-specific implementaiton for network byte ordering (which on little endian systems like the MSP or PC does a swap, on others does nothing).

    One trick that should force alignment is to create a union between the array and an INT. Then the compiler should force the required word alignment.
    It may even be a union of a char array and a long long array. Makes addressing the long longs simpler (no need for the *8 factor in the index).

    But don't ask me how to initialize such a construct. :)

  • Jens-Michael Gross said:

    One trick that should force alignment is to create a union between the array and an INT. Then the compiler should force the required word alignment.
    It may even be a union of a char array and a long long array. Makes addressing the long longs simpler (no need for the *8 factor in the index).

    But don't ask me how to initialize such a construct.

    I agree with JMG, this is probably the most portable mechanism.  I would suggest using the largest type you intend to use for your system as that will guarantee alignment for any platform.

    By default, union initializations initialize only the first member of the union thus the initialization statement would be the same as you currently are using.

    Thus the following union declaration provides you the required alignment and initializes the data array.  Note that the aligner member of the union need not fill the entire space of the array as a single member of this type will force alignment.  In general, you will probably never access the aligner member anyway.

    union { char data[512], long long aligner } packet = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };

    To access the data it is simply

    packet.data[i];

    Note that this assumes your compiler adheres to at least the C99 standard.  Most compilers only claim they adhere to the C89 standard (C90 technically but that's another story) but even this is not always correct as when the C++ 93 spec was released many C compilers incorporated much of the additional semantics of C++ definitions which were not specifically disallowed by the C89 standard to simplify compilation of common code constructs.  Bottom line, you will have to try the syntax to see if your compiler supports it but this is pretty legacy style stuff so hopefully all will work out fine.

    Jim Noxon

**Attention** This is a public forum