历史上的今天
返回首页

历史上的今天

今天是:2025年08月10日(星期日)

正在发生

2019年08月10日 | 【STM32】STM32之flash

2019-08-10 来源:eefocus

一、简介


本文介绍STM32系列如何将flash的一部分当做eeprom来存储数据。


注:本驱动特点是可自定义数据存储空间、限制写入地址避免误写至代码段、支持跨页读写、允许保存非半字倍数的字节。


二、实验平台


库版本:STM32F10x_StdPeriph_Lib_V3.5.0


编译软件:MDK4.53


硬件平台:STM32开发板(主芯片stm32f103c8t6)


仿真器:JLINK


三、版权声明


博主:甜甜的大香瓜


声明:喝水不忘挖井人,转载请注明出处。


原文地址:http://blog.csdn.NET/feilusia


联系方式:897503845@qq.com


香瓜BLE之CC2541群:127442605


香瓜BLE之CC2640群:557278427


香瓜BLE之Android群:541462902


香瓜单片机之STM8/STM32群:164311667

甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i


四、实验前提

1、在进行本文步骤前,请先阅读以下博文:

1)《STM32F10xxx 闪存编程》(下载地址):http://blog.csdn.net/feilusia/article/details/49031709


2、在进行本文步骤前,请先实现以下博文:

暂无


五、基础知识


1、flash的介绍

答:

香瓜使用的stm32f103c8t6的flash为64K,详情如下图:

1)主存储器(BOOT1=x、BOOT0=0)

①地址:从0x08000000开始。

②页大小:小、中容量的flash为1K每页,大容量的flash为2K每页。

2)信息块

①系统存储器(BOOT1=0、BOOT0=1):存放ST自带的启动代码。

②选项字节:一般用于配置写保护、读保护等功能。

3)闪存存储器/接口寄存器

flash所用到的寄存器。


2、闪存等待时间是什么?

答:

由于flash的频率最高位24MHz,所以当STM32的频率小于24MHz时不需要等待时间、大于24MHz时需要等待时间。

例如当STM32的频率为72MHz时,需要在工程中设置等待时间:“FLASH_SetLatency(FLASH_Latency_2); ”


3、闪存的读、写、擦除是如何的?

答:

1)读:可以读有效地址内的任意字节。

2)写:需要先解闪存锁,然后按半字(2个字节)的倍数写入。

3)擦除:需要先解闪存锁,然后可以页擦除、全片擦除。


4、如何解闪存锁?

答:

1)首先要知道flash有三个键值:

①RDPRT键 = 0x000000A5

②KEY1 = 0x45670123

③KEY2 = 0xCDEF89AB

2)将KEY1与KEY2依次写入到FLASH_KEYR寄存器即可实现解闪存锁。


5、写flash只能按半字的倍数来写,但如果只有3个字节要保存,那该如何操作?

答:

香瓜的驱动是把flash中的整页数据读出来,修改要写的3个字节,然后再按页写回去。

虽然此法浪费了些写多余字节的时间,但能只改动flash中所需的3个字节,而不是按半字的倍数(4个)来写。


6、如何避免写到代码段导致代码运行异常?

答:

以stm32f103c8t6为例,它的flash大小是64K,范围是0x8000000~0x8010000。

假设通过MDK编译后得知代码段大小为31K(0x7C00),所以在32K(0x8007D00)之后的位置肯定都不是代码段,都可用于自定义的数据存储空间。

保险起见可参考香瓜下文使用的方式,使用flash的末尾4K。


六、实验步骤


1、编写并添加驱动


1)编写驱动GUA_Flash.c(存放在“……HARDWARE”)


//******************************************************************************         

//name:             GUA_Flash.c           

//introduce:        flash驱动    

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18  

//******************************************************************************  

#include "stm32f10x.h"

#include "GUA_Flash.h"

#include

 

/********************内部变量************************/ 

static GUA_U8 sbGUA_Flash_Data[GUA_FLASH_SECTOR_SIZE] = {0};

 

/*********************内部函数声明************************/

static GUA_U16 GUA_Flash_ReadHalfWord(GUA_U32 nGUA_Flash_CustomOffsetAddr);

static GUA_U8 GUA_Flash_ReadByte(GUA_U32 nGUA_Flash_CustomOffsetAddr);

static GUA_U32 GUA_Flash_ReadWord(GUA_U32 nGUA_Flash_CustomOffsetAddr);

 

//******************************************************************************            

//name:             GUA_Flash_ReadHalfWord           

//introduce:        读取指定地址的字       

//parameter:        nGUA_Flash_CustomOffsetAddr:偏移地址 

//return:           该地址的字         

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18                     

//******************************************************************************

static GUA_U32 GUA_Flash_ReadWord(GUA_U32 nGUA_Flash_CustomOffsetAddr)

{

GUA_U32 nGUA_Flash_Addr = GUA_FLASH_CUSTOM_ADDR_START + nGUA_Flash_CustomOffsetAddr;

return *(GUA_U32*)nGUA_Flash_Addr;

}

 

//******************************************************************************            

//name:             GUA_Flash_ReadHalfWord           

//introduce:        读取指定地址的半字       

//parameter:        nGUA_Flash_CustomOffsetAddr:偏移地址 

//return:           该地址的半字         

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18                     

//******************************************************************************

static GUA_U16 GUA_Flash_ReadHalfWord(GUA_U32 nGUA_Flash_CustomOffsetAddr)

{

GUA_U32 nGUA_Flash_Addr = GUA_FLASH_CUSTOM_ADDR_START + nGUA_Flash_CustomOffsetAddr;

return *(GUA_U16*)nGUA_Flash_Addr;

}

 

//******************************************************************************            

//name:             GUA_Flash_ReadHalfWord           

//introduce:        读取指定地址的字节    

//parameter:        nGUA_Flash_CustomOffsetAddr:偏移地址 

//return:           该地址的字节         

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18                     

//******************************************************************************

static GUA_U8 GUA_Flash_ReadByte(GUA_U32 nGUA_Flash_CustomOffsetAddr)

{

GUA_U32 nGUA_Flash_Addr = GUA_FLASH_CUSTOM_ADDR_START + nGUA_Flash_CustomOffsetAddr;

return *(GUA_U8*)nGUA_Flash_Addr;

}

 

//******************************************************************************            

//name:             GUA_Flash_Read           

//introduce:        读取指定地址、指定数据长度的数据     

//parameter:        nGUA_Flash_CustomOffsetAddr:偏移地址 

//                  pGUA_Data:数据缓存区               

//                  nGUA_Data_Num:读取的字节数

//return:           none         

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18                     

//******************************************************************************

void GUA_Flash_Read(GUA_U32 nGUA_Flash_CustomOffsetAddr, GUA_U8 *pGUA_Data, GUA_U32 nGUA_Data_Num)

{

while(nGUA_Data_Num--)

{

*pGUA_Data++ = GUA_Flash_ReadByte(nGUA_Flash_CustomOffsetAddr++);

}

}

 

//******************************************************************************            

//name:             GUA_Flash_Write           

//introduce:        写入指定地址、指定数据长度的数据        

//parameter:        nGUA_Flash_Addr:读地址 

//                  pGUA_Data:数据缓存区(必须偶数个字节)               

//                  nGUA_Data_Num:数据长度(必须偶数个字节)

//return:           执行情况,详情见eGUA_FLASH_STATUS         

//author:           甜甜的大香瓜                 

//email:            897503845@qq.com     

//QQ group:         香瓜单片机之STM8/STM32(164311667)                  

//changetime:       2017.03.18                     

//******************************************************************************

eGUA_FLASH_STATUS GUA_Flash_Write(GUA_U32 nGUA_Flash_CustomOffsetAddr, GUA_U8 *pGUA_Data, GUA_U32 nGUA_Data_Num)

{

GUA_U32 nGUA_Flash_Addr = GUA_FLASH_CUSTOM_ADDR_START + nGUA_Flash_CustomOffsetAddr; //要写入的地址

eGUA_FLASH_STATUS eGUA_Flash_Status = GUA_FLASH_STATUS_OK; //flash操作情况

GUA_U16 i;

GUA_U32 nGUA_Flash_SectorPos = (nGUA_Flash_Addr - GUA_FLASH_ADDR_START)/GUA_FLASH_SECTOR_SIZE; //算出是第几个扇区(从0开始)

GUA_U16 nGUA_Flash_SectorAddr_Offset = (nGUA_Flash_Addr - GUA_FLASH_ADDR_START)%GUA_FLASH_SECTOR_SIZE; //扇区内偏移地址

GUA_U16 nGUA_Flash_SectorAddr_Remain = GUA_FLASH_SECTOR_SIZE - nGUA_Flash_SectorAddr_Offset; //扇区内剩余字节

GUA_U16 nGUA_HalfWord = 0;

GUA_U16 nGUA_HalfWord_Num;

FLASH_Status eGUA_Flash_Lib_Status = FLASH_COMPLETE; 

推荐阅读

史海拾趣

Broyce Control公司的发展小趣事

进入21世纪,Broyce Control已经成为电气和电子产品设计、制造和供应领域的佼佼者。公司不仅在技术上持续创新,还注重与行业伙伴的合作与交流。通过参与国际标准的制定和推广,Broyce Control逐渐在行业内树立了领导地位。同时,公司还积极承担社会责任,推动可持续发展和环保理念的实践,为行业的健康发展做出了积极贡献。

D+H Mechatronic AG公司的发展小趣事

随着市场竞争的加剧,D+H Mechatronic AG开始调整其市场布局策略。公司根据市场需求和产品特点,有针对性地开拓新的市场领域。同时,公司还加强了与客户的沟通和合作,深入了解客户需求并提供定制化的解决方案。这些举措使公司在激烈的市场竞争中保持了稳定的增长态势,并逐步巩固了其在电子行业中的地位。

EEMB Co Ltd公司的发展小趣事

EEMB集团成立于1995年,初期以外销为主,总部位于武汉东西湖金银湖畔。公司创始人们凭借对电子行业的敏锐洞察力和对锂电池技术的深入研究,决定专注于锂电池的研发与生产。他们组建了一支技术实力强大的研发团队,并开始着手设计和生产高性能的锂电池产品。在初期的几年里,公司逐渐在市场上建立起了一定的声誉,并开始与一些知名的工业企业和设备制造商建立合作关系。

安谱隆(Ampleon)公司的发展小趣事

2022年,无锡锡产微芯半导体有限公司完成了对安谱隆的收购。这一交易金额超过百亿元,是当年中国最大的半导体并购交易事件之一。锡产微芯的收购不仅为安谱隆提供了更广阔的发展平台,也为其在半导体行业中的进一步发展注入了新的活力。在锡产微芯的支持下,安谱隆开启了新的发展阶段,继续在全球射频市场中发挥着重要作用。

这五个故事展示了安谱隆从恩智浦剥离出来到被锡产微芯收购的发展历程。在这个过程中,安谱隆不仅展现了其强大的技术实力和市场潜力,也经历了资本市场的波折与挑战。然而,正是这些经历使得安谱隆更加成熟和稳健,为其未来的发展奠定了坚实的基础。

Free2Move公司的发展小趣事

在恩智浦剥离射频业务后,安谱隆迅速吸引了资本市场的关注。建广资产成功竞标,以18亿美元(约116.82亿元人民币)的价格收购了安谱隆。这一交易不仅显示了建广资产对安谱隆技术实力和市场潜力的认可,也为安谱隆未来的发展注入了新的动力。在建广资产的支持下,安谱隆开始了其独立发展的新篇章。

骅讯(Cmedia)公司的发展小趣事

随着技术的不断发展,骅讯公司进一步扩大了其业务范围,成功开发了PC主板AC97。这一成果是英特尔高清晰度音频应用的重要发展,标志着骅讯在音频技术领域的进一步突破。通过AC97的开发,骅讯进一步巩固了其在音频芯片设计领域的领先地位。

问答坊 | AI 解惑

用什么方法在一个比较喧闹的环境中只能捕捉到自己说话的语音

在一个很嘈杂的环境中比如闹市中,用什么传感器只能捕捉到半径很小的一个范围内的声音(也就是自己说话的声音或者是距离自己很近的人所说话的声音),查了很多相关资料能不能从说话人的声波波段出发?或者是从近声场和远声场出发?    请 ...…

查看全部问答>

有酬项目:S3C2440 WINCE 5.0上SDIO接口marvel 8686 WIFI模块驱动移植,已有WIFI驱动,需要做SDIO的驱动,有BSP,但是

这个WIFI模块为GM9601,厂家提供的驱动是marvel 8686驱动。 据厂家说,只要修改SDIO驱动即可,工作量1天。 由于本人能力有限,对WINCE系统不熟,现将此项目外包。 要求: 1. 一定是在S3C2440、WINCE 5.0上移植过SDIO WIFI模块的人,由于进度紧 ...…

查看全部问答>

请问哪个函数可以得到内核镜像 的基址?

请问哪个函数可以得到内核镜像 的基址? 我在DDK文档中找不到这样的函数. 还有,有什么函数能取到内核镜像的大小呢??/ 本人菜鸟,初学驱动编译,问题都比较弱智. 望大大们,不要见怪,请赐教,谢谢!!!…

查看全部问答>

适合学习的arm开发板有哪些?

适合学习的arm开发板有哪些? 新手哦!…

查看全部问答>

keil中关于片外RAM的疑问

MOV A,#30H MOV R1,#0E0H MOVX @R1,A MOVX A,@R1复制代码 意思是一个对片外RAM操作的,用keil下自带的模拟下,调用内存,输入I:0e0h,现实的是00,为什么啊?不是应该是30h的嘛?? 最终的a的值是30h,但是片外里面显示的是00,怎么回事啊??…

查看全部问答>

新手求助,谢谢

刚开始学嵌入式,用的是PB4.2,有一块SMDK2440的开发板,按照厂家给的wince安装手册一 步步操作下来,但在最后出现一个致命错误: srcgen D:\\WINCE420\\PLATFORM\\SMDK2440 QT2440LHQ D:\\WINCE420\\PUBLIC\\QT2440~1\\WIN CE420\\smdk2440\\ces ...…

查看全部问答>

uip的使用问题

代码如下:void connect_server(void){    u16_t ipaddr[2];    uip_ipaddr(ipaddr,192,168,1,101);    uip_connect(ipaddr,HTONS(10001));        char *echo=\"conn ...…

查看全部问答>

关于LM3S811核心板的一些想法

我们最近拿到的LM3S811板子只是个核心板,像普通的RS232或RS485、SPI(即ssi)、IIC等外设都没有 更别说其他的一些高级的外设了   谁有这方面的板子或者图纸   坛子有没有兴趣组织个这样的活动 将这个板子画出来   如果相应的 ...…

查看全部问答>

【讨论】如何扩展launchpad的IO口

刚刚看到论坛上的 wuqingyou 坛友突然发现launchpad的IO数量不够用,正为这个事烦恼的帖子,也看到了坛子上的“老人” ——wangfucong,juring 的热心回复。launchpad作为G系列这个低成本的430的开发板,确实没有提供非常多的IO口;其 ...…

查看全部问答>

基于FPGA的采集系统与ISA通讯出现问题

这个系统用来实现数据采集的功能,AD采用的是tlc5510,控制器采用EP2C8Q208,与上位总线通讯机通过ISA通讯,但是仿真可以实现采集的功能,但是实际采集的数据却是全零…

查看全部问答>