Proper way to write to flash memory

Here’s what I’m trying to do.

I have a rather large array defined const unsigned char varName[] = {...} so that it will be placed into the flash memory on the Core. I would like to now modify this data.

I tried to use FLASSH_ProgramHalfWord since this is the function used to write to the virtual EEPROM but no dice. I also tried memcpy but it produced a hard fault :frowning: Below is my code. Suggestions? What’s the proper way to do this?

#include "application.h"

SYSTEM_MODE(MANUAL);

const unsigned char flashVar[] = {0xFF, 0x00, 0x99};

char buff[100];
int test = 3;
/* This function is called once at start up ----------------------------------*/
void setup()
{
    Serial.begin(9600);
    while(!Serial.available()) Spark.process();
    Serial.println("Program Start - Version 1.5");
    Serial.print("Flash Var Address: ");
    
    sprintf(buff,"The memory address of 'test' is: %p\n", (void*) &test);
    Serial.println(buff);
    
    sprintf(buff,"The memory address of 'flashVar[0]' is: %p and the value is '%x'\n", (void*) &flashVar[0], flashVar[0]);
    Serial.println(buff);
    
    sprintf(buff,"The memory address of 'flashVar[1]' is: %p and the value is '%x'\n", (void*) &flashVar[1], flashVar[1]);
    Serial.println(buff);
    
    sprintf(buff,"The memory address of 'flashVar[2]' is: %p and the value is '%x'\n", (void*) &flashVar[2], flashVar[2]);
    Serial.println(buff);
    
    uint32_t EepromAddress = (uint32_t)&flashVar[0];
    uint16_t EepromData = 0xeeee;
    
    sprintf(buff,"The memory address of 'flashVar[0]' is: %x and the data to be written is '%x'\n", EepromAddress, EepromData);
    Serial.println(buff);
    
    // This doesn't seem to do anything
    FLASH_ProgramHalfWord(EepromAddress, EepromData);
    
    // This causes a hard fault
    memcpy((void *)EepromAddress,&EepromData,1);
    
    sprintf(buff,"The memory address of 'flashVar[0]' is: %p and the value is '%x'\n", (void*) &flashVar[0], flashVar[0]);
    Serial.println(buff);
    
    sprintf(buff,"The memory address of 'flashVar[1]' is: %p and the value is '%x'\n", (void*) &flashVar[1], flashVar[1]);
    Serial.println(buff);
    
    sprintf(buff,"The memory address of 'flashVar[2]' is: %p and the value is '%x'\n", (void*) &flashVar[2], flashVar[2]);
    Serial.println(buff);
    
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    //This will run in a loop
}

The proper way would be to use the EEPROM class. Something like this…

for(int i = 0; i < sizeof( flashVar ); i++)
      EEPROM.write(i, flashVar[i] );

for(int i = 0; i < sizeof( flashVar ); i++)
      flashVar[i] = EEPROM.read(i);

The lower level functions look a bit more difficult, so let the firmware handle the EEPROM_START_ADDRESS, and unlocking the pages they have designated for user data. It can save you headaches if anything changes.

Thanks for the reply. Sadly I need far more than 100 bytes of memory. Any other suggestions? I do appreciate the help!

It looks like the limit of 100 bytes is just save RAM because the 2 pages that can be accessed safely (I think) can give you 2K to play with. If that’s enough, you can do it yourself.

Just going by their code, first call FLASH_Unlock(), then status = FLASH_ErasePage(PAGE0_BASE_ADDRESS) which will set 1K of space to FF. (EEPROM programming can only open connections making zeros). Or status = EEPROM_Format() which looks like it erases both pages at once but writes VALID_PAGE to the first 2 bytes of each page.

Then to write up to 2048 bytes. Also make sure you have an even number of bytes in your array.

unit16_t *pFlashData = (uint16_t *)flashVar;
uint32_t Address = PAGE0_BASE_ADDRESS;
for(int index = 0; index < sizeof(flashVar); index ++)
        FLASH_ProgramHalfWord(Address + (index<<1), pFlashData[index]);

To read…

for(int index = 0; index < sizeof(flashVar); index ++)
        pFlashData[index] = ((__IO uint16_t *)Address)[index];

Eidt: or
memcpy(flashVar, (__IO unint16_t *)PAGE0_BASE_ADDRESS, sizeof(flashVar) );

I’m probably getting something wrong with casting all over this. The main thing is to erase before writing, and do all the I/O in 16 bit, and get the addressing correct. Actually, the reads may work in 8 bit come to think of it, but it’s probably easier to implement this way.