STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多。平时写的代码,烧写完之后还有大量的剩余。有效利用这剩余的FLASH能存储不少数据。因此研究了一下STM32F4读写内部FLASH的一些操作。

【STM32F4 内部Flash的一些信息】

STM32F407VG的内部FLASH的地址是:0x08000000,大小是0x00100000。

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

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

参考Demo中的例子,将FLASH的页的其实地址(基地址)可定义如下:

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

在库里边,FLASH的Sector编号定义如下,这是供库里边的几个函数使用的。需要将地址转换成Sector编号:

#define FLASH_Sector_0     ((uint16_t)0x0000) /*!< Sector Number 0 */
#define FLASH_Sector_1     ((uint16_t)0x0008) /*!< Sector Number 1 */
#define FLASH_Sector_2     ((uint16_t)0x0010) /*!< Sector Number 2 */
#define FLASH_Sector_3     ((uint16_t)0x0018) /*!< Sector Number 3 */
#define FLASH_Sector_4     ((uint16_t)0x0020) /*!< Sector Number 4 */
#define FLASH_Sector_5     ((uint16_t)0x0028) /*!< Sector Number 5 */
#define FLASH_Sector_6     ((uint16_t)0x0030) /*!< Sector Number 6 */
#define FLASH_Sector_7     ((uint16_t)0x0038) /*!< Sector Number 7 */
#define FLASH_Sector_8     ((uint16_t)0x0040) /*!< Sector Number 8 */
#define FLASH_Sector_9     ((uint16_t)0x0048) /*!< Sector Number 9 */
#define FLASH_Sector_10    ((uint16_t)0x0050) /*!< Sector Number 10 */
#define FLASH_Sector_11    ((uint16_t)0x0058) /*!< Sector Number 11 */

Demo中有将地址转换成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;
}

有了这些定义之后,我们就可以开始正式操作FLASH了

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

使用库函数不用这么麻烦,函数FLASH_Unlock()即可完成对FLASH的解锁。

解锁FLASH之后,使用函数FLASH_ClearFlag清除FLASH的状态寄存器。然后就可以对FLASH进行写操作了。我按照示例工程,擦除两块FLASH。

下边是操作FLASH的代码,首先擦除两块FLASH,然后向这两块FLASH中写入数据。最后进行校验:

要写入的数据定义:

#define DATA_32                 ((uint32_t)0x12345678)

开始FLASH操作:

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

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

/* Get the number of the start and end sectors */
  StartSector = GetSector(FLASH_USER_START_ADDR);  //获取FLASH的Sector编号
  EndSector = GetSector(FLASH_USER_END_ADDR);
 
  //擦除FLASH
  for (i = StartSector; i < EndSector; i += 8)  //每次FLASH编号增加8,可参考上边FLASH Sector的定义。
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    if (FLASH_EraseSector(i, VoltageRange_3) != FLASH_COMPLETE)
    {
      while (1)
      {
      }
    }
  }
 
  /*擦除完毕*/
  /*开始写入*/
  Address = FLASH_USER_START_ADDR;
 
    while (Address < FLASH_USER_END_ADDR)
  {
    if (FLASH_ProgramWord(Address, DATA_32) == FLASH_COMPLETE)   //将DATA_32写入相应的地址。
    {
      Address = Address + 4;
    }
    else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
      }
    }
  }
 
  FLASH_Lock();  //读FLASH不需要FLASH处于解锁状态。
 
//读出数据 检查写入值是否正确
  Address = FLASH_USER_START_ADDR;
  MemoryProgramStatus = 0x0;
   while (Address < FLASH_USER_END_ADDR)
  {
    data32 = *(__IO uint32_t*)Address;   //读FLASH中的数据,直接给出地址就行了。跟从内存中读数据一样。

if (data32 != DATA_32)
    {
      MemoryProgramStatus++; 
    }

Address = Address + 4;
  }

下边是使用STLink Utility读出的数据,检查一下,确实写进去数据了:

参考文档是ST的 STM32F40xxx and STM32F41xxx Flash programming manual。可在ST网站下载。文档编号:PM0081。FLASH的有不少寄存器,各个含义手册上有详细介绍。我只是简单地看了下。使用库函数操作,好像不大需要详细理解这些寄存器了。

PS:这个实验主要代码来自ST的Demo。这里我只是加入了个人的注释。不当之处,望高人指点。

STM32F4读写内部FLASH【使用库函数】的更多相关文章

  1. 第50章 读写内部FLASH—零死角玩转STM32-F429系列

    第50章     读写内部FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  2. STM32学习笔记:读写内部Flash(介绍+附代码)

    一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...

  3. STM32 对内部FLASH读写接口函数(转)

    源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...

  4. STM32f030f4p6 内部flash 打包读写

    最近做到的项目在运行需要把一组uint8_t(unsigned char)的数据进行掉电储存,想到单片机STM32f030f4p6内部flash可以直接由程序操作,写了以下代码用于uint8_t数据打 ...

  5. [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写

     一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...

  6. STM32 对内部FLASH读写接口函数

    因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. 原理:先要把整页FLASH的内容搬到RAM中 ...

  7. STM32 内部flash的读写程序

    ​ /* Base address of the Flash sectors */ #define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base ...

  8. STM32F103使用内部Flash保存参数

    在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数.这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能.将这类数据存在指定的 ...

  9. STM32内部flash存储小数——别样的C语言技巧

    今天在进行STM32内部falsh存储的时候,发现固件库历程的函数原型是这样的: 第一个是地址,在我的STM32中是2K一页的,第二个是要写入的数据. 问题就来了,存储一个小数该怎么办呢?固件库给的是 ...

随机推荐

  1. BackTrack5-r3安装VMware Tools

    bt login:root //默认的BT系统账号password:toor //默认的BT系统密码,这里的密码是不显示的.root@bt:~#startx //进入图形模式 启动BT虚拟机系统-在V ...

  2. AI第二次作业

    2.9  设有如下语句,请用相应的谓词公式分别把它们表示出来: (1)有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花.      解:设 P(x): x是人      L(x,y): x喜 ...

  3. HP T505恢复出厂系统

    1.制作usb启动U盘. ------ 从HP网站上下载,或者找供应商提供 2.按F11,从U盘启动进去,会自动执行安装,等待完成即可以.

  4. ae学习

    Ae           提供者CoSA 1993年1月 版本1.0 代号Egg 主要加入法人功能layered compositing with mask, effect, transforms, ...

  5. Ansible-Tower快速入门-7.配置实时事件【翻译】

    配置实时事件 在tower的菜单中,在接近用户菜单处有一个带有颜色的小点,这个带颜色的小点显示tower的实时事件功能的状态 如果这个小点是绿色的,表示运行正常,如果这个小点是红色或橙色,表示实时事件 ...

  6. win32记事本程序(二)

    遇到一个较大的难题,做记事本要不要使用edit或者是richedit控件呢.如果用控件的话感觉没什么挑战,不用控件,现有的参考资料仅有<windows程序设计>第六章的TYPER程序,这个 ...

  7. Windows下VTK6.0.0安装详解(CMake使用说明)

    操作系统:Windows7,用到工具:Visual studio.CMake. 1.准备工作 VTK下载: 下载最新VTK稳定版(6.0.0,截至2013年7月)http://www.vtk.org/ ...

  8. 提升Nginx+PHP-FPM性能技巧

    /etc/php-fpm.d 2.1进程数   php-fpm初始/空闲/最大worker进程数      pm.max_children = 300      pm.start_servers = ...

  9. ipython notebook 显示图

    import random import matplotlib from pylab import * %pylab inline list = [random.random() for i in r ...

  10. js 获取当前焦点所在的元素、给元素和input控件添加键盘监听事件、添加页面级的键盘监听事件

    页面级的键盘监听事件 document.onkeydown = function (event) { var e = event || window.event || arguments.callee ...