M7/Core/Src/flash_if.c

329 lines
9.0 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_EMPTY = 0,
FLASH_NOT_EMPTY = 1
};
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/**
* @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
* @param pSource: pointer on buffer with data to write
* @param uLength: Length of data buffer in byte. It has to be 64-bit aligned.
* @retval HAL Status.
*/
static int32_t FLASH_IF_Write_Buffer(uint32_t pDestination, uint8_t *pSource, uint32_t uLength);
/**
* @brief This function checks if part of Flash is empty
It handles 32b unaligned address
* @param addr: Start of user flash area
* @param size: number of bytes.
* @retval FLASH_EMPTY or FLASH_NOT_EMPTY.
*/
static int32_t FLASH_IF_IsEmpty(uint8_t *addr, uint32_t size);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Exported functions --------------------------------------------------------*/
int32_t FLASH_IF_Write(uint32_t address, uint8_t *data, uint32_t size, uint8_t *dataTempPage)
{
/* USER CODE BEGIN FLASH_IF_Write_1 */
/* USER CODE END FLASH_IF_Write_1 */
int32_t status = FLASH_OK;
uint32_t page_start_index = PAGE(address);
uint32_t page_end_index = PAGE(address + size - 1);
uint32_t curr_size = size;
uint32_t curr_dest_addr = address;
uint32_t curr_src_addr = (uint32_t)data;
if ((data == NULL) || ((size % sizeof(uint64_t)) != 0) || ((address % sizeof(uint64_t)) != 0))
{
return FLASH_PARAM_ERROR;
}
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0U)
{
return FLASH_LOCK_ERROR;
}
if (page_start_index != page_end_index)
{
curr_size = FLASH_PAGE_SIZE - (address % FLASH_PAGE_SIZE);
}
for (uint32_t idx = page_start_index; idx <= page_end_index; idx++)
{
if (FLASH_IF_IsEmpty((uint8_t *)curr_dest_addr, curr_size) != FLASH_EMPTY)
{
if (dataTempPage == NULL)
{
return FLASH_PARAM_ERROR;
}
/* backup initial Flash page data in RAM area */
UTIL_MEM_cpy_8(dataTempPage, (uint8_t *)(idx * FLASH_PAGE_SIZE + FLASH_BASE), FLASH_PAGE_SIZE);
/* copy fragment into RAM area */
UTIL_MEM_cpy_8(&dataTempPage[((uint32_t)curr_dest_addr) % FLASH_PAGE_SIZE], (uint8_t *)curr_src_addr, curr_size);
/* erase the Flash sector, to avoid writing twice in RAM */
if (FLASH_IF_EraseByPages(idx, 1, 0) != FLASH_OK)
{
status = FLASH_ERASE_ERROR;
break; /* exit for loop */
}
else
{
/* copy the whole flash sector including fragment from RAM to Flash*/
if (FLASH_IF_Write_Buffer(idx * FLASH_PAGE_SIZE + FLASH_BASE, dataTempPage, FLASH_PAGE_SIZE) != FLASH_OK)
{
status = FLASH_WRITE_ERROR;
break; /* exit for loop */
}
}
}
else
{
if (FLASH_IF_Write_Buffer(curr_dest_addr, (uint8_t *)curr_src_addr, curr_size) != FLASH_OK)
{
status = FLASH_WRITE_ERROR;
break; /* exit for loop */
}
}
/* 2nd part of memory overlapped on 2nd flash sector */
curr_dest_addr += curr_size;
curr_src_addr += curr_size;
curr_size = size - curr_size;
}
return status;
/* USER CODE BEGIN FLASH_IF_Write_2 */
/* USER CODE END FLASH_IF_Write_2 */
}
int32_t FLASH_IF_Write64(uint32_t address, uint64_t data)
{
/* USER CODE BEGIN FLASH_IF_Write64_1 */
/* USER CODE END FLASH_IF_Write64_1 */
while (*(uint64_t *)address != data)
{
while (LL_FLASH_IsActiveFlag_OperationSuspended());
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data);
}
return FLASH_OK;
/* USER CODE BEGIN FLASH_IF_Write64_2 */
/* USER CODE END FLASH_IF_Write64_2 */
}
int32_t FLASH_IF_EraseByPages(uint32_t page, uint16_t n, int32_t interrupt)
{
/* USER CODE BEGIN FLASH_IF_EraseByPages_1 */
/* USER CODE END FLASH_IF_EraseByPages_1 */
HAL_StatusTypeDef hal_status;
FLASH_EraseInitTypeDef erase_str;
uint32_t page_error;
erase_str.TypeErase = FLASH_TYPEERASE_PAGES;
erase_str.Page = page;
erase_str.NbPages = n;
/* Erase the Page */
if (interrupt)
{
hal_status = HAL_FLASHEx_Erase_IT(&erase_str);
}
else
{
hal_status = HAL_FLASHEx_Erase(&erase_str, &page_error);
}
return ((hal_status == HAL_OK) ? FLASH_OK : ((hal_status == HAL_BUSY) ? FLASH_BUSY : FLASH_ERASE_ERROR));
/* USER CODE BEGIN FLASH_IF_EraseByPages_2 */
/* USER CODE END FLASH_IF_EraseByPages_2 */
}
void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue)
{
/* USER CODE BEGIN HAL_FLASH_EndOfOperationCallback_1 */
/* USER CODE END HAL_FLASH_EndOfOperationCallback_1 */
/* Call CleanUp callback when all requested pages have been erased */
if (ReturnValue == 0xFFFFFFFFUL)
{
HWCB_FLASH_EndOfCleanup();
}
/* USER CODE BEGIN HAL_FLASH_EndOfOperationCallback_2 */
/* USER CODE END HAL_FLASH_EndOfOperationCallback_2 */
}
void HAL_FLASH_OperationErrorCallback(uint32_t ReturnValue)
{
/* USER CODE BEGIN HAL_FLASH_OperationErrorCallback_1 */
/* USER CODE END HAL_FLASH_OperationErrorCallback_1 */
}
void HWCB_FLASH_EndOfCleanup(void)
{
/* USER CODE BEGIN HWCB_FLASH_EndOfCleanup_1 */
/* USER CODE END HWCB_FLASH_EndOfCleanup_1 */
}
/* USER CODE BEGIN EF */
/* USER CODE END EF */
/* Private Functions Definition -----------------------------------------------*/
static int32_t FLASH_IF_Write_Buffer(uint32_t pDestination, uint8_t *pSource, uint32_t uLength)
{
/* USER CODE BEGIN FLASH_IF_Write_Buffer_1 */
/* USER CODE END FLASH_IF_Write_Buffer_1 */
uint8_t *pSrc = pSource;
uint64_t src_value;
int32_t status = FLASH_OK;
for (uint32_t i = 0; i < (uLength / sizeof(uint64_t)); i++)
{
UTIL_MEM_cpy_8(&src_value, pSrc, sizeof(uint64_t));
/* Avoid writing 0xFFFFFFFFFFFFFFFFLL on erased Flash */
if (src_value != UINT64_MAX)
{
status = FLASH_IF_Write64(pDestination, src_value);
}
pDestination += sizeof(uint64_t);
pSrc += sizeof(uint64_t);
if (status != FLASH_OK)
{
/* exit the for loop*/
break;
}
}
return status;
/* USER CODE BEGIN FLASH_IF_Write_Buffer_2 */
/* USER CODE END FLASH_IF_Write_Buffer_2 */
}
static int32_t FLASH_IF_IsEmpty(uint8_t *addr, uint32_t size)
{
/* USER CODE BEGIN FLASH_IF_IsEmpty_1 */
/* USER CODE END FLASH_IF_IsEmpty_1 */
uint64_t *addr64;
uint32_t i;
/* start memory NOT 64bits aligned */
while ((((uint32_t)addr) % sizeof(uint64_t)) != 0)
{
if (*addr++ != UINT8_MAX)
{
return FLASH_NOT_EMPTY;
}
size--;
}
/* addr64 is 64 bits aligned */
addr64 = (uint64_t *)addr;
for (i = 0; i < (size / sizeof(uint64_t)); i++)
{
if (*addr64++ != UINT64_MAX)
{
return FLASH_NOT_EMPTY;
}
}
size -= sizeof(uint64_t) * i;
/* end memory NOT 64 bits aligned */
addr = (uint8_t *)addr64;
while (size != 0)
{
if (*addr++ != UINT8_MAX)
{
return FLASH_NOT_EMPTY;
}
size--;
}
return FLASH_EMPTY;
/* USER CODE BEGIN FLASH_IF_IsEmpty_2 */
/* USER CODE END FLASH_IF_IsEmpty_2 */
}
/* USER CODE BEGIN PrFD */
/* USER CODE END PrFD */