Given that there are many differences in the way data is written to EEPROM and Flash, how exactly is EEPROM emulation done with internal flash?
Also, flash needs to be erased in large blocks before data can be written over. In that case, if we want to write only a small amount of data in emulated EEPROM without disturbing the other contents, how is it achieved? What are the software techniques for this?
Best Answer
There are probably many different algorithms to accomplish EEPROM emulation without forcing a lot of unnecessary writes. The main concept is like a ledger (except values don't depend on previous values). The data set or a variable has many "records" in the ledger. When a new value is written, the old value must be invalidated. For example, you can invalidate the old value by writing some magic value which means "that record is invalid". Then, a new record can be created. Looking up a value means reading through the ledger to find the current record. All invalidated records can be ignored. Flash pages can be erased when full (the values must all be invalid or be migrated to a new flash page before erasing).
Here's a simple, concrete algorithm example:
Let's say I have a data set of 6 bytes. I will devote 2 flash pages to emulated EEPROM for my 6 byte data set. Make the following assumptions:
Flash page header
I'll start my flash page with some sort of header to indicate that I am actively storing data there (or not). Let me use 4 bytes at the start of the flash page which indicate one of the following conditions:
Record header
For each record, I will start with a header also. Let me use 2 bytes, indicating one of the following:
Flash pages start erased
System initialization
After detecting that the EEPROM data has not been initialized, I will begin by initializing my data set to all 0s:
Notice that bytes 2-3 were not written and remain 0xFFFF. When this flash page fills up and I start a new flash page, I will write 0x5555 over bytes 2-3.
The record header essentially works the same. Byte 1 of the record #0 header remains 0xFF indicating that it is the current record (because byte 0 is 0x55).
Write the value 0xDEADBEEFCAFE
In this order:
Order is important for recovery from spurious resets (this is similar to a journal in a filesystem).
Write the value 0x12345678ABCD
The current page is full
This is what the pages look like when the current page (Page #0) is completely full (the current value is 0xAAAA5555BBBB):
Notice that flash page #0 is not yet invalidated (the current record is the last record in flash page #0).
Write the value 0x80009000ABCD
The next value must go into flash page #1. After writing the new record in flash page #1 and creating the page header to indicate that flash page #1 now contains the current value, we invalidate flash page #0 (write 0x55 to bytes 2-3) and the last record in flash page #0 (write 0x55 to the last record's header byte 1).
Now, flash page #0 is completely invalid, and the new page is Flash page #1.
Flash page #0 is garbage collected (erased)
Finally, flash page #0 can be erased when the system finds it convenient.
Record lookup, real-world complexities
In the real world, the data set would be larger and more complex than a single 6-byte chunk. There are many complexities I glossed over. This is a really simple example, but it would work. It illustrates how EEPROM can be emulated in flash without excessive erasing by creating a ledger of value records.
To look up the current data set values, find which flash page is current (one and only one flash page should have the header 0x5555FFFF). Then, read through the records in that page sequentially until finding the current record (one and only one record should have record header 0x55FF). Errors could invalidate the header configuration, potentially leading to multiple pages and/or records which appear to be current. A real application would need to handle such errors.