/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file flash_if.c * @author MCD Application Team * @brief This file provides set of firmware functions to manage Flash * Interface functionalities. ****************************************************************************** * @attention * * Copyright (c) 2021 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "flash_if.h" #include "stm32_mem.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* External variables ---------------------------------------------------------*/ /* USER CODE BEGIN EV */ /* USER CODE END EV */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /** * @brief Flash empty status enumeration */ enum { FLASH_IF_MEM_EMPTY = 0, FLASH_IF_MEM_NOT_EMPTY = 1 }; /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /** * @brief Get internal flash page index from page address */ #define PAGE_INDEX(__ADDRESS__) (uint32_t)((((__ADDRESS__) - FLASH_BASE) % FLASH_BANK_SIZE) / FLASH_PAGE_SIZE) /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ static uint8_t *pAllocatedBuffer = NULL; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* Private Functions prototypes: internal flash ------------------------------*/ /** * @brief This function writes a data buffer in flash (data are 64-bit aligned). * * @note After writing data buffer, the flash content is checked. * @param pDestination: Start address for target location. It has to be 8 bytes aligned. * @param pSource: pointer on buffer with data to write * @param uLength: Length of data buffer in bytes. It has to be 8 bytes aligned. * @return FLASH_IF_StatusTypedef status */ static FLASH_IF_StatusTypedef FLASH_IF_INT_Write(void *pDestination, const void *pSource, uint32_t uLength); /** * @brief This function reads flash * * @param pDestination: Start address for target location * @param pSource: flash address to read * @param uLength: number of bytes * @return FLASH_IF_StatusTypedef status */ static FLASH_IF_StatusTypedef FLASH_IF_INT_Read(void *pDestination, const void *pSource, uint32_t uLength); /** * @brief This function does an erase of n (depends on Length) pages in user flash area * * @param pStart pointer of flash address to be erased * @param uLength number of bytes * @return FLASH_IF_StatusTypedef status */ static FLASH_IF_StatusTypedef FLASH_IF_INT_Erase(void *pStart, uint32_t uLength); /** * @brief This function checks if part of Flash is empty * * @param pStart flash address to check * @param uLength number of bytes to check. It has to be 8 bytes aligned. * @return int32_t FLASH_IF_MEM_EMPTY or FLASH_IF_MEM_NOT_EMPTY */ static int32_t FLASH_IF_INT_IsEmpty(void *pStart, uint32_t uLength); /** * @brief Clear error flags raised during previous operation * * @retval FLASH_IF_StatusTypedef status */ static FLASH_IF_StatusTypedef FLASH_IF_INT_Clear_Error(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Exported functions --------------------------------------------------------*/ FLASH_IF_StatusTypedef FLASH_IF_Init(void *pAllocRamBuffer) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_OK; /* USER CODE BEGIN FLASH_IF_Init_1 */ /* USER CODE END FLASH_IF_Init_1 */ pAllocatedBuffer = (uint8_t *)pAllocRamBuffer; /* USER CODE BEGIN FLASH_IF_Init_2 */ /* USER CODE END FLASH_IF_Init_2 */ return ret_status; } FLASH_IF_StatusTypedef FLASH_IF_DeInit(void) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_OK; /* USER CODE BEGIN FLASH_IF_DeInit_1 */ /* USER CODE END FLASH_IF_DeInit_1 */ pAllocatedBuffer = NULL; /* USER CODE BEGIN FLASH_IF_DeInit_2 */ /* USER CODE END FLASH_IF_DeInit_2 */ return ret_status; } FLASH_IF_StatusTypedef FLASH_IF_Write(void *pDestination, const void *pSource, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_ERROR; /* USER CODE BEGIN FLASH_IF_Write_1 */ /* USER CODE END FLASH_IF_Write_1 */ if (IS_FLASH_MAIN_MEM_ADDRESS((uint32_t)pDestination)) { ret_status = FLASH_IF_INT_Write(pDestination, pSource, uLength); } /* USER CODE BEGIN FLASH_IF_Write_2 */ /* USER CODE END FLASH_IF_Write_2 */ return ret_status; } FLASH_IF_StatusTypedef FLASH_IF_Read(void *pDestination, const void *pSource, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_ERROR; /* USER CODE BEGIN FLASH_IF_Read_1 */ /* USER CODE END FLASH_IF_Read_1 */ if (IS_FLASH_MAIN_MEM_ADDRESS((uint32_t)pSource)) { ret_status = FLASH_IF_INT_Read(pDestination, pSource, uLength); } /* USER CODE BEGIN FLASH_IF_Read_2 */ /* USER CODE END FLASH_IF_Read_2 */ return ret_status; } FLASH_IF_StatusTypedef FLASH_IF_Erase(void *pStart, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_ERROR; /* USER CODE BEGIN FLASH_IF_Erase_1 */ /* USER CODE END FLASH_IF_Erase_1 */ /* Check Flash start address */ if (IS_FLASH_MAIN_MEM_ADDRESS((uint32_t)pStart)) { ret_status = FLASH_IF_INT_Erase(pStart, uLength); } /* USER CODE BEGIN FLASH_IF_Erase_2 */ /* USER CODE END FLASH_IF_Erase_2 */ return ret_status; } /* USER CODE BEGIN EF */ /* USER CODE END EF */ /* Private Functions Definition -----------------------------------------------*/ /* Private Functions : internal flash -----------------------------------------*/ static FLASH_IF_StatusTypedef FLASH_IF_INT_Write(void *pDestination, const void *pSource, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_OK; /* USER CODE BEGIN FLASH_IF_INT_Write_1 */ /* USER CODE END FLASH_IF_INT_Write_1 */ uint32_t uDest = (uint32_t)pDestination; uint32_t uSource = (uint32_t)pSource; uint32_t length = uLength; uint32_t page_index; uint32_t address_offset; uint32_t start_page_index; uint32_t page_address; uint32_t number_pages; uint32_t current_dest; uint32_t current_source; uint32_t current_length; if ((pDestination == NULL) || (pSource == NULL) || !IS_ADDR_ALIGNED_64BITS(uLength) || !IS_ADDR_ALIGNED_64BITS((uint32_t)pDestination)) { return FLASH_IF_PARAM_ERROR; } /* Clear error flags raised during previous operation */ ret_status = FLASH_IF_INT_Clear_Error(); if (ret_status == FLASH_IF_OK) { /* Unlock the Flash to enable the flash control register access */ if (HAL_FLASH_Unlock() == HAL_OK) { start_page_index = PAGE_INDEX(uDest); number_pages = PAGE_INDEX(uDest + uLength - 1U) - start_page_index + 1U; if (number_pages > 1) { length = FLASH_PAGE_SIZE - (uDest % FLASH_PAGE_SIZE); } for (page_index = start_page_index; page_index < (start_page_index + number_pages); page_index++) { page_address = page_index * FLASH_PAGE_SIZE + FLASH_BASE; if (FLASH_IF_INT_IsEmpty(pDestination, length) != FLASH_IF_MEM_EMPTY) { if (pAllocatedBuffer == NULL) { ret_status = FLASH_IF_PARAM_ERROR; break; /* exit for loop */ } /* backup initial Flash page data in RAM area */ FLASH_IF_INT_Read(pAllocatedBuffer, (const void *)page_address, FLASH_PAGE_SIZE); /* copy fragment into RAM area */ UTIL_MEM_cpy_8(&pAllocatedBuffer[uDest % FLASH_PAGE_SIZE], (const void *)uSource, length); /* erase the Flash sector, to avoid writing twice in RAM */ if (FLASH_IF_INT_Erase((void *)page_address, FLASH_PAGE_SIZE) != FLASH_IF_OK) { ret_status = FLASH_IF_ERASE_ERROR; break; /* exit for loop */ } /* copy the whole flash sector including fragment from RAM to Flash */ current_dest = page_address; current_source = (uint32_t)pAllocatedBuffer; current_length = FLASH_PAGE_SIZE; } else { /* write a part of flash page from selected source data */ current_dest = uDest; current_source = uSource; current_length = length; } for (address_offset = 0U; address_offset < current_length; address_offset += 8U) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by word */ if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, current_dest, *((uint64_t *)(current_source + address_offset))) == HAL_OK) { /* Check the written value */ if (*(uint64_t *)current_dest != *(uint64_t *)(current_source + address_offset)) { /* Flash content doesn't match SRAM content */ ret_status = FLASH_IF_WRITE_ERROR; break; } /* Increment FLASH Destination address */ current_dest = current_dest + 8U; } else { /* Error occurred while writing data in Flash memory */ ret_status = FLASH_IF_WRITE_ERROR; break; } } if (ret_status != FLASH_IF_OK) { /* Error occurred while writing data in Flash memory */ break; } /* Increment FLASH destination address, source address, and decrease remaining length */ uDest += length; uSource += length; length = ((uLength - length) > FLASH_PAGE_SIZE) ? FLASH_PAGE_SIZE : uLength - length; } /* Lock the Flash to disable the flash control register access (recommended * to protect the FLASH memory against possible unwanted operation) */ HAL_FLASH_Lock(); } else { ret_status = FLASH_IF_LOCK_ERROR; } } /* USER CODE BEGIN FLASH_IF_INT_Write_2 */ /* USER CODE END FLASH_IF_INT_Write_2 */ return ret_status; } static FLASH_IF_StatusTypedef FLASH_IF_INT_Read(void *pDestination, const void *pSource, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_OK; /* USER CODE BEGIN FLASH_IF_INT_Read_1 */ /* USER CODE END FLASH_IF_INT_Read_1 */ if ((pDestination == NULL) || (pSource == NULL)) { return FLASH_IF_PARAM_ERROR; } UTIL_MEM_cpy_8(pDestination, pSource, uLength); /* USER CODE BEGIN FLASH_IF_INT_Read_2 */ /* USER CODE END FLASH_IF_INT_Read_2 */ return ret_status; } static FLASH_IF_StatusTypedef FLASH_IF_INT_Erase(void *pStart, uint32_t uLength) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_OK; /* USER CODE BEGIN FLASH_IF_INT_Erase_1 */ /* USER CODE END FLASH_IF_INT_Erase_1 */ HAL_StatusTypeDef hal_status = HAL_ERROR; uint32_t page_error = 0U; uint32_t uStart = (uint32_t)pStart; FLASH_EraseInitTypeDef erase_init; if (pStart == NULL) { return FLASH_IF_PARAM_ERROR; } /* Clear error flags raised during previous operation */ ret_status = FLASH_IF_INT_Clear_Error(); if (ret_status == FLASH_IF_OK) { /* Unlock the Flash to enable the flash control register access */ if (HAL_FLASH_Unlock() == HAL_OK) { erase_init.TypeErase = FLASH_TYPEERASE_PAGES; erase_init.Page = PAGE_INDEX(uStart); /* Get the number of pages to erase from 1st page */ erase_init.NbPages = PAGE_INDEX(uStart + uLength - 1U) - erase_init.Page + 1U; /* Erase the Page */ hal_status = HAL_FLASHEx_Erase(&erase_init, &page_error); if (hal_status != HAL_OK) { ret_status = (hal_status == HAL_BUSY) ? FLASH_IF_BUSY : FLASH_IF_ERASE_ERROR; } /* Lock the Flash to disable the flash control register access (recommended * to protect the FLASH memory against possible unwanted operation) */ HAL_FLASH_Lock(); } else { ret_status = FLASH_IF_LOCK_ERROR; } } /* USER CODE BEGIN FLASH_IF_INT_Erase_2 */ /* USER CODE END FLASH_IF_INT_Erase_2 */ return ret_status; } static int32_t FLASH_IF_INT_IsEmpty(void *pStart, uint32_t uLength) { int32_t status = FLASH_IF_MEM_EMPTY; /* USER CODE BEGIN FLASH_IF_INT_IsEmpty_1 */ /* USER CODE END FLASH_IF_INT_IsEmpty_1 */ uint32_t index; for (index = 0; index < uLength; index += 8) { if (*(uint64_t *)pStart != UINT64_MAX) { status = FLASH_IF_MEM_NOT_EMPTY; break; } pStart = (void *)((uint32_t)pStart + 8U); } /* USER CODE BEGIN FLASH_IF_INT_IsEmpty_2 */ /* USER CODE END FLASH_IF_INT_IsEmpty_2 */ return status; } static FLASH_IF_StatusTypedef FLASH_IF_INT_Clear_Error(void) { FLASH_IF_StatusTypedef ret_status = FLASH_IF_LOCK_ERROR; /* USER CODE BEGIN FLASH_IF_INT_Clear_Error_1 */ /* USER CODE END FLASH_IF_INT_Clear_Error_1 */ /* Unlock the Program memory */ if (HAL_FLASH_Unlock() == HAL_OK) { /* Clear all FLASH flags */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); /* Unlock the Program memory */ if (HAL_FLASH_Lock() == HAL_OK) { ret_status = FLASH_IF_OK; } } /* USER CODE BEGIN FLASH_IF_INT_Clear_Error_2 */ /* USER CODE END FLASH_IF_INT_Clear_Error_2 */ return ret_status; } /* USER CODE BEGIN PrFD */ /* USER CODE END PrFD */ /* HAL overload functions ---------------------------------------------------------*/ /** * @note This function overwrites the __weak one from HAL */ void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue) { /* USER CODE BEGIN HAL_FLASH_EndOfOperationCallback_1 */ /* USER CODE END HAL_FLASH_EndOfOperationCallback_1 */ if (ReturnValue == 0xFFFFFFFFUL) { /* Call when all requested pages have been erased */ } /* USER CODE BEGIN HAL_FLASH_EndOfOperationCallback_2 */ /* USER CODE END HAL_FLASH_EndOfOperationCallback_2 */ } /** * @note This function overwrites the __weak one from HAL */ void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue) { /* USER CODE BEGIN HAL_FLASH_OperationErrorCallback_1 */ /* USER CODE END HAL_FLASH_OperationErrorCallback_1 */ } /* USER CODE BEGIN Overload_HAL_weaks */ /* USER CODE END Overload_HAL_weaks */