STM32F4 FLASH

STM32F4 FLASH

  • 简介
  • 基本知识
  • 代码块

简介

在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数。这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能。将这类数据存在指定的位置,需要修改时直接修改存储位置的数值,需要使用时则直接读取,会是一种方便的做法。考虑到这些数据量比较少,使用专门的存储单元既不经济,也没有必要,而STM32F4内部的Flash容量较大,而且ST的库函数中还提供了基本的Flash操作函数,实现起来也比较方便。
本代码用于上电时读取flash数据给滤波器权重参数(float型),再有其他信号时可以修改flash数据(未做)。

基本知识

STM32F40xx/41xx 的闪存模块组织如图 所示
STM32F40xx/41xx 的闪存模块组织如图

主存储器,该部分用来存放代码和数据常数(如 const 类型的数据),主存储器的起始地址就是 0X08000000, B0、 B1 都接 GND 的时候,就是从 0X08000000 开始运行代码的。

代码块

ST的库函数包含了对flash的基本操作,为了使用方面,根据我们自己的需要对其进行再次封装。
对于读操作相对比较简单,内置闪存模块可以在通用地址空间直接寻址,就像读取变量一样。
对于写操作相对来说要复杂得多,写操作包括对用户数据的写入和擦除。为了防止误操作还有写保护锁。但这些基本的操作ST的库函数已经为我们写好了,我们只需要调用即可。

#define FLASH_SAVE_ADDR  0X08020000 
//设置FLASH 保存地址(必须为偶数,且所在扇区,要大于本代码所占用到的扇区.
//否则,写操作的时候,可能会导致擦除整个扇区,从而引起部分程序丢失.引起死机.

#define STM32_FLASH_BASE 0x08000000  //STM32 FLASH的起始地址

#define SIZE   4
float vel_filter_weight_read[SIZE] = {0.0};
float vel_filter_weight_write[SIZE] = {0.0};
float x_filter_0 = 0.0, x_filter_1 = 0.0;
float yaw_filter_0 = 0.0, yaw_filter_1 = 0.0;

//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000) //扇区0起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000) //扇区1起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000) //扇区2起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000) //扇区3起始地址, 16 Kbytes  
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000) //扇区4起始地址, 64 Kbytes  
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000) //扇区5起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000) //扇区6起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000) //扇区7起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_8     ((u32)0x08080000) //扇区8起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000) //扇区9起始地址, 128 Kbytes  
#define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000) //扇区10起始地址,128 Kbytes  
#define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000) //扇区11起始地址,128 Kbytes

/**获取某个地址所在的flash扇区
  *addr:flash地址
  *返回值:0~11,即addr所在的扇区
  */
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
  if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
  else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
  else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
  else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
  else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
  else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
  else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
  else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
  else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
  else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
  else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10;

  return FLASH_Sector_11;
}
/**读取指定地址的字(32位数据)
  *faddr:读地址
  *返回值:对应数据
  */
u32 STMFLASH_ReadWord(u32 faddr)
{
  return *(vu32*)faddr;
}
/**从指定地址开始读出指定长度的数据
  *ReadAddr:起始地址
  *pBuffer:数据指针
  *NumToRead:字(4位)数
  */
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)
{
  u32 i;
  for(i=0;i<NumToRead;i++)
  {
    pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
    ReadAddr+=4;//偏移4个字节.
  }
}
/**WriteAddr:起始地址(此地址必须为4的倍数!!)
  *pBuffer:数据指针
  *NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
  */
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{
  FLASH_Status status = FLASH_COMPLETE;
  u32 addrx=0;
  u32 endaddr=0;

  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;//非法地址

  FLASH_Unlock();                                   //解锁
  FLASH_DataCacheCmd(DISABLE);                      //FLASH擦除期间,必须禁止数据缓存

  addrx=WriteAddr;                                  //写入的起始地址
  endaddr=WriteAddr+NumToWrite*4;                   //写入的结束地址

  if(addrx<0X1FFF0000)                              //只有主存储区,才需要执行擦除操作!!
  {
    while(addrx<endaddr)                            //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
    {
      if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)      //有非0XFFFFFFFF的地方,要擦除这个扇区
      {
        status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!

        if(status!=FLASH_COMPLETE)break;            //发生错误了
      }
      else addrx+=4;
    }
  }
  if(status==FLASH_COMPLETE)
  {
    while(WriteAddr<endaddr)//写数据
    {
      if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
      {
        break;//写入异常
      }

      WriteAddr+=4;
      pBuffer++;
    }
  }

  FLASH_DataCacheCmd(ENABLE);//FLASH擦除结束,开启数据缓存
  FLASH_Lock();//上锁
}
void Flash_Read(void)
{
  u32 *Ptr = (u32*)vel_filter_weight_read;
  u32 Read[4];

  STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)vel_filter_weight_read,SIZE);

  Read[0] = *Ptr;
  Read[1] = *(Ptr+1);
  Read[2] = *(Ptr+2);
  Read[3] = *(Ptr+3);

  if((Read[0] != 0xFFFFFFFF)&&(Read[0] != 0)&&(Read[1] != 0xFFFFFFFF)&&(Read[1] != 0))            //flash 中存入了正确数据则读取数据,否则使用默认数据
  {
    x_filter_0 = vel_filter_weight_read[0];
    x_filter_1 = vel_filter_weight_read[1];
  }else
  {
    x_filter_0 = 0.99;
    x_filter_1 = 0.01;
  }
  if((Read[2] != 0xFFFFFFFF)&&(Read[2] != 0)&&(Read[3] != 0xFFFFFFFF)&&(Read[3] != 0))
  {
    yaw_filter_0 = vel_filter_weight_read[2];
    yaw_filter_1 = vel_filter_weight_read[3];
  } else
  {
    yaw_filter_0 = 0.95;
    yaw_filter_1 = 0.05;
  }
}
int main(void)
{
  System_Init();//其他初始化函数
  Flash_Read();

   while(1)
   {
      //if(Flag == 1)
      //STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)vel_filter_weight_write,SIZE);//根据实际情况添加
    }
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值