Has anyone else got anywhere with trying to write to the flash memory at runtime?
I had a go at this last night and I think I am getting somewhere. It doesn't help that the datasheet is vague and occasionally inaccurate on the subject. This example code increments a variable and writes it to flash every time the reset button is pressed (after a 1.5 second delay the first time) - could people please test this and tell me if it works? If it works reliably then it might be possible for someone to develop it into some kind of EEPROM-emulation library.
// flash memory write example by stimmer
// call nv_load() to load data from flash
// modify nv_ram[] array (64 32-bit words)
// then call nv_save() to save back to flash (not too often!)
uint32_t nv_ram[64];
const uint32_t nv_flash[64] __attribute__((aligned(256)))={0};
//taken from ASF
__attribute__ ((section(".ramfunc")))
uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr) {
volatile uint32_t ul_status;
p_efc->EEFC_FCR = ul_fcr;
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
return (ul_status & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE));
}
void nv_load(){
for(int i=0;i<64;i++)nv_ram[i]=nv_flash[i];
}
// This is complete guesswork. The docs are all wrong!
int nv_save(){
uint32_t * nv_write = const_cast<uint32_t *> (nv_flash);
unsigned long FlashSectorNum = ((unsigned long)nv_flash - 0x80000) / 256;
Efc * efc = FlashSectorNum >= 1024 ? EFC1 : EFC0;
FlashSectorNum &= 1023;
unsigned long flash_cmd = 0;
unsigned long flash_status = 0;
flash_cmd = (0x5A << 24) | (FlashSectorNum << 8) | 0x03;
noInterrupts();
for(int i=0;i<64;i++)nv_write[i]=nv_ram[i];
flash_status = efc_perform_fcr (efc, flash_cmd);
interrupts();
return flash_status;
}
void setup() {
Serial.begin(115200);
nv_load();
if(nv_ram[6]!=9){
nv_ram[6]=9;
nv_ram[42]=1;
delay(1500);
Serial.println("This is the first time I have been run.");
// you probably won't see that unless you open the serial monitor quite soon after uploading
}
else {
Serial.print("I have been reset ");
Serial.print(nv_ram[42]);
Serial.print(" time");
Serial.println(nv_ram[42]==1 ? "." : "s.");
if(nv_ram[42]>10)Serial.println("Please don't reset me any more, as we don't know how many times the flash can be reprogrammed before it breaks.");
if(nv_ram[42]>100)Serial.println("I said stop pressing the bloody reset button you idiot!");
nv_ram[42]++;
}
nv_save();
}
void loop() {
}