Hi All and thanks for the responses.
Considering everything, I'll show what I've learned. I figure some
people would be interested.
I'm compiling with low optimization. Compiling with high optimization
fixed the problem. So if I let the compiler optimize more, no need for fixes.
Go figure.
I'll show the disassembly below. For the disassembly, I've created a
simpler function that replicates the error. It is
void AT45_Read(unsigned long addr, unsigned char* buffer, unsigned int len) {
volatile unsigned long tempLong; //use volatile keyword for it to work.
tempLong = AT45_DeviceID();
buffer[0] = *((unsigned char*)(&tempLong)+0);
buffer[1] = *((unsigned char*)(&tempLong)+1);
buffer[2] = *((unsigned char*)(&tempLong)+2);
buffer[3] = *((unsigned char*)(&tempLong)+3);
buffer[5] = 0x00;
}
Here is the disassembly from the working code:
void AT45_Read(unsigned long addr, unsigned char* buffer, unsigned int len) {
Next label is a Thumb label
AT45_Read:
0x00006D7C B510 PUSH {R4, LR}
0x00006D7E B081 SUB SP, SP, #4
0x00006D80 1C0C MOV R4, R1
tempLong = AT45_DeviceID();
0x00006D82 F7FF ; pre BL/BLX
0x00006D84 FFD9 BL AT45_DeviceID ; 0x6D38
0x00006D86 9000 STR R0, [SP, #0]
buffer[0] = *((unsigned char*)(&tempLong)+0);
0x00006D88 4668 MOV R0, SP
0x00006D8A 7800 LDRB R0, [R0, #0]
0x00006D8C 7020 STRB R0, [R4, #0]
buffer[1] = *((unsigned char*)(&tempLong)+1);
0x00006D8E 4668 MOV R0, SP
0x00006D90 7840 LDRB R0, [R0, #1]
0x00006D92 7060 STRB R0, [R4, #1]
buffer[2] = *((unsigned char*)(&tempLong)+2);
0x00006D94 4668 MOV R0, SP
0x00006D96 7880 LDRB R0, [R0, #2]
0x00006D98 70A0 STRB R0, [R4, #2]
buffer[3] = *((unsigned char*)(&tempLong)+3);
0x00006D9A 4668 MOV R0, SP
0x00006D9C 78C0 LDRB R0, [R0, #3]
0x00006D9E 70E0 STRB R0, [R4, #3]
buffer[5] = 0x00;
0x00006DA0 2000 MOV R0, #0
0x00006DA2 7160 STRB R0, [R4, #5]
}
0x00006DA4 B001 ADD SP, SP, #4
0x00006DA6 BC10 POP {R4}
0x00006DA8 BC01 POP {R0}
0x00006DAA 4700 BX R0
0x00006DAC 8004 STRH R4, [R0, #0]
0x00006DAE E002 B 0x006DB6
Here is the disassembly from the non-working code (volatile keyword removed)
void AT45_Read(unsigned long addr, unsigned char* buffer, unsigned int len) {
Next label is a Thumb label
AT45_Read:
0x00006D7C B510 PUSH {R4, LR}
0x00006D7E B082 SUB SP, SP, #8
0x00006D80 1C0C MOV R4, R1
tempLong = AT45_DeviceID();
0x00006D82 F7FF ; pre BL/BLX
0x00006D84 FFD9 BL AT45_DeviceID ; 0x6D38
0x00006D86 9001 STR R0, [SP, #4]
buffer[0] = *((unsigned char*)(&tempLong)+0);
0x00006D88 4668 MOV R0, SP
0x00006D8A 7900 LDRB R0, [R0, #4]
0x00006D8C 7020 STRB R0, [R4, #0]
buffer[1] = *((unsigned char*)(&tempLong)+1);
0x00006D8E 4668 MOV R0, SP
0x00006D90 7840 LDRB R0, [R0, #1]
0x00006D92 7060 STRB R0, [R4, #1]
buffer[2] = *((unsigned char*)(&tempLong)+2);
0x00006D94 4668 MOV R0, SP
0x00006D96 7880 LDRB R0, [R0, #2]
0x00006D98 70A0 STRB R0, [R4, #2]
buffer[3] = *((unsigned char*)(&tempLong)+3);
0x00006D9A 4668 MOV R0, SP
0x00006D9C 78C0 LDRB R0, [R0, #3]
0x00006D9E 70E0 STRB R0, [R4, #3]
buffer[5] = 0x00;
0x00006DA0 2000 MOV R0, #0
0x00006DA2 7160 STRB R0, [R4, #5]
}
0x00006DA4 B002 ADD SP, SP, #8
0x00006DA6 BC10 POP {R4}
0x00006DA8 BC01 POP {R0}
0x00006DAA 4700 BX R0
0x00006DAC 8004 STRH R4, [R0, #0]
0x00006DAE E002 B 0x006DB6
In the correct code, SP points to the address 0x40003CBC
In the incorrect code, SP points to the address 0x40003CB8
Makes sense since the incorrect code is subtracting 8, not 4.
Here are the values at the memory:
0x40003CB8 9b 85 00 40
0x40003CBC 1f 26 00 00
The correct code stores 1f 26 00 00 in buffer
The incorrect code stores 1f 85 00 40 in buffer
Makes sense since the incorrect code goes to the stack pointer, and indexes 4
into it, then 1 2 3
And the correct code goes to the stack pointer and indexes 0, then 1, 2, 3
So I'm guessing the compiler is doing something wrong. Maybe I'll let
IAR know.
Thanks again for everyone's interest.
>>> On 2007-03-14 at 19:43, d...@ovro.caltech.edu
wrote:
>> So my first guess is that this is an endianness
issue ...
>
> The LPCs are little endian. Although ARMs in general can be either.
I knew the ARM core could be both, but couldn't remember
which the LPC implemented.
I'm working on FPGA code that interfaces to a big-endian
PowerPC, using little-endian-centric FPGA JTAG debugging tools,
so endianness issues are currently near-and-dear ;)
Cheers
Dave