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;
}

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32L4系列微控制器的Flash写入对齐是指在进行数据写入操作时,需按照特定的对齐规则进行操作。这是由于Flash写入操作必须按照特定的字节顺序进行,否则可能会导致数据写入错误。 STM32L4系列微控制器的Flash写入对齐要求以字为单位进行,即每次写入的数据长度必须是4字节(32位)的整数倍。如果写入的数据长度不满足该要求,就需要进行数据对齐处理,通常是通过在数据前面添加填充字节来使其长度满足要求。 例如,如果要写入长度为5字节的数据到Flash中,就需要进行对齐处理。在此情况下,可以添加3个填充字节,使总长度变为8字节,然后再进行写入操作。这样就满足了Flash写入对齐的要求。 对Flash进行写入对齐操作的目的是确保数据写入的可靠性和正确性。如果不按照要求进行对齐,可能会导致数据写入错位或错误,进而影响系统的稳定性和功能。 总之,STM32L4系列微控制器的Flash写入对齐要求数据长度必须是4字节的整数倍,如果不满足要求,则需要进行数据对齐处理。这样可以保证数据的正确写入,提高系统的可靠性。 ### 回答2: 在进行STM32 L4系列芯片的Flash写入操作时,对齐是非常重要的一个因素。对齐是指在数据写入Flash存储器时,需要按照特定的规则将数据的存储地址与Flash内存的块边界对齐。对齐的目的是提高数据访问效率和保证写入数据的正确性。 在STM32 L4系列芯片中,Flash内存是以块的形式进行管理的,每个块的大小为一个固定的字节数。当进行Flash写入操作时,需要保证待写入数据的存储地址是块大小的倍数,即对齐于块边界。 对齐的好处主要有两点。首先,对齐可以提高数据访问的速度,因为Flash存储器是按块进行操作的,如果数据不对齐,可能会导致读取写入操作跨越多个块,增加了访问时间。而对齐可以保证数据操作的范围在一个块内,减少了对其他块的访问,提高了效率。 其次,对齐可以确保写入数据的正确性。Flash存储器在进行写入操作时,只能对整个块进行擦除写入,而不能对部分数据进行操作。如果数据不对齐,可能会导致需要修改的数据与其他数据混杂在同一个块中,从而导致擦除整个块,进而丢失其他数据。而对齐可以保证每个块只包含待写入的数据,避免了数据的损失。 总之,STM32 L4系列芯片的Flash写入对齐非常重要。正确的对齐可以提高数据访问效率和确保数据的正确性。在进行Flash写入操作时,需要根据Flash内存块的大小,保证待写入数据的存储地址是块大小的倍数,以充分利用Flash存储器的性能和功能。 ### 回答3: 在进行STM32 L4系列微控制器的Flash写入时,对齐是一个很重要的概念。 对齐意味着将数据按照特定的边界地址进行整理和存储。在STM32 L4系列中,Flash写入的最小单位是字(Word),每个字大小为4字节(32位)。因此,对齐的概念是基于字节的,要求每次写入的数据长度是4的倍数。 对齐是必要的,因为Flash写入操作必须按照特定的规则进行。如果数据的长度不是4的倍数,并且没有对齐到起始地址,则会导致无效的写入操作,从而导致数据错误或者系统不稳定。 在进行Flash写入操作时,需要确保待写入数据的长度是4的倍数,并且起始地址是对齐的。一个简单的方法是使用字节对齐的数据类型或者使用填充字节(padding bytes)将数据补齐到4的倍数,并确保起始地址是对齐的。 另外,ST提供了一些库函数来帮助进行Flash写入操作的对齐。例如,通过调用HAL_FLASH_Program函数,可以以字节为单位进行连续写入,该函数会自动进行对齐。 总之,对齐是STM32 L4系列Flash写入的一个重要概念,确保数据长度是4的倍数,并且起始地址是对齐的是必要的,以避免写入操作错误和系统不稳定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值