Electronics > Microcontrollers

mapping out eeprom space

(1/4) > >>

Simon:
I have need to write a few byte to EEPROM on a SAMC (this is actually a dedicated area of the flash memory but for clarity I will refer to it as EEPROM)

I can't constantly write this data as it will wear the memory out. I would copy the data from the EEPROM at start up and hold it in a user buffer to then write it back to EEPROM on shut down.

Now in my instance I think all of my data will be uint32 anyway so I can create an array, but what about being able to deal with any data?

The only way I can think to do it is to create a structure with each variable defined.

I suppose I could do a union of my variable structure and my array.

This would probably be required anyway as a way to get data in and out by name rather than (array) address whilst the array still allows me to write code that can cycle through the memory space when writing or reading the EEPROM.

Nominal Animal:
There was a related thread recently started by peter-h you missed, ideas for storing frequently updated data in a flash chip.

Simon:
No I'm not asking about how to stop the wearing. As i said I have but a few bytes so I have made my plan. Read the data out at power up to RAM (put it into a variable). Update the variable during run as required. When power is about to be removed write the data back to the EEPROM.

So to handle the EEPROM it seems to make sense to deal in 32 bit chunks and make an array of these chunks. This means that I can keep track of pages and rows in a 3 dimensional array. The array can then be easily loaded up from the EEPROM or written to the EEPROM by cycling through each 32 bit chunk of data treating it as a uint32.

But in my program it makes sense to be able to use any data type and to use sensible names rather than eeprom[row][page][word] so I believe a union of that array and a structure would allow me to use the structured variables in the program and use the addressability of the array when I want to write the data or read it to EEPROM.

Nominal Animal:
Ah, okay.


--- Quote from: Simon on January 26, 2022, 03:35:59 pm ---But in my program it makes sense to be able to use any data type and to use sensible names rather than eeprom[row][page][word] so I believe a union of that array and a structure would allow me to use the structured variables in the program and use the addressability of the array when I want to write the data or read it to EEPROM.
--- End quote ---
The other alternative is to write a pair of functions, pack and unpack, that copy the data between global variables and EEPROM.

Because this decouples the long-term storage format from the RAM format, it lets you pick more sensible data types for each variable, and optionally save some room.  For example, it makes sense for an often-accessed value to be a full register wide integer, but if it is actually limited to a much smaller range, say -50 to +205, you can actually store it in a single unsigned byte with a fixed offset (-50).

Another benefit from this is in that especially the pack function can compare the data to be stored and the existing data, and make an executive decision whether an update is necessary or not.

However.

On SAMC, the smallest erase unit is one row, or four 64 byte pages; i.e. 256 bytes.  Do you really need all those 2048 bits to store your state?  If not, then the aforementioned wear leveling thread is applicable.

Basically, if your data fits in 127, 84, 63, 50, 41, 34, 31, ... = floor(256/n)-1 bytes with n≥2  (easier if they fit in floor(64/n)-1 bytes, since write granularity is a page and not a row), and you reserve at least two rows (eight pages, or 512 bytes) of Flash, you can efficiently reduce the wear on your Flash storage by only erasing the other (next) row when the previous one is full, and using a single additional byte as a sequential counter to indicate which one was written last.  (AFAIK, SAMC too allows multiple writes to the same Flash page as long as the previously written data is unchanged.  This means that only the 0x00 and 0xFF counter values need to be reserved for erased pages (I can't be arsed to check which one SAMC erases to) for detecting "unused" record slots that can be filled without erasing the page.

Simon:
The EEPROM will do 100'000 cycles, the machine will be powered on a few times a day, lets say 10 times.

100'000 / 10 = 10'000 days
10'000 /  5 = 2'000 weeks
2'000 / 50 = 40 years.....

i have a pack/unpack method:


--- Code: ---void read_eeprom_to_user_buffer()
{
uint8_t wordcounter ;
uint8_t pagecounter  ;
uint8_t rowcounter = 0 ;

while ( rowcounter < d_eeprom_rows)
{
pagecounter = 0 ;

while ( pagecounter < d_eeprom_pages_per_row )
{
wordcounter = 0 ;

while (wordcounter < d_eeprom_words_per_page)
{
if ( REG_NVMCTRL_INTFLAG & 0x01 )
{
v_eeprom_user_buffer[rowcounter][pagecounter][rowcounter] = register32(FLASH_USER_PAGE_ADDR + wordcounter * 4 + pagecounter * FLASH_USER_PAGE_SIZE + rowcounter * FLASH_USER_PAGE_SIZE * d_eeprom_pages_per_row ) ;
wordcounter ++ ;
}
}

pagecounter ++ ;
}

rowcounter ++ ;
}
}

--- End code ---

I do similar to write back and anther similar function goes row by row to erase the contents for the entire area ready for a bulk write.

I am using 1 256 byte row, yes they go that small. Obviously this will not work to control the entire available EEPROM space as there is 16kB of it and of RAM, this is just to store stuff that needs loading at power up and saving again at power down, like distance travelled, run time etc.

So to use that array in my program is clunky, I think I can union it with a struct so that I have variable names like eeprom.my_variable, I don't have to care where it goes in the EEPROM, the array covers the same space and will dealt with as above when it comes to storing.

so I am thinking of something like:

--- Code: ---
union {
volatile struct nv_variables
{
uint32_t metres_since_new ;
uint32_t metres_since_service ;
uint32_t decimetres_since_power_up ;
uint32_t decimetres_at_power_up ;
}  nv ;
volatile uint32_t v_eeprom_user_buffer[d_eeprom_rows][d_eeprom_pages_per_row][d_eeprom_words_per_page] ;
} nv ;


--- End code ---

so what do I call these? nv.nv.metres_since_new  or nv.metres_since_new  ?

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version