I'm using an AT91SAM7 uC and have inherited some C code which is giving me fits. When I run this code I get a data abort error. I've tracked down the offending line of code, and it appears to be caused by something like this:
n = (UINT8) ((UINT16*)(pObject->pVar))[0];
pObject->pVar points to an instance of a structure like this:
typedef __packed struct{ UINT16 v1; UINT32 v2; UINT32 v3; UINT32 v4; UINT32 v5; }OBJTYPE; OBJTYPE xxx = {0,0,0,0,0};
When I stop the debugger on the line that causes the data abort error, I can see that pObject->pVar is pointing to 0x00200173. Is the data abort error happening because that object is not on a 32-bit boundary in memory? If so, how can I [easily] fix that? I've been going through all the online doc's reading about __packed, #pragma pack(n), adding unions to typedefs, etc.; but all the things I've been trying have not fixed the problem.
Is there an easy way (besides the __at__ attribute) to get variables like the above structure to be aligned on 32-bit boundaries?
Can anyone give me a suggestion for how to resolve this problem?
Help... Dave.
Hi Per,
Many thanks to your help.
I found a page: http://www.keil.com/support/docs/3194.htm
So, I guess, the "evil solution" for the menthioned problem might be?
n = (UINT8) ((__packed UINT16*)(pObject->pVar))[0];
I don't understand why you typecast to a pointer to a 16-bit value if your goal is to throw away the upper 8 bits. Why not use a pointer to a 8-bit value in the first place?
It is only when the pointer points to a "magic" memory address - such as in some cases a SFR - that you may have to read out both bytes at the same time, even if the goal is just to keep one of them.
Why not use a pointer to a 8-bit value in the first place?
As the OP said, the code is inherited, so I guess in practical term nobody can provide the answer. It could be anything ranging from some strange coding style convention to plain incompetence...
Well... here's something funny...
I used a #define and an edit macro to create two copies of the 1st line of each typedef. The goal was to allow conditionally deleting __packed from the typedef's for a little experimentation.
As expected, after removing them, the data abort error went away. What I didn't expect was that the code didn't break. In other words, all the other stuff that used these objects still worked. The really good thing was that the part I enabled (that made the data abort error show up in the first place) just started working.
Who says nice things don't happen once in a while.
Thanks for urging me to remove __packed from all these typedefs. Now I'm really curious, though, why were they there in the first place? They surely don't look like they were needed.
Just to close the loop on using the 8-bit cast to access the 1st 16-bit element in each object definition, I have no idea why that casting was done that strange way. But, this code is full of really odd stuff that would seem to violate any style/coding convention I've ever seen.
Thanks again. Dave.
I can see three reasons for packing.
1) You need to match the memory layout of a memory-mapped device.
2) You need to conserve space.
3) You are lazy and want to access packed structures in file systems or files directly, instead of creating a #define or a helper function for reading/writing the potentially unaligned values.
Note that for 1 and 3, you may also have to take byte order into account, in which case it may not help to pack.
An ARM chip is normally fast enough that you can write code to explicitly pack/unpack data, instead of having the compiler pack the structures. That will help if moving to another compiler or processor.