Sliders_McGee/Core/Src/NVmem.c

198 lines
4.2 KiB
C
Raw Permalink Normal View History

/**
*********************************************************************
*
* @file NVmem.c
* @brief
*
* @date 2024-07-13 12:24:17
* @author CT
*
* @details Provides an interface for reading and writting to non-volatile memory
* Operates with a shadow buffer and write timeout to minimize writes to NV-memory
*
*************************************************************************
**/
#include <stdint.h>
#include "stm32g4xx_hal.h"
#include "NVmem.h"
// write timeout
static uint32_t m_last_write = 0;
//
static int32_t m_shadow_buf_synced = 0;
//
static uint8_t m_shadow_buf[NVMEM_SIZE] = {0};
// non-volatile memory location
uint8_t __attribute__((section (".ConfigData"))) config_data[NVMEM_SIZE] __attribute__ ((aligned (2048)));
static int write_flash(void);
static uint32_t get_bank(uint32_t addr);
int32_t NVmem_init(void)
{
// TODO add CRC over section stored at end
// copy flash to shadow buffer
for (uint32_t i = 0; i < NVMEM_SIZE; i++)
{
m_shadow_buf[i] = config_data[i];
}
return (0);
}
void NVmem_service(void)
{
// if the write timeout has expried and the shadow buffer has not been synced to NVmem
if (((HAL_GetTick() - m_last_write) >= WRITE_TIMEOUT) && (!m_shadow_buf_synced))
{
// write shadow buffer to nvmem
write_flash();
// set synced flag
m_shadow_buf_synced = 1;
}
}
int32_t NVmem_write(uint8_t* data, uint32_t addr, uint32_t len)
{
// bound check
if (addr + len >= NVMEM_SIZE)
return (-1);
// write data to shadow buf
uint32_t data_index = 0;
for (uint32_t i = addr; i < len; i++)
{
m_shadow_buf[i] = data[data_index++];
}
// set sync flag to out of sync
m_shadow_buf_synced = 0;
return (0);
}
int32_t NVmem_write_immediate(uint8_t* data, uint32_t addr, uint32_t len)
{
int32_t ret = 0;
// bound check
if (addr + len >= NVMEM_SIZE)
return (-1);
// write data to shadow buf
uint32_t data_index = 0;
for (uint32_t i = addr; i < len; i++)
{
m_shadow_buf[i] = data[data_index++];
}
// write shadow buffer to nvmem
ret = write_flash();
// set synced flag
m_shadow_buf_synced = 1;
return (ret);
}
int32_t NVmem_read(uint8_t* data, uint32_t addr, uint32_t len)
{
// bound check
if (addr + len >= NVMEM_SIZE)
return (-1);
// copy data using provided pointer
uint32_t index = 0;
for (uint32_t i = addr; i < len; i++)
{
data[index++] = m_shadow_buf[i];
}
return (0);
}
/* PRIVATE FUNCTIONS */
// Read from flash
// Write to flash
int write_flash(void)
{
uint32_t page_error = 0;
HAL_StatusTypeDef status;
HAL_FLASH_Unlock();
// Erase flash area
FLASH_EraseInitTypeDef erase_init_struct;
erase_init_struct.TypeErase = FLASH_TYPEERASE_PAGES;
erase_init_struct.Banks = get_bank(NVMEM_ADDR);
erase_init_struct.Page = (NVMEM_ADDR - FLASH_BASE) / FLASH_PAGE_SIZE;
erase_init_struct.NbPages = 1;
status = HAL_FLASHEx_Erase(&erase_init_struct, &page_error);
if (HAL_OK != status)
{
HAL_FLASH_Lock();
return (-1);
}
uint64_t buf;
uint32_t len = NVMEM_SIZE;
uint32_t prog_addr = NVMEM_ADDR;
uint32_t index = 0;
while (len >= 8)
{
buf = (uint64_t)m_shadow_buf[index];
buf |= ((uint64_t)m_shadow_buf[index + 1] << 8);
buf |= ((uint64_t)m_shadow_buf[index + 2] << 16);
buf |= ((uint64_t)m_shadow_buf[index + 3] << 24);
buf |= ((uint64_t)m_shadow_buf[index + 4] << 32);
buf |= ((uint64_t)m_shadow_buf[index + 5] << 40);
buf |= ((uint64_t)m_shadow_buf[index + 6] << 48);
buf |= ((uint64_t)m_shadow_buf[index + 7] << 56);
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, prog_addr, buf);
index += 8;
prog_addr += 8;
len -= 8;
}
HAL_FLASH_Lock();
return ((int)status);
}
uint32_t get_bank(uint32_t addr)
{
uint32_t bank = 0;
uint32_t val = 0;
val = (addr - FLASH_BASE) / FLASH_BANK_SIZE;
if (0 == val)
{
bank = FLASH_BANK_1;
}
else
{
bank = FLASH_BANK_2;
}
return (bank);
}