STM32F407 Flash操作笔记

简述

STM32F4XX的闪存擦除方式分为两种:扇区擦除(最小单元16K)和整片擦除。在实际应用中,为满足重要信息的存储,需将信息存入FLASH中,针对以上两种擦除方式,扇区擦除更符合实际的需要。
参考手册:
闪存模块组织

写FLASH操作

扇区擦除流程
经过以上五个步,就可以擦除某个扇区。但是实际运用过程中,一个扇区只存储一个信息或标志,会造成资源严重浪费。现采用缓存的方式,先读取当下扇区的数据,将读取的数据和要写入的数据组合,待擦除后再次写入。

代码片

  • 写FLASH操作
/*
 *  WriteAddr: 起始地址 (u32)address 是 4 的整数倍, (u32)data
 *  pBuffer:   数据指针
 *  NumToWrite:字(u32)数
 */
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)        //对非0XFFFF FFFF 的地方,先擦除
        {
            if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//对非0XFFFF FFFF 的地方,先擦除
            {   
                status=FLASH_EraseSector(GetSector(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();//上锁
    Printf("Flash status :%d\r\n",status);
}
 

 

  • 数据流存储
#define SectorLen 128 //数据长度 128 * 4 = 512 结合实际需要长度调整
/*
 *  (u32)address 是 4 的整数倍, (u32)data
 *  FreeStart( 0x08008000 )~FreeEnd( 0x08010000 )
 */
void SaveDataToFlash( u32 address, u32 data )
{
    FLASH_Status status = FLASH_COMPLETE;

    u32 site[SectorLen] = {FreeStart}, FlashBuffer[SectorLen] = {0};

    for ( u8 i = 0; i < SectorLen; i ++ )//读取扇区数据,随即擦除
    {
//      if ( STMFLASH_ReadWord( site[i] ) != 0XFFFFFFFF)//0XFFFFFFFF代表无数据
        {
            FlashBuffer[i] = STMFLASH_ReadWord( site[i] );
            site[ i + 1 ] = site[i] + 4;
            if ( address == site[i] )
                FlashBuffer[i] = data;
        }
    }
    FLASH_Unlock();//解锁
    FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
    status = FLASH_EraseSector( GetSector( address ), VoltageRange_3 );//VCC=2.7~3.6V之间!!
    if ( status == FLASH_COMPLETE )
    {       
        for (u8 i = 0; i < SectorLen; i ++)
        {
            if ( FLASH_ProgramWord( site[i], FlashBuffer[i] ) != FLASH_COMPLETE )//写入数据
            { 
                break;  //写入异常
            }
        } 
    }
    FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束,开启数据缓存
    FLASH_Lock();//上锁
    Printf("Save status = %d\r\n",status);

//  return addr;
}
 

 

读FLASH操作

STM23F4 的 FLASH 读取是很简单的。例如,我们要从地址 addr,读取一个字(字节为 8位, 半字为 16 位,字为 32 位),可以通过如下的语句读取:data=(vu32)addr;
将 addr 强制转换为 vu32 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。

代码片

/*
 *faddr :读地址
 *return:对应数据
 */
u32 STMFLASH_ReadWord(u32 faddr)
{
    return *(vu32*)faddr; 
}
//读FLASH操作
/*
 *  ReadAddr  :起始地址 (u32)address 是 4 的整数倍, (u32)data
 *  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个字节
    }
}
 
  • 调试注意事项
  • 在FLASH读写操作时,未使用数据类型(u32),致读到的数据一直为:-1(0xFFFF FFFF 默认值,即该地址写数据失败) ;
  • 主存储区<0x0800 0000 ~ 0x080F FFFF>,存储数据地址小于0x0800 0000,存储出错,主控无响应。在写操作时,一定要保证其 Address 有效!
posted @ 2020-11-25 09:11  dreamrj  阅读(2964)  评论(0编辑  收藏  举报