/* * nvm.c * * Created on: Nov 1, 2022 * Author: mateusz */ #include "nvm.h" #define KB *1024 #ifdef STM32L471xx #include #include #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 }