O7/Core/Src/flash_if.c

485 lines
14 KiB
C

/* 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 */