176 lines
3.8 KiB
C
176 lines
3.8 KiB
C
|
/**
|
||
|
*********************************************************************
|
||
|
*
|
||
|
* @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 "stm32g0xx_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);
|
||
|
|
||
|
int32_t NVmem_init(void)
|
||
|
{
|
||
|
// 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
|
||
|
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 = FLASH_BANK_1;
|
||
|
erase_init_struct.Page = (0x801F800 - 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 = 0x801F800;
|
||
|
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);
|
||
|
}
|