历史上的今天
返回首页

历史上的今天

今天是:2024年09月22日(星期日)

正在发生

2018年09月22日 | STM32操作访问内部Flash

2018-09-22 来源:eefocus

目录:


1、STM32 FLASH操作流程


2、Flash基本知识点


3、OK,上干货,上代码


-------------------------------------------------------------------------------------------------

STM32中存储区分为:随机存取存储器RAM和只读存储器ROM。 

其中:


RAM为常说的内存,比如手机的2G内存4G内存等,就是程序跑起来的时候所占用的存储空间,特点是掉电数据丢失。

ROM为常说的硬盘,比如手机的64G和128G等,可以简单的理解为硬盘的存储空间,特点是掉电数据不丢失,所以又叫“非易失性存储器件”。 

ROM又包含:EEPROM和Flash。

画个嵌入式产品存储器件的思维导图如下(如有什么地方不对,恳请大神们进行指正): 

STM32操作访问内部Flash

STM32操作访问内部Flash


作为ROM的一份子,flash的特点自然是掉电数据不丢失。但是,flash在STM32中比较重要,程序也是保存在这个地方,所以轻易不让用户进行随意的读写,以避免不必要的问题。


而这篇博客就先简单记录一下flash的访问流程和方法(读和写),具体原理以后理解深刻了再做补充。


blog.csdn.net/Ace_Shiyuan/article/details/78196648


1、STM32 FLASH操作流程


Flash操作已经属于嵌入式设备中很底层的操作了,直接对地址进行存取,简单描述,Flash操作大致需要以下流程:


1、确定要写入Flash的首地址(稍后介绍确定地址的方法)

2、解锁Flash

3、对Flash进行操作(写入数据)

4、对Flash重新上锁

1.1 如何查找并选定要写入Flash十六进制地址值的方法


要想选定安全的Flash地址进行读写,可以根据自己的STM32 MCU型号,查找数据手册,确定FLASH的地址区段,因为起始段会存储代码,所以一定要避开起始段,以避免数据错误。(我一般是根据Flash大小计算Flash的最末尾地址,往前推一段地址空间,在这里一般不会对代码中的数据产生覆盖等影响)


此次操作Flash使用的MCU是STM32103C8T6,所以以该型号MCU为例进行描述:


在数据手册中,可以看到STM32103C8T6的flash起始地址是0x0800 0000(如下图所示),而STM32103C8T6的Flash大小为64K,可以计算出STM32103C8T6的Flash地址范围是:0x0800 0000——0x0800 FFFF(计算方法:STM32内存大小与地址的对应关系以及计算方法)。这里选取0x0800 F000作为读写操作的起始地址,对于C8T6这款MCU,操作这个起始地址应该算是很安全的范围了。 

STM32操作访问内部Flash

STM32操作访问内部Flash-------------------------------------------------------------------------------------------------

2、Flash基本知识点


2.1 Flash容量


Flash根据容量大小可以分为以下三种:


1、小容量产品:Flash大小为1-32KB    (STM32F10X_LD)

2、中容量产品:Flash大小为64-128KB (STM32F10X_MD)

3、大容量产品:Flash大小为256KB以上(STM32F10X_HD)

2.2 ST库对Flash操作的支持


ST库中对Flash操作主要提供了以下几类操作API函数:


1、Flash解锁、锁定函数 

void FLASH_Unlock(void); //解锁函数:在对Flash操作之前必须解锁

void FLASH_Lock(void); //锁定函数:同理,操作完Flash之后必须重新上锁

2、Flash写操作函数 

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data); //32位字写入函数

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); //16位半字写入函数

FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data); //用户选择字节写入函数 

注:这里需要说明,32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2。写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。

3、Flash擦除函数 

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

FLASH_Status FLASH_EraseAllPages(void);

FLASH_Status FLASH_EraseOptionBytes(void);

4、获取Flash状态 

FLASH_Status FLASH_GetStatus(void); 

获取Flash状态函数,主要是为了获取Flash的状态,以便于根据状态对Flash进行操作。该函数返回值是通过枚举类型定义的,在代码中可以看到FLASH_Status类型定义如下(具体含义看注释即可):

typedef enum 


FLASH_BUSY = 1,        //忙

FLASH_ERROR_PG,      //编程错误

FLASH_ERROR_WRP,   //写保护错误

FLASH_COMPLETE,      //操作完成

FLASH_TIMEOUT         //操作超时

}FLASH_Status;

5、等待操作完成函数 

FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout); 

注:在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。

3、OK,上干货,上代码


根据ST库提供的上述函数,我们可以自己编写Flash的读写操作代码如下:


3.1 先定义一个Flash操作的起始地址宏定义和Flash状态指示标志位


#define STARTADDR 0x0800F000 //STM32F103C8T6适用


volatile FLASH_Status FLASHStatus = FLASH_BUSY; //Flash操作状态变量

3.2 编写各个读写函数


//////////////////////////////////////////////////////////////////////////////////

// Name:        WriteFlashOneWord

//

// Function:    向内部Flash写入32位数据

//

// Input:         WriteAddress:数据要写入的目标地址(偏移地址)

//                  WriteData:   写入的数据

//////////////////////////////////////////////////////////////////////////////////

void WriteFlashOneWord(uint32_t WriteAddress, uint32_t WriteData)

{   

    FLASH_UnlockBank1(); //解锁flash

    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

    

    FLASHStatus = 1; //清空状态指示标志位

    FLASHStatus = FLASH_ErasePage(STARTADDR);  

    if(FLASHStatus == FLASH_COMPLETE)   

    {  

        FLASHStatus = 1; //清空状态指示标志位

        FLASHStatus = FLASH_ProgramWord(STARTADDR+WriteAddress, WriteData); //flash.c 中API函数

    }

    

    FLASHStatus = 1; //清空状态指示标志位

    FLASH_LockBank1(); //锁定flash

}


//////////////////////////////////////////////////////////////////////////////////

// Name:        WriteFlashData

//

// Function:    向内部Flash写入数据

//

// Input:        WriteAddress:数据要写入的目标地址(偏移地址)

//                 data[]:      写入的数据首地址

//                 num:        写入数据的个数

//////////////////////////////////////////////////////////////////////////////////

void WriteFlashData(uint32_t WriteAddress, uint8_t data[], uint32_t num)

{

    uint32_t i = 0;

    uint16_t temp = 0;


    FLASH_UnlockBank1(); //解锁flash

    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); 

    

    FLASHStatus = 1; //清空状态指示标志位

    FLASHStatus = FLASH_ErasePage(STARTADDR); //擦除整页

    if(FLASHStatus == FLASH_COMPLETE) //flash操作完成

    {

        FLASHStatus = 1; //清空状态指示标志位

        for(i=0; i2, temp); //写入数据

    }


    FLASHStatus = 1; //清空状态指示标志位

    FLASH_LockBank1(); //锁定flash

//////////////////////////////////////////////////////////////////////////////////

// Name:        ReadFlashNBtye

//

// Function:    从内部Flash读取N字节数据

//

// Input:         ReadAddress:数据地址(偏移地址)

//                  ReadBuf:读取到的数据存放位置指针

//                  ReadNum:读取字节个数

//

// Output:      读取的字节数

//////////////////////////////////////////////////////////////////////////////////

int ReadFlashNBtye(uint32_t ReadAddress, uint8_t *ReadBuf, int32_t ReadNum)

{   

    int DataNum = 0;


    ReadAddress = (uint32_t)STARTADDR + ReadAddress;  

    while(DataNum < ReadNum)

    {        

        *(ReadBuf + DataNum) = *(__IO uint8_t*) ReadAddress++;  

        DataNum++;     

    }

    return DataNum;

}


//////////////////////////////////////////////////////////////////////////////////

// Name:        ReadFlashData

//

// Function:    从内部Flash读取num字节数据

//

// Input:         ReadAddress:数据地址(偏移地址)

//                  dest_Data:      读取到的数据存放位置指针

//                  num:              读取字节个数

//////////////////////////////////////////////////////////////////////////////////

void ReadFlashData(uint32_t ReadAddress, uint8_t *dest_Data, uint32_t num)

{

    int i = 0;

    ReadAddress = (uint32_t)STARTADDR + ReadAddress; 

    while(i < num) 

    {

        *(dest_Data+i) = *(__IO uint16_t*) ReadAddress;

        ReadAddress += 2;

        i++;

    }

}


推荐阅读

史海拾趣

锋鸣电子(Fengming)公司的发展小趣事

随着新能源和储能市场的快速发展,福斯特公司也积极拓展相关业务领域。公司不仅关注光伏材料的研发和生产,还将目光投向了动力电池及储能领域。例如,公司推出的铝塑复合膜产品已完成一期2000万平米扩产项目,并计划未来进一步拓展至动力电池及储能领域。这一举措不仅丰富了公司的产品线,还为公司带来了新的增长点和发展机遇。同时,福斯特还加强与新能源产业链上下游企业的合作,共同推动新能源和储能产业的发展。

East Texas Integrated Circuits公司的发展小趣事

随着ETIC的产品在市场上逐渐获得认可,公司面临着市场拓展的挑战。为了扩大市场份额,ETIC决定进入国际市场。他们首先选择了亚洲市场作为突破口,通过深入了解当地市场需求和竞争环境,制定了一系列有针对性的营销策略。经过几年的努力,ETIC成功地在亚洲市场建立了稳定的客户基础,并逐渐将业务拓展到了欧洲和北美市场。

FERYSTER公司的发展小趣事

FERYSTER公司的创始人在一次国际电子展览会上,被一款新型半导体芯片技术深深吸引。他意识到这项技术将引领电子行业的新一轮革命。于是,他果断决定投入大量资金和资源,组建研发团队,对该技术进行深入研究。经过数年的努力,FERYSTER公司成功掌握了这项技术,并推出了基于该技术的全新产品系列。这些产品以其卓越的性能和稳定性,迅速在市场上取得了成功,为公司的快速发展奠定了坚实基础。

南京绿芯(Grenergy)公司的发展小趣事

FERYSTER公司的创始人在一次国际电子展览会上,被一款新型半导体芯片技术深深吸引。他意识到这项技术将引领电子行业的新一轮革命。于是,他果断决定投入大量资金和资源,组建研发团队,对该技术进行深入研究。经过数年的努力,FERYSTER公司成功掌握了这项技术,并推出了基于该技术的全新产品系列。这些产品以其卓越的性能和稳定性,迅速在市场上取得了成功,为公司的快速发展奠定了坚实基础。

台湾凌通(Generalplus)公司的发展小趣事
可能是光线阈值设置不当,导致指示灯在光线变化时无法正确响应。可尝试调整光敏元件的灵敏度或重新设置光线阈值。
Crosspoint Solutions公司的发展小趣事

随着技术的不断更新换代,人才成为电子企业竞争的核心要素。Crosspoint Solutions公司高度重视人才培养和引进工作,通过校园招聘、社会招聘等多种渠道吸引优秀人才加入。同时,公司还建立了完善的培训体系,不断提升员工的技能水平和创新能力。这些优秀的人才为公司的发展提供了强有力的支撑。

问答坊 | AI 解惑

Protel99出现“Access violation at address 40067324 in module 'Vcl50.bpl'.

使用Protel99打开PCB图的时候出现“Access violation at address 40067324 in module \'Vcl50.bpl\'. Write of address 0000014C” 请问怎么解决啊…

查看全部问答>

示波器开发总结

这段时间一直比较忙,没有时间来整理资料,幸亏有汤汤的提醒,做一些简单的总结和资料的发布。 示波器的性能指标: 最高60M采样; 具有上升边沿或下降边沿的电平触发功能; 采用2.8寸TFT显示,人机界面友好; 采用STM32控制器作为主控芯片,波 ...…

查看全部问答>

终结嵌入式时代的方案(原创)

这样设想,有一个家庭,他们有很多家用电器,包括电视机,空调,微波炉,冰箱等等,他们都需要有一个控制程序。现在一般是用嵌入式在家电里面进行编程是吧?这样有很多问题,一个是开发成本,因为要给每个家电做个小程序,用来控制它,一个是这个嵌 ...…

查看全部问答>

LPC2478能跑WinCE吗?

得到一块LPC2478的开发板,里面的资源太少了,只有些Demo程序,如果自己在上面移植个操作系统,ARM7TDMI-S,没MMU也能跑Linux、winCE吗? 请了解的人给点建议。…

查看全部问答>

串口通信的问题,高手来帮帮忙!

我们单位要给新买的AN2512C支流低电阻测量仪编一个软件用串口读取测量数据,vc++。这台仪器支持串口通信(说明书里也提供了通信协议)。可是我编出来之后“不灵”(也就是说那台仪器“没有反应”),求教高手!谢谢。 我用串口精灵也调过,按照协 ...…

查看全部问答>

何时可以买到STM32L的样品?

多处寻找STM32L样品未果,请版主提供一下线索,还有多久。 如果等待太长只好再选其他M3…

查看全部问答>

AD DA 芯片求推荐

主要是希望牛牛们推荐符合要求的主流片子。 AD/DA分辨率都为12bit以上, 多路(AD一共需要8路,DA一共需要16路,当然不一定一片搞定)。 速度是AD总转换时间小于5us,DA建立时间小于5us。  …

查看全部问答>

怎样让两个信号源发出的信号同步

我做的一个模电书中反向加法电路,想让两个信号源中发出的信号同步,比如全是100HZ,峰峰值是100mv,这两者之间没有相位差。这是我的两个信号源发生器,下图…

查看全部问答>

Xilinx ISE软件安装包

有木有给个Xilinx ise的安装包加破解包呢。。。小女子电脑是win764位机,几次下载安装都不正确。。而且Xilinx官网注册了但是老显示错误。。急求,谢谢。。。…

查看全部问答>