SP8EBC-ParaTNC/src/nvm.c

353 wiersze
7.6 KiB
C

/*
* nvm.c
*
* Created on: Nov 1, 2022
* Author: mateusz
*/
#include "nvm.h"
#define KB *1024
#ifdef STM32L471xx
#include <stm32l4xx_hal_cortex.h>
#include <stm32l4xx.h>
#include "./drivers/l4/flash_stm32l4x.h"
//!< Size of single flash memory page
#define NVM_PAGE_SIZE 2048
//!< How flash program operation are aligned, how many bytes must be programmed at once
#define NVM_WRITE_BYTE_ALIGN 8
#endif
//#define NVM_MEASUREMENT_OFFSET 0
//!< Size of NVM data logger in pages
#define NVM_MEASUREMENT_PAGES_USED 96
//!< Size of NVM data logger in bytes
#define NVM_MEASUREMENT_MAXIMUM_SIZ (NVM_PAGE_SIZE * NVM_MEASUREMENT_PAGES_USED)
//!< A macro to calculate start address of last page for NVM data logger
#define START_OF_LAST_NVM_PAGE (nvm_base_address + NVM_MEASUREMENT_MAXIMUM_SIZ - NVM_PAGE_SIZE)
//!< Base address of NVM data logger for device with 1MB of Flash
#define LOGGER_BASE_ADDRESS_1MB_DEVICE 0x08080000 // Page 256 from 511
#define LOGGER_BASE_ADDRESS_512K_DEVICE 0x08040000 // Page 256 from 383 (warning! there are no pages within 128-255)
uint32_t nvm_base_address = 0;
//!< Start address of flash page used currently for NVM
uint32_t nvm_current_page_address = 0;
/**
* Pointer to
*/
uint8_t * nvm_data_ptr = 0;
nvm_state_result_t nvm_general_state = NVM_UNINITIALIZED;
#define WAIT_FOR_PGM_COMPLETION \
while (1) {\
flash_status = FLASH_GetBank1Status(); \
\
if (flash_status == FLASH_BUSY) { \
; \
} \
else if (flash_status == FLASH_ERROR_PG) { \
nvm_general_state = NVM_PGM_ERROR; \
break; \
} \
else { \
break; \
} \
} \
void nvm_measurement_init(void) {
uint8_t data = 0;
// flash operation result
FLASH_Status flash_status = 0;
#if defined(STM32L471xx)
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
nvm_base_address = LOGGER_BASE_ADDRESS_1MB_DEVICE;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
nvm_base_address = LOGGER_BASE_ADDRESS_512K_DEVICE;
}
else {
// unknown device ??
nvm_general_state = NVM_INIT_ERROR;
return;
}
// find the first non-erased page
for (uint32_t i = nvm_base_address; i < (nvm_base_address + NVM_MEASUREMENT_MAXIMUM_SIZ); i += NVM_PAGE_SIZE) {
// get the content of first byte
data = *((uint8_t*) i);
// check if data is in erased state
if (data == 0xFF) {
// first byte is erased, set data pointer to start of this page
nvm_data_ptr = (uint8_t*) i;
// and break from the loop
break;
}
// get the last byte of flash memory page
data = *(((uint8_t*) i + NVM_PAGE_SIZE - 1));
if (data == 0xFF) {
// last byte is not erased
nvm_data_ptr = (uint8_t*) i;
break;
}
}
// if free flash memory page has been found
if (nvm_data_ptr != 0) {
// go through memory page and find clean (erased state) 64 bit word
for (int i = 0; i < NVM_PAGE_SIZE; i += NVM_WRITE_BYTE_ALIGN) {
// get this byte
data = *(nvm_data_ptr + i);
if (data == 0xFF) {
// rewind data pointer to this byte
nvm_data_ptr += i;
// and break the loop
break;
}
}
// program initialization mark
// unlock flash memory
FLASH_Unlock();
// enable programming
FLASH->CR |= FLASH_CR_PG;
*((uint32_t*)(nvm_data_ptr)) = 0xDEADBEEFu;
WAIT_FOR_PGM_COMPLETION
*((uint32_t*)(nvm_data_ptr)+ 1) = 0x00000000u;
WAIT_FOR_PGM_COMPLETION
if (nvm_general_state != NVM_PGM_ERROR) {
nvm_data_ptr += NVM_WRITE_BYTE_ALIGN;
nvm_general_state = NVM_OK;
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
FLASH_Lock();
}
else {
// ig no there is no space on the flash memory
nvm_general_state = NVM_NO_SPACE_LEFT;
}
#endif
}
nvm_state_result_t nvm_measurement_store(nvm_measurement_t * data) {
nvm_state_result_t out = NVM_OK;
#if defined(STM32L471xx)
volatile uint32_t * src = (uint32_t *)data;
uint32_t next_page_addr = 0;
// flash operation result
FLASH_Status flash_status = 0;
// check if there is a room for storage
if (nvm_general_state == NVM_NO_SPACE_LEFT) {
// erase first page of NVM flash area
nvm_data_ptr = (uint8_t*)nvm_base_address;
flash_status = FLASH_ErasePage(nvm_data_ptr);
if (flash_status == FLASH_COMPLETE) {
nvm_general_state = NVM_OK;
}
else {
nvm_general_state = NVM_PGM_ERROR;
}
}
else {
// check if currently last page is used
if ((uint32_t)nvm_data_ptr < START_OF_LAST_NVM_PAGE) {
// if not check if next page of flash memory is erased or not
if (*(nvm_data_ptr + NVM_PAGE_SIZE) != 0xFF) {
// an address somewhere within the next page of memory
next_page_addr = (uint32_t)nvm_data_ptr + NVM_PAGE_SIZE;
// a start of next flash page
next_page_addr = (next_page_addr / NVM_PAGE_SIZE) * NVM_PAGE_SIZE;
flash_status = FLASH_ErasePage(next_page_addr);
if (flash_status != FLASH_COMPLETE) {
nvm_general_state = NVM_PGM_ERROR;
}
}
}
}
FLASH_Unlock();
// check if NVM has been initialized and it is ready to work
if (nvm_general_state != NVM_UNINITIALIZED) {
// check if there is a room to store this measurement
if (nvm_general_state != NVM_NO_SPACE_LEFT) {
// enable programming
FLASH->CR |= FLASH_CR_PG;
// progam this measurement
for (int i = 0 ; i < NVM_RECORD_SIZE / 4; i++) {
*((uint32_t*)(nvm_data_ptr) + i) = *(src + i);
WAIT_FOR_PGM_COMPLETION
if (flash_status != FLASH_COMPLETE) {
break;
}
}
// move data pointer
nvm_data_ptr += NVM_WRITE_BYTE_ALIGN;
// and check if an end has
if ((uint32_t)nvm_data_ptr < nvm_base_address + NVM_MEASUREMENT_MAXIMUM_SIZ) {
;
}
else {
out = NVM_NO_SPACE_LEFT;
nvm_general_state = NVM_NO_SPACE_LEFT;
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
}
}
FLASH_Lock();
#endif
return out;
}
void nvm_erase_all(void) {
#if defined(STM32L471xx)
uint32_t base_address = 0;
FLASH_Unlock();
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = 0x08080000;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = 0x08040000;
}
else {
return;
}
for (int i = 0; i < NVM_MEASUREMENT_PAGES_USED; i++) {
FLASH_ErasePage(base_address + (i * NVM_PAGE_SIZE));
}
FLASH_Lock();
#endif
}
void nvm_test_prefill(void) {
#if defined(STM32L471xx)
uint32_t * base_address = 0;
// flash operation result
FLASH_Status flash_status = 0;
FLASH_Unlock();
// enable programming
FLASH->CR |= FLASH_CR_PG;
// check current flash size
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = (uint32_t *)0x08080000;
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = (uint32_t *)0x08040000;
}
else {
return;
}
// program first 10 pages of flash with 0xABCDABCD / 0x99889988
for (int i = 0; i < 10; i++) {
// flash programming must be 64 bit (8 bytes) aligned
for (int j = 0; j < NVM_PAGE_SIZE / 8; j++) {
*(base_address++) = 0xABCDABCD;
WAIT_FOR_PGM_COMPLETION
*(base_address++) = 0x99889988;
WAIT_FOR_PGM_COMPLETION
}
}
if (FLASH_SIZE == 1024 KB) {
// 1024KB
base_address = (uint32_t *)(0x08080000 + 11 * NVM_PAGE_SIZE);
}
else if (FLASH_SIZE == 512 KB) {
// 512KB
base_address = (uint32_t *)(0x08040000 + 11 * NVM_PAGE_SIZE);
}
else {
return;
}
for (int i = 11; i < NVM_MEASUREMENT_PAGES_USED; i++) {
// flash programming must be 64 bit (8 bytes) aligned
for (int j = 0; j < NVM_PAGE_SIZE / 8; j++) {
*(base_address++) = 0x12345678;
WAIT_FOR_PGM_COMPLETION
*(base_address++) = 0x99999999;
WAIT_FOR_PGM_COMPLETION
}
}
// disable programming
FLASH->CR &= (0xFFFFFFFF ^ FLASH_CR_PG);
FLASH_Lock();
#endif
}