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 the current compiler. (I am convinced the code has worked a year ago.)
- Do not have the compiler set to optimize. (For debugging)
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.
- Coping a value to ram and then writing to eeprom.
This would add an extra step which could easily be forgotten why it is required. - Or enabling optimization.
This would make debugging a large project very difficult.
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.