STM32读写内部Flash

发布者:温雅如风最新更新时间:2018-12-25 来源: eefocus关键字: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:


这里写图片描述


参考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读写  内部Flash 引用地址:STM32读写内部Flash

上一篇:STM32f103 —— 内部flash读写
下一篇:关于STM32与SD卡通信的一些思考与总结

推荐阅读最新更新时间:2024-03-16 16:21

STM32之SPI读写外部FLASH
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) SPI_FLASH_Write_SR(0x02);//使能状态寄存器中的写存储器 SST25V_DBSY(); SPI_FLASH_Write_SR(0x02);//使能状态寄存器中的写存储器 SST25V_DBSY(); 实验目的:将数据写入外部FLASH中,然后再读出来显示在LCD上 实验平台:基于STM32F103C8T6的彩屏开发板 FLASH:SST25VF016B 图1:FLASH硬件接口 图2:S ST25VF016地址自增写数据 图3:SST2
[单片机]
<font color='red'>STM32</font>之SPI<font color='red'>读写</font>外部<font color='red'>FLASH</font>
STM32 Flash读写;Flash地址对应的存储内容及方式
概念:计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是1个字节, 1个存储单元存放1个字节,每个存储单元对应一个32位(bit)地址,所以重要的话说三遍:对于32bit的ARM CPU 一个32位地址指向1个字节!!! 一个32位地址指向1个字节!!! 一个32位地址指向1个字节!!! 我们常说的flash空间,多少多少K,指的是多少多少K byte 假如我们执行下面的函数操作: FlashWriteWord_P(0x1082,&WordVar); /* 向0x1082、0x1083中写入0xABCD */ 经过编译,从map文件查看flash内容如下: 注意,前面的1080是
[单片机]
【飞思卡尔 MC9S12】内部Flash读写
上一篇讲到PRM文件与内存映射,其中有个重要寄存器叫做GPAGE,可以全局访问所有地址范围,Flash操作也是基于这个地址。 在讲述Flash读写之前,有一个重要概念要普及,就是Flash操作代码不能存储在被操作的Flash物理块中,例如我要擦除一个Flash中某一个扇区内容,这个擦除动作的代码不能存在这个Flash物理块中(Flash中代码运行时,相当于读操作,此时不能擦写)。 那我们如何擦写Flash呢? 很简单,只有一个解决方案,就是将Flash操作代码存储到RAM中。不过,就我们以往的理解,函数都是存储在Flash中的,如何存储到RAM中呢? 由这个解决方案引申出好几个子解决方案。 一、通过在PRM文件
[单片机]
使用ST-Link Utility去除STM32芯片读写保护
问题:使用ISP/J-Link/ST-Link等无法下载代码,提示芯片写保护;读芯片信息时提示读保护。 原因:一般是修改了选项字节。 解决方法:这里使用ST-Link Utility来修改选项字节。 使用ST-Link连接到STM32芯片,点击Connect。 存在读保护。 修改选项字节。 将读保护等级修改为Level 0。 打钩的扇区会添加写保护,点击Unselect all不选择写保护。 写入选项字节后Flash会被擦除。 能正常写入程序。
[单片机]
使用ST-Link Utility去除<font color='red'>STM32</font>芯片<font color='red'>读写</font>保护
STM32的UART读写及printf打印
0.摘要 本文以STM32F1x系列单片机为例,主要介绍了串口的初始化、串口中断、接收/发送、串口调试等内容,也顺带讲到中断分组、半主机模式以及微库MicroLIB。 1.串口初始化 串口初始化主要包括对IO、USART和中断的初始化。根据STM32F1x手册RM0008的P166,USART在全双工模式下,发送口TX要配置成复用推挽输出,接收口RX要配置成浮空输入或上拉输入。此外,本文不使用USART的硬件流控制,所谓硬件流控制就是通过加入额外的引脚(RTS和CTS)来控制数据的收发过程,在数据传输之前确认收发双方均准备好才进行通信,用于防止接收缓冲区满而导致的数据丢失问题。 /********************
[单片机]
<font color='red'>STM32</font>的UART<font color='red'>读写</font>及printf打印
stm32寄存器之spi2读写sd卡
看完sd卡读写,我也忍不住自己试一试 使用spi1的时候,程序运行成功,但是当我尝试用spi2 的时候,一次一次的fail,现在总结发现本身错在这几个地方,其中也有一些地方是大家的普遍错误: 1,自己尝试硬件的时候,一定要把硬件先连接好,这个是基础保障,不能急 2,spi1 的时钟是接在APB2上,是72MHZ,而spi2的时钟是接在APB1上的,是36MHZ 所以从SPI1转移到SPI2时一定要注意分频的问题 3,在学习板上使用spi接口的时候,一定要禁用掉使用这个接口的其余模块,我自己的学习板上就是,nrf2401与vs1003都用了SPI2接口,我的是要禁用掉vs1003就可以,禁用方法就是把vs10
[单片机]
STM32把SD卡内容搬运到内部FLASH之一
首先阅读这篇博文: STM32操作访问内部flash,包括写入数据到flash和从flash读取数据 :https://blog.csdn.net/Ace_Shiyuan/article/details/78196648 这篇文章写得比较明白,但是它写的函数不饱满,没有把Flash充分写满,意思如下: 请看写数组的函数:FLASHStatus = FLASH_ProgramHalfWord(STARTADDR+WriteAddress+i*2, temp);//写入数据 存在问题:比如写u8 pBuffer ={ 123456789 };写进去是:01 00 02 00.... 这样的 中间浪费了,/因为u8转u16会自动给前
[单片机]
<font color='red'>STM32</font>把SD卡内容搬运到<font color='red'>内部</font><font color='red'>FLASH</font>之一
STM32系统学习——SPI(读写串行 FLASH
一、SPI 协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。 可与 I2C 章节对比阅读,体会两种通讯总线的差异以及 EEPROM 存储器与 FLASH 存储 器的区别。 1、物理层 SPI通讯使用 3 条总线及片选线,3条总线分别为 SCK、MOSI、MISO,片选线为 SS,它们的作用介绍如下: (1) SS( Slave Select):从设备选择信号线,常称为片选信号线,也称为 NSS、CS,以下用 NS
[单片机]
<font color='red'>STM32</font>系统学习——SPI(<font color='red'>读写</font>串行 <font color='red'>FLASH</font>)
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved