STM32 Flash读写擦除功能代码实现

1.说明:

        本文提供关于 STM32 的 Flash 读取、写入、擦除 功能代码,可以用于内部、外部 Flash 的读写操作,用于与存储数据、OTA 升级 等 ,关于Flash的基础操作。

函数测试环境:STM32G474 ,其他 STM32 差别不大,根据需求具体调试修改即可。

2.上代码

2.1: flash_if.h

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef FLASH_IF_H
#define FLASH_IF_H

/* Includes ------------------------------------------------------------------*/
#include "stm32g4xx.h"

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
#define FLASH_IF_MIN_WRITE_LEN (8U)  /* Flash programming by 64 bits */
/* Exported functions ------------------------------------------------------- */

HAL_StatusTypeDef FLASH_If_Init(void);
HAL_StatusTypeDef FLASH_If_Write(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_If_Read(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_If_Erase_Size(void *pStart, uint32_t uLength);
HAL_StatusTypeDef FLASH_INT_Init(void);
HAL_StatusTypeDef FLASH_INT_If_Write(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_INT_If_Read(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_INT_If_Erase_Size(void *pStart, uint32_t uLength);
HAL_StatusTypeDef FLASH_EXT_Init(void);
HAL_StatusTypeDef FLASH_EXT_If_Write(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_EXT_If_Read(void *pDestination, const void *pSource, uint32_t uLength);
HAL_StatusTypeDef FLASH_EXT_If_Erase_Size(void *pStart, uint32_t uLength);


#endif  /* FLASH_IF_H */

2.2: flash_if.c

/* Includes ------------------------------------------------------------------*/
#include "flash_if.h"
#include "string.h"
#include <stdio.h>

/* Uncomment the line below if you want some debug logs */
#define FLASH_IF_DBG
#ifdef FLASH_IF_DBG
#define FLASH_IF_TRACE printf
#else
#define FLASH_IF_TRACE(...)
#endif /* FLASH_IF_DBG */


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define NB_PAGE_SECTOR_PER_ERASE  2U    /*!< Nb page erased per erase */
#define EXTERNAL_FLASH_ADDRESS    0x90000000U


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/


/* Private function prototypes -----------------------------------------------*/
static uint32_t GetPage(uint32_t uAddr);
static HAL_StatusTypeDef FLASH_INT_If_Clear_Error(void);

/* Public functions : wrapper ---------------------------------------------------------*/

/**
  * @brief  Initialize internal and external flash interface (OSPI/QSPI) 初始化内外flash接口(OSPI/QSPI)
  * @param  none
  * @retval HAL status.
  */
HAL_StatusTypeDef FLASH_If_Init(void)
{
  HAL_StatusTypeDef e_ret_status = HAL_OK;

  e_ret_status = FLASH_INT_Init();
  if (e_ret_status == HAL_OK)
  {
    e_ret_status = FLASH_EXT_Init();
  }
  return e_ret_status;
}
/**
  * @brief  Depending on start address, this function will call internal or external (OSPI/QSPI) flash driver
  *         .擦除 flash 指定地址,可以是内部或外部,根据地址程序自动选择
  * @param  pStart: flash address to be erased
  * @param  uLength: number of bytes
  * @retval HAL status.
  */
HAL_StatusTypeDef FLASH_If_Erase_Size(void *pStart, uint32_t uLength)
{
  /* Check Flash start address */
  if ((uint32_t) pStart < EXTERNAL_FLASH_ADDRESS)
  {
    return FLASH_INT_If_Erase_Size(pStart, uLength);
  }
  else
  {
    return FLASH_EXT_If_Erase_Size(pStart, uLength);
  }
}

/**
  * @brief  Depending on destination address, this function will call internal or external (OSPI/QSPI) flash driver
  *         .向flash中写入指定长度的数据
  * @param  pDestination: flash address to write
  * @param  pSource: pointer on buffer with data to write
  * @param  uLength: number of bytes
  * @retval HAL Status.
  */
HAL_StatusTypeDef FLASH_If_Write(void *pDestination, const void *pSource, uint32_t uLength)
{
  /* Check Flash destination address */
  if ((uint32_t) pDestination < EXTERNAL_FLASH_ADDRESS)
  {
    return FLASH_INT_If_Write(pDestination, pSource, uLength);
  }
  else
  {
    return FLASH_EXT_If_Write(pDestination, pSource, uLength);
  }
}

/**
  * @brief  Depending on destination address, this function will call internal or external (OSPI/QSPI) flash driver
  * @brief  Depending on source address, this function will call internal or external (OSPI/QSPI) flash driver
  *         .读取 flash 中指定地址的数据,根据地址自动选择内部、外部flash
  * @param  pDestination: pointer on buffer to store data
  * @param  pSource: flash address to read
  * @param  uLength: number of bytes
  * @retval HAL Status.
  */
HAL_StatusTypeDef FLASH_If_Read(void *pDestination, const void *pSource, uint32_t uLength)
{
  /* Check Flash source address */
  if ((uint32_t) pSource < EXTERNAL_FLASH_ADDRESS)
  {
    return FLASH_INT_If_Read(pDestination, pSource, uLength);
  }
  else
  {
    return FLASH_EXT_If_Read(pDestination, pSource, uLength);
  }
}

/* Public functions : internal flash --------------------------------------------------------- */
/**
  * @brief  This function initialize the internal flash interface if required
  * @param  none
  * @retval HAL status.
  */
HAL_StatusTypeDef FLASH_INT_Init(void)
{
  return HAL_OK;
}

/**
  * @brief  This function does an erase of n (depends on Length) pages in user flash area
  *         .此函数会擦除 mcu 内部 flash 区域中的 n(取决于长度)页面
  * @param  pStart: Start of user flash area
  * @param  uLength: number of bytes.
  * @retval HAL status.
  */
HAL_StatusTypeDef FLASH_INT_If_Erase_Size(void *pStart, uint32_t uLength)
{
  uint32_t page_error = 0U;
  uint32_t uStart = (uint32_t)pStart;
  FLASH_EraseInitTypeDef x_erase_init;
  HAL_StatusTypeDef e_ret_status = HAL_ERROR;
  uint32_t first_page = 0U;
  uint32_t nb_pages = 0U;
  uint32_t chunk_nb_pages;

  /* Clear error flags raised during previous operation */
  e_ret_status = FLASH_INT_If_Clear_Error();

  if (e_ret_status == HAL_OK)
  {
    /* Unlock the Flash to enable the flash control register access *************/
    if (HAL_FLASH_Unlock() == HAL_OK)
    {
      first_page = GetPage(uStart);
      /* Get the number of pages to erase from 1st page */
      nb_pages = GetPage(uStart + uLength - 1U) - first_page + 1U;
      x_erase_init.TypeErase   = FLASH_TYPEERASE_PAGES;
      x_erase_init.Banks       = FLASH_BANK_1;
      /* Erase flash per NB_PAGE_SECTOR_PER_ERASE to avoid watch-dog */
      do
      {
        chunk_nb_pages = (nb_pages >= NB_PAGE_SECTOR_PER_ERASE) ? NB_PAGE_SECTOR_PER_ERASE : nb_pages;
        x_erase_init.Page = first_page;
        x_erase_init.NbPages = chunk_nb_pages;
        first_page += chunk_nb_pages;
        nb_pages -= chunk_nb_pages;
        if (HAL_FLASHEx_Erase(&x_erase_init, &page_error) != HAL_OK)
        {
          HAL_FLASH_GetError();
          e_ret_status = HAL_ERROR;
        }
        /* Refresh Watchdog */
        WRITE_REG(IWDG->KR, IWDG_KEY_RELOAD);
      } while (nb_pages > 0);
      /* Lock the Flash to disable the flash control register access (recommended
      to protect the FLASH memory against possible unwanted operation) *********/
      HAL_FLASH_Lock();

    }
    else
    {
      e_ret_status = HAL_ERROR;
    }
  }

  return e_ret_status;
}

/**
  * @brief  This function writes a data buffer in flash (data are 32-bit aligned).
  *         .此函数在闪存中写入缓冲区的数据(数据为 32 位对齐)
  * @note   After writing data buffer, the flash content is checked.
  *         .缓冲区数据写入后,检查flash内容。
  * @param  pDestination: Start address for target location. It has to be 8 bytes aligned.
  *         .目标位置的起始地址。它必须是 8 个字节对齐的。
  * @param  pSource: pointer on buffer with data to write
  *         .缓冲区上的指针,其中包含要写入的数据
  * @param  uLength: Length of data buffer in bytes. It has to be 8 bytes aligned.
  *         .数据缓冲区的长度(以字节为单位)。它必须是 8 个字节对齐的。
  * @retval HAL Status.
  */
HAL_StatusTypeDef FLASH_INT_If_Write(void *pDestination, const void *pSource, uint32_t uLength)
{
  HAL_StatusTypeDef e_ret_status = HAL_ERROR;
  uint32_t pdata = (uint32_t)pSource;

  /* Clear error flags raised during previous operation */
  e_ret_status = FLASH_INT_If_Clear_Error();

  if (e_ret_status == HAL_OK)
  {
    /* Unlock the Flash to enable the flash control register access *************/
    if (HAL_FLASH_Unlock() != HAL_OK)
    {
      return HAL_ERROR;

    }
    else
    {
      /* DataLength must be a multiple of 64 bit */
      for (uint32_t i = 0U; i < uLength; i += 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, (uint32_t)pDestination,  *((uint64_t *)(pdata + i)))
            == HAL_OK)
        {
          /* Check the written value */
          if (*(uint64_t *)pDestination != *(uint64_t *)(pdata + i))
          {
            /* Flash content doesn't match SRAM content */
            e_ret_status = HAL_ERROR;
            break;
          }
          /* Increment FLASH Destination address */
          pDestination = (void *)((uint32_t)pDestination + 8U);
        }
        else
        {
          /* Error occurred while writing data in Flash memory */
          e_ret_status = HAL_ERROR;
          break;
        }
      }
      /* Lock the Flash to disable the flash control register access (recommended
      to protect the FLASH memory against possible unwanted operation) *********/
      HAL_FLASH_Lock();
    }
  }
  return e_ret_status;
}

/**
  * @brief  This function reads flash
  *         .读取内部 flash 中的数据
  * @param  pDestination: Start address for target location
  * @param  pSource: flash address to read
  * @param  uLength: number of bytes
  * @retval HAL Status.
  */
HAL_StatusTypeDef FLASH_INT_If_Read(void *pDestination, const void *pSource, uint32_t uLength)
{
  memcpy(pDestination, pSource, uLength);
  return HAL_OK;
}

/* Public functions : external flash ---------------------------------------------------------*/

HAL_StatusTypeDef FLASH_EXT_Init(void)
{
  return HAL_OK;
}

/* No external flash available on this product
   ==> return SFU_ERROR */

HAL_StatusTypeDef FLASH_EXT_If_Erase_Size(void *pStart, uint32_t uLength)
{
  return HAL_ERROR;
}

HAL_StatusTypeDef FLASH_EXT_If_Write(void  *pDestination, const void *pSource, uint32_t uLength)
{
  return HAL_ERROR;
}

HAL_StatusTypeDef FLASH_EXT_If_Read(void *pDestination, const void *pSource, uint32_t uLength)
{
  return HAL_ERROR;
}

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Clear error flags raised during previous operation
  *         .清除上一次操作期间引发的错误标志
  * @param  None
  * @retval HAL Status.
  */
HAL_StatusTypeDef FLASH_INT_If_Clear_Error(void)
{
  HAL_StatusTypeDef ret = HAL_ERROR;

  /* 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 = HAL_OK;
    }
#ifdef FLASH_IF_DBG
    else
    {
      FLASH_IF_TRACE("[FLASH_IF] Lock failure\r\n");
    }
#endif /* FLASH_IF_DBG */
  }
#ifdef FLASH_IF_DBG
  else
  {
    FLASH_IF_TRACE("[FLASH_IF] Unlock failure\r\n");
  }
#endif /* FLASH_IF_DBG */
  return ret;
}

/**
  * @brief  Gets the page of a given address
  *         .获取给定地址的页面
  * @param  Addr: Address of the FLASH Memory
  * @retval The page of a given address
  */
uint32_t GetPage(uint32_t Addr)
{
  uint32_t page = 0U;

  page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE_128_BITS;

  return page;
}

作者:软饭硬吃666

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 Flash读写擦除功能代码实现

发表评论