Go Down

Topic: Writing to flash / EEPROM emulation (Read 2820 times) previous topic - next topic

stimmer

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.

Code: [Select]
// 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() {
}
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

cmaglie

I've started something here, if you want to give it a look:

https://github.com/cmaglie/Flash

but honestly I'm not satisfied with the API I come up, I didn't exclude a complete refactoring.
C.

Go Up