STM32F429IGT6 读写内部 Flash 驱动
STM32F429IGT6 读写内部 Flash 驱动

STM32F429IGT6 读写内部 Flash 驱动

针对 F429 内部 Flash 扇区大小不一致的特点做了适配,可以读写任意扇区、地址。

本驱动中使用了内部 SRAM 做为读写缓冲区,占用内存较大,实际项目中推荐使用 SDRAM 做为读写缓冲区,并搭配动态内存管理机制使用。本驱动已经通过了充分验证,可以直接在项目中使用。

头文件

/*********************************************************************************************************
* 模块名称:Flash.h
* 摘    要:Flash模块
* 当前版本:1.0.0
* 作    者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日   
* 内    容:
* 注    意:
**********************************************************************************************************
* 取代版本:
* 作    者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
#ifndef _FLASH_H_
#define _FLASH_H_

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "DataType.h"

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/
//扇区大小为128K
#define FLASH_PAGE_SIZE ((u32)(128 * 1024))

/*********************************************************************************************************
*                                              枚举结构体定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              API函数声明
*********************************************************************************************************/
void InitFlash(void);                                                              //初始化内部Flash模块
void FlashWriteWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len); //向Flash中写入字
void FlashReadWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len);  //从Flash读取字

#endif

源文件

/*********************************************************************************************************
* 模块名称:Flash.c
* 摘    要:Flash模块
* 当前版本:1.0.0
* 作    者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日   
* 内    容:
* 注    意:
**********************************************************************************************************
* 取代版本:
* 作    者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "Flash.h"
#include "stm32f4xx_conf.h"
#include "UART1.h"

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              枚举结构体定义
*********************************************************************************************************/
typedef struct
{
  unsigned int sectorNumber;   //扇区编号
  unsigned int sectorSize;     //扇区大小
  unsigned int sectorBaseAddr; //扇区起始地址
}StructSectorInfo;

/*********************************************************************************************************
*                                              内部变量
*********************************************************************************************************/
//Flash 写入缓冲区
static unsigned int s_arrFlashBuf[FLASH_PAGE_SIZE / 4];

//扇区信息
static const StructSectorInfo s_arrSectorInfo[24] = 
{
  {FLASH_Sector_0 , 16  * 1024, 0x08000000},
  {FLASH_Sector_1 , 16  * 1024, 0x08004000},
  {FLASH_Sector_2 , 16  * 1024, 0x08008000},
  {FLASH_Sector_3 , 16  * 1024, 0x0800C000},
  {FLASH_Sector_4 , 64  * 1024, 0x08010000},
  {FLASH_Sector_5 , 128 * 1024, 0x08020000},
  {FLASH_Sector_6 , 128 * 1024, 0x08040000},
  {FLASH_Sector_7 , 128 * 1024, 0x08060000},
  {FLASH_Sector_8 , 128 * 1024, 0x08080000},
  {FLASH_Sector_9 , 128 * 1024, 0x080A0000},
  {FLASH_Sector_10, 128 * 1024, 0x080C0000},
  {FLASH_Sector_11, 128 * 1024, 0x080E0000},
  {FLASH_Sector_12, 16  * 1024, 0x08100000},
  {FLASH_Sector_13, 16  * 1024, 0x08104000},
  {FLASH_Sector_14, 16  * 1024, 0x08108000},
  {FLASH_Sector_15, 16  * 1024, 0x0810C000},
  {FLASH_Sector_16, 64  * 1024, 0x08110000},
  {FLASH_Sector_17, 128 * 1024, 0x08120000},
  {FLASH_Sector_18, 128 * 1024, 0x08140000},
  {FLASH_Sector_19, 128 * 1024, 0x08160000},
  {FLASH_Sector_20, 128 * 1024, 0x08180000},
  {FLASH_Sector_21, 128 * 1024, 0x081A0000},
  {FLASH_Sector_22, 128 * 1024, 0x081C0000},
  {FLASH_Sector_23, 128 * 1024, 0x081E0000},
};

/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/ 
static unsigned int GetSectorSize(unsigned int sector);     //根据扇区编号获取扇区大小
static unsigned int GetSectorBaseAddr(unsigned int sector); //根据扇区编号获取扇区起始地址
static unsigned int GetSectorNumber(unsigned int addr);     //根据地址获取扇区编号

/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称: GetSectorSize
* 函数功能: 根据扇区编号获取扇区大小
* 输入参数: sector:扇区编号
* 输出参数: void
* 返 回 值: 扇区大小(字节)
* 创建日期: 2023年02月03日
* 注    意:
*********************************************************************************************************/
static unsigned int GetSectorSize(unsigned int sector)
{
  unsigned int i;
  for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
  {
    if(sector == s_arrSectorInfo[i].sectorNumber)
    {
      return s_arrSectorInfo[i].sectorSize;
    }
  }
  return 0;
}

/*********************************************************************************************************
* 函数名称: GetSectorBaseAddr
* 函数功能: 根据扇区编号获取扇区起始地址
* 输入参数: sector:扇区编号
* 输出参数: void
* 返 回 值: 扇区起始地址
* 创建日期: 2023年02月03日
* 注    意:
*********************************************************************************************************/
static unsigned int GetSectorBaseAddr(unsigned int sector)
{
  unsigned int i;
  for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
  {
    if(sector == s_arrSectorInfo[i].sectorNumber)
    {
      return s_arrSectorInfo[i].sectorBaseAddr;
    }
  }
  return s_arrSectorInfo[0].sectorBaseAddr;
}

/*********************************************************************************************************
* 函数名称: GetSectorNumber
* 函数功能: 根据地址获取扇区编号
* 输入参数: addr:地址
* 输出参数: void
* 返 回 值: 扇区编号
* 创建日期: 2023年02月03日
* 注    意:
*********************************************************************************************************/
static unsigned int GetSectorNumber(unsigned int addr)
{
  unsigned int i;
  for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
  {
    if((addr >= s_arrSectorInfo[i].sectorBaseAddr) && (addr < (s_arrSectorInfo[i].sectorBaseAddr + s_arrSectorInfo[i].sectorSize)))
    {
      return s_arrSectorInfo[i].sectorNumber;
    }
  }
  return s_arrSectorInfo[0].sectorNumber;
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitFlash
* 函数功能:初始化Flash模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void InitFlash(void)
{
  
}

/*********************************************************************************************************
* 函数名称:FlashWriteWord
* 函数功能:向Flash中写入字
* 输入参数:startAddr-起始地址,pBuf-待写入数据指针,len-写入数据的数量
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注    意:输入数据一定是uint32_t的指针,即数据一定是按照4字节对齐写入的
*          写入数据时为保证之前写入的数据不被擦除,Flash读写以页为单位
*********************************************************************************************************/
void FlashWriteWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len)
{
  unsigned int i;          //循环变量
  unsigned int pageNumber; //页编号
  unsigned int pageSize;   //页大小,按字节
  unsigned int pageAddr;   //页地址,即起始地址 startAddr 所在的页地址
  unsigned int pageOff;    //页内偏移地址(32位计算),即起始地址 startAddr 所在的页的偏移地址
  unsigned int rwAddr;     //读写地址
  unsigned int dataCnt;    //已写入数据量
  
  //获取页编号和页大小
  pageNumber = GetSectorNumber(startAddr);
  pageSize = GetSectorSize(pageNumber);

  //计算页地址和页内偏移量
  pageAddr = GetSectorBaseAddr(pageNumber);
  pageOff  = (startAddr - pageAddr) / 4;

  //解锁Flash,准备写入
  FLASH_Unlock();

  //已写入数据量清零
  dataCnt = 0;

  //写入Flash时需要先读取整页的内容到缓冲区,然后擦除一整页,将缓冲区修改后再写回Flash
  while(1)
  {
    //读取一整页的数据到缓冲区
    rwAddr = pageAddr;
    for(i = 0; i < pageSize / 4; i++)
    {
      s_arrFlashBuf[i] = *(u32*)rwAddr;
      rwAddr = rwAddr + 4;
    }

    //擦除一整页
    FLASH_EraseSector(pageNumber, VoltageRange_3);;
    
    //修改缓冲区内的内容
    while(pageOff < pageSize / 4)
    {
      //将数据保存到缓冲区
      s_arrFlashBuf[pageOff] = pBuf[dataCnt];

      //已写入数据加一
      dataCnt++;

      //页内偏移量加一
      pageOff++;

      //写入完成
      if(dataCnt >= len)
      {
        break;
      }
    }

    //页内偏移量清零
    pageOff = 0;

    //将修改后的缓冲区内容写回Flash
    rwAddr = pageAddr;
    for(i = 0; i < pageSize / 4; i++)
    {
      FLASH_ProgramWord(rwAddr, s_arrFlashBuf[i]);
      rwAddr = rwAddr + 4;
    }

    //更新到下一页
    pageAddr = pageAddr + pageSize;
    pageNumber = GetSectorNumber(pageAddr);

    //写入完成
    if(dataCnt >= len)
    {
      break;
    }
  }

  //Flash上锁
  FLASH_Lock();
}

/*********************************************************************************************************
* 函数名称:FlashReadWord
* 函数功能:从Flash读取字
* 输入参数:startAddr-起始地址(由于是字(32位)读取,因此,此地址必须为4的倍数);pBuf-数据指针
*           len-字(32位)数,即要读取的32位数据的个数
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注    意:
*********************************************************************************************************/
void FlashReadWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len)
{
  u16 i;
  u32 addr;
  addr = startAddr; 
  for(i = 0; i < len; i++)
  {
    pBuf[i] = *(vu32*)(addr);     //读取字(32位)
    addr += 4;                    //由于是字(32位),故地址增加4
  }
}

一条评论

评论已关闭。