Hello,
I am working on a project which uses the eeporm of the LPC1837JET100.
At some point our code has stopped working.
I have check our version control and could not find a change.
So I started experimenting and found a problem when writing to the eeprom with a hard-coded value.
#include "board.h"
typedef struct
{
volatile unsigned value_a;
volatile unsigned value_b;
volatile unsigned value_c;
volatile unsigned value_d;
volatile unsigned value_e;
} __attribute__((aligned(1),packed)) TMemory_structure;
int main(void)
{
//init eeprom
Chip_Clock_Enable(CLK_MX_EEPROM);
Chip_EEPROM_Init(LPC_EEPROM);
Chip_EEPROM_SetAutoProg(LPC_EEPROM, EEPROM_AUTOPROG_AFT_1WORDWRITTEN);
//get pointer to eeprom
volatile TMemory_structure* data = (TMemory_structure*)EEPROM_ADDRESS(0,0);
//prepare values
static const unsigned value_in_program = 0x12345678;
unsigned value_in_ram = 0x87654321;
//write value in ram to eeprom
data->value_d = value_in_ram;
//wait for operation to compete
while( (LPC_EEPROM->INTSTAT & EEPROM_INT_ENDOFPROG) == 0);
LPC_EEPROM->INTSTATCLR = EEPROM_INT_ENDOFPROG;
//write value in program to eeprom
data->value_d = value_in_program;
volatile static int i = 0 ;
while(1) {
i++ ;
}
return 0 ;
}
In this example line 34 will not write data to the eeprom.
For this to fail you have to have the following situation.
If you have this situation the compiler will generate 4 strb instructions to write to the eeprom.
Instead of a single str instruction.
24 unsigned value_in_ram = 0x87654321;
1a00042a: ldr r3, [pc, #104] ; (0x1a000494 <main()+136>)
1a00042c: str r3, [r7, #0]
27 data->value_d = value_in_ram;
1a00042e: ldr r3, [r7, #4]
1a000430: ldr r2, [r7, #0]
1a000432: str r2, [r3, #12]
// skip some lines //
34 data->value_d = value_in_program;
1a000456: ldr r3, [r7, #4]
1a000458: ldrb r2, [r3, #12]
1a00045a: movs r2, #0
1a00045c: orr.w r2, r2, #120 ; 0x78
1a000460: strb r2, [r3, #12]
1a000462: ldrb r2, [r3, #13]
1a000464: movs r2, #0
1a000466: orr.w r2, r2, #86 ; 0x56
1a00046a: strb r2, [r3, #13]
1a00046c: ldrb r2, [r3, #14]
1a00046e: movs r2, #0
1a000470: orr.w r2, r2, #52 ; 0x34
1a000474: strb r2, [r3, #14]
1a000476: ldrb r2, [r3, #15]
1a000478: movs r2, #0
1a00047a: orr.w r2, r2, #18
1a00047e: strb r2, [r3, #15]
While the assembly will write the value to the address of the eeprom. The eeprom will not save the data.
In the user manual of the LPC18xx I found the reason this would not work.
The first step is writing a minimum of 1 word (4 bytes) to a maximum of 32 words (128 bytes)
to the desired page in the 16 kB EEPROM address space at address 0x2004 0000.
I assume writing a byte at a time does not count.
My question is why does the compiler use the strb instruction 4 times instead of 1 str instruction.
There are 5 asm instructions to copy a value from program to ram to eeprom.
And 17 instructions to copy a value from program to eeprom.
Skipping ram uses 12 instructions more.
It could have loaded the value from program in r2 and then stored it in eeprom, using 2 instructions. (3 instructions if we include loading r3 with a pointer to the eeprom.)
While I do not mind using a few instructions more while optimization is turned off for debugging.
In this case the eeprom peripheral will not save the data because it needs a write of 4 bytes instead of 4 writes of a byte.
I found a few way to get the code to work.
However I would like to know if there is a way to make sure the str instruction is used.
Because the ways I have found feel like they should not be needed.
已解决! 转到解答。
You asked:
My question is why does the compiler use the strb instruction 4 times instead of 1 str instruction.
Answer:
To write a 4 byte value in a single write, it MUST be 4-byte aligned, and the compiler must KNOW that it is guaranteed to be 4-byte aligned. You can do this by declaring a value as
int x __attribute__ ((aligned (4))) = 0;
You asked:
My question is why does the compiler use the strb instruction 4 times instead of 1 str instruction.
Answer:
To write a 4 byte value in a single write, it MUST be 4-byte aligned, and the compiler must KNOW that it is guaranteed to be 4-byte aligned. You can do this by declaring a value as
int x __attribute__ ((aligned (4))) = 0;