This is not that complicated to do.
Basically what you need is a constant global variable which will get placed in flash and define the location using a pragma.
In C++ the header might look something like this:
class FlashLookUpTable
{
public:
struct LookUpTable_t
{
uint32_t table[100];
};
public:
static LookUpTable_t const * GetLookUpTablePointer();
private:
static const uint32_t FLASH_PAGE_SIZE = 1024U; // or whatever the flash smallest deletable size is
// This variable contains the number of bytes needed to store the structure in complete flash pages
static const uint32_t ARRAY_SIZE = (sizeof(LookUpTable_t)/FLASH_PAGE_SIZE) + FLASH_PAGE_SIZE;
union FlashPageSizedStructure
{
LookUpTable_t t;
uint8_t flashpage[ARRAY_SIZE];
}
static const FlashPageSizedStructure tableInFlash;
};
And this is how the implementation looks:
// the exact pragma depends on the compiler used, this one works for IAR
// the location should be at the start of a page boundary, especially when using this union approach
#pragma location=0x800FC00U
const FlashLookUpTable::FlashPageSizedStructure FlashLookUpTable::tableInFlash =
{
// initialize values here
}
FlashLookUpTable::LookUpTable_t const * FlashLookUpTable::GetLookUpTablePointer(void) const
{
return &tableInFlash.t;
}
To write that page in flash, you need a buffer (either in RAM or in flash) with the same size of a flash page because you have to erase the page before you write it again, so an in place change of a single value is not possible.
Depending on how exactly you use it, you might need to declare the structure as volatile
. This happens especially if you access the table directly (not with a pointer like in this case).
Some compilers optimize the code in such a way, that they take the constant out of the table directly into the code. Result is, that if you change the value in your table, the value is not taken into account in the code.
The IAR compiler had some trouble (it is fixed in the current version) handling a static volatile const
so I switched to using a pointer.
If you want to change the values, you need some sort of flash algorithm.
Writing flash always consists of:
- Backup page content
- Update backup with changed values
- Erase page
- Write page
- for safety: compare written page with backup
Note for the advanced:
In some cases you can exploit that you can writes zeros to positions where a one was, so you could change a 0x7F to 0x3F, but not the other way round. In that case you don't need to do a page erase. Some controllers might not support this.