/*
* nvram.c
*
* Created on: 4 Jun 2017
* Author: Mike
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32l1xx_hal.h"
#include "nvram.h"
// NVRAM hardware erases to all 0x
nvram_info_t const HARDWARE_ERASED = {.u32 = 0UL};
// Marked as erased change to all 1
nvram_info_t const MARKED_ERASED = {.u32 = ~0UL};
// marked as unusable change pattern to something in between
nvram_info_t const MARKED_UNUSABLE = {.u32 = 0x55555555UL};
nvram_info_t NVRAM_Base[NVRAM_WORDS] __attribute__((section(".NVRAM_Data"))); // set by linker
static void
WriteNVRAM(nvram_info_t *Address, nvram_info_t data)
{
HAL_FLASHEx_DATAEEPROM_Unlock();
HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_WORD, (uint32_t)Address, data.u32);
HAL_FLASHEx_DATAEEPROM_Lock();
}
static void
EraseNVRAM(nvram_info_t *Address)
{
HAL_FLASHEx_DATAEEPROM_Unlock();
HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEERASEDATA_WORD, (uint32_t)Address);
HAL_FLASHEx_DATAEEPROM_Lock();
}
void write_nvram_data(nvram_info_t data)
{
int base = 0;
/* search blank */
for (int ptr = 0; ptr < NVRAM_WORDS; ptr++)
{
// erase the entry just found
if (NVRAM_Base[ptr].data.tag == data.data.tag)
{
// erase previous data, delete any entries that have a matching tag
WriteNVRAM(&NVRAM_Base[ptr], MARKED_ERASED);
// record the next location to the marked erased location
// so that future writes occur further along in the Flash
if (base == 0)
base = ptr;
}
}
// search forward for next erased or empty element, use it
for (int offset = 1; offset < NVRAM_WORDS + 1; offset++)
{
int index = (base + offset) % NVRAM_WORDS;
if (NVRAM_Base[index].u32 == MARKED_ERASED.u32 || NVRAM_Base[index].u32 == HARDWARE_ERASED.u32)
{
if (NVRAM_Base[index].u32 != HARDWARE_ERASED.u32)
EraseNVRAM(&NVRAM_Base[index]);
WriteNVRAM(&NVRAM_Base[index], data);
// now check to see if it actually went
if (NVRAM_Base[index].u32 != data.u32)
{
WriteNVRAM(&NVRAM_Base[index], MARKED_UNUSABLE); // mark as neither unused or used
continue;
}
return;
}
}
}
nvram_info_t *find_nvram_data(uint8_t searchTag)
{
for (int ptr = 0; ptr < NVRAM_WORDS; ptr++)
{
if (NVRAM_Base[ptr].data.tag == searchTag)
return &NVRAM_Base[ptr];
}
return NULL;
}
void erase_nvram()
{
/* search blank */
for (int ptr = 0; ptr < NVRAM_WORDS; ptr++)
{
EraseNVRAM(&NVRAM_Base[ptr]);
}
}