STM32读写内部Flash

工作中使用STM32F407ZGT6这块芯片开发项目,内部Flash有1M之多,出于数据存储需要,而外部没有拓展EEPROM,就想着将数据存入Flash中。因此研究了一下STM32F4读写内部Flash的一些操作。

以下是关于Flash介绍,部分来自互联网:
【STM32F4 内部Flash的一些信息】

STM32F407ZGTx的内部Flash的地址是:0x08000000,大小是0x00100000。

写Flash的时候,如果发现写入地址的Flash没有被擦出,数据将不会写入。Flash的擦除操作,只能按Sector进行。不能单独擦除一个地址上的数据。因此在写数据之前需要将地址所在Sector的所有数据擦除。

在STM32F4的编程手册上可找到Flash的Sector划分,我们现在只操作Main memory:

STM32读写内部Flash_第1张图片

参考Demo中的例子,将Flash的页的起始地址(基地址)可定义如下:

/* Base address of the Flash sectors */
 #define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Sector 0, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Sector 1, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Sector 2, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Sector 3, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Sector 4, 64 Kbytes */
 #define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Sector 5, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Sector 6, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Sector 7, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Sector 8, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Sector 9, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Sector 10, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Sector 11, 128 Kbytes */

实际使用中,由于代码是存在Flash前几个Sector中的,那么自己定义的数据最好存在Flash后几个Sector中,尽量避免对前几个Sector的读写。

有了这些定义之后,我们就可以开始操作Flash了。注意:对Flash的操作不需要Configuration,不像操作其他STM外设,需要先进行相关参数的配置。

首先,要向Flash写入数据需要先将Flash解锁。根据手册定义,解锁Flash需要先向寄存器FLASH_KEYR写入0x45670123之后再向这个寄存器写入0xCDEF89AB。这两个数据在库中已经定义成了:FLASH_KEY1和FLASH_KEY2.

使用库函数时不用这么麻烦,函数FLASH_Unlock()即可完成对Flash的解锁。解锁flash之后,使用函数FLASH_ClearFlag清除Flash的状态寄存器。然后就可以对Flash进行写操作了。数据写入完成以后,需要重新上锁,使用函数FLASH_Lock()。

以下是操作Flash的实际代码(由于实际需要,读写的为double类型数据):

#ifndef _FLASHRW_H
#define _FLASHRW_H
#include "stm32f4xx.h"

#define STORAGE_MAXI    2
#define STORAGE_MAXJ    25
#define STORAGE_SIZE    4       //数据按32位存储,故SIZE为4
#define FLASH_USER_END_ADDR     ((uint32_t)0x080FFFFF) /* End of Flash*/

/* Base address of the Flash sectors */
 #define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Sector 0, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Sector 1, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Sector 2, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Sector 3, 16 Kbytes */
 #define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Sector 4, 64 Kbytes */
 #define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Sector 5, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Sector 6, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Sector 7, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Sector 8, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Sector 9, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Sector 10, 128 Kbytes */
 #define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Sector 11, 128 Kbytes */
/**
  * @}
  */ 

extern double Max_Storage[STORAGE_MAXI][STORAGE_MAXJ];
typedef enum{FAILED = 0,PASSED = !FAILED} Write_Status;

void PrintArray(double Data[][STORAGE_MAXJ]);
void ReadFlash(uint32_t Address,double Data[][STORAGE_MAXJ]);
Write_Status WriteFlash(uint32_t Address,const double Data[][STORAGE_MAXJ]);

#endif
*******************************************************
*文件名称: FlashRW.c 
*
*功能说明:Flash读写,数组内容显示
******************************************************/

double Max_Storage[STORAGE_MAXI][STORAGE_MAXJ]; 
/******************************************************
函数名称: void ReadFlash(uint32_t Address,double Data[][STORAGE_MAXJ])
功    能:读取Flash中内容到Max_Storage[][]中
输    入:uint32_t Address :存储空间首地址
          double Data[][STORAGE_MAXJ] : 存放读取到数据的数组
输    出:无
******************************************************/
void ReadFlash(uint32_t Address,double Data[][STORAGE_MAXJ])
{
    uint8_t i,j;
    //读FLASH不需要FLASH处于解锁状态,直接取地址内数据
    for(i = 0;i < STORAGE_MAXI;i++)
    {
        for(j = 0;j < STORAGE_MAXJ;j++)
        {
            //读取时/1000,000取得相应位数的小数
            Data[i][j] = (double)(*(vu32 *)Address)/1000000;
            Address += STORAGE_SIZE;
        }
    }
}

/******************************************************
函数名称: void PrintArray(double Data[][STORAGE_MAXJ])
功    能:显示二维数组中的元素
输    入:double Data[][STORAGE_MAXJ] :    二维数组首地址
输    出:无
注    意:仅用来显示FlashRW.h文件中定义的大小的数组[STORAGE_MAXI][STORAGE_MAXJ]
******************************************************/
void PrintArray(double Data[][STORAGE_MAXJ])
{
    uint8_t i,j;
    for(i = 0;i < STORAGE_MAXI;i++)
    {
        for(j = 0;j < STORAGE_MAXJ;j++)
        {
            printf("Data[%d][%d] : %f\n",i,j,Data[i][j]);
        }
//      printf("\n");
    }
}

/******************************************************
函数名称: uint32_t GetSector(uint32_t Address)
功    能:判断地址所在的Sector
输    入:uint32_t Address :存储空间首地址
输    出:uint32_t :Sector编号
******************************************************/
uint32_t GetSector(uint32_t Address)
{
  uint32_t sector = 0;

  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_Sector_0;  
  }
  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_Sector_1;  
  }
  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_Sector_2;  
  }
  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_Sector_3;  
  }
  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_Sector_4;  
  }
  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_Sector_5;  
  }
  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_Sector_6;  
  }
  else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_Sector_7;  
  }
  else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_Sector_8;  
  }
  else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_Sector_9;  
  }
  else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_Sector_10;  
  }
  else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
  {
    sector = FLASH_Sector_11;  
  }

  return sector;
}

/******************************************************
函数名称: uint8_t WriteFlash(uint32_t Address,const double Data[][STORAGE_MAXJ])
功    能:将指定大小的二维数组写入Flash_Sector_11
输    入:uint32_t Address :存储空间首地址
          const double Data[][STORAGE_MAXJ] : 需要写入的源数据
输    出:Write_Status : 写入结果{ FAILED : 写入失败,PASSED : 写入成功 }
******************************************************/
Write_Status WriteFlash(uint32_t Address,const double Data[][STORAGE_MAXJ])
{
    uint8_t i,j,result;

    result = PASSED;

    FLASH_Unlock(); //解锁FLASH后才能向FLASH中写数据

    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                 FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR| FLASH_FLAG_PGSERR); 

    /*擦除FLASH*/
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */ 
    if (FLASH_EraseSector(GetSector(Address),VoltageRange_3) != FLASH_COMPLETE)
    { 
        printf("Erase failed.\n");
//      while (1)
//      {
//      }
    }
    /*擦除完毕*/
    /*开始写入*/
    for(i = 0;i < STORAGE_MAXI;i++)
    {
        for(j = 0;j < STORAGE_MAXJ;j++)
        {
            //将数据写入相应的地址,如果出错则打印写入失败的数据标号,*1000,000保留6位小数
            if(FLASH_ProgramWord(Address,(uint32_t)(Data[i][j]*1000000)) == FLASH_COMPLETE) 
            {
                Address = Address + STORAGE_SIZE;
            }
            else
            {
                result = FAILED;
                /* Error occurred while writing data in Flash memory. 
                 User can add here some code to deal with this error */
                printf("Write Failed @ %d %d .\n",i,j);
//              while(1)
//              {
//              }
            }
        }
    }

    FLASH_Lock();  //写数据完成,加锁FLASH

    return result;
}

你可能感兴趣的:(STM32)