历史上的今天
返回首页

历史上的今天

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

正在发生

2018年10月08日 | STM32F103RCT6之FLASH读写操作

2018-10-08 来源:eefocus

一、STM32F103的FLASH简介

1、如图所示,STM32F103内部FLASH存储区分为三个区域:主存储区、信信息块和闪存存储器接口寄存器。

储存储区是我们读写FLASH的主要的存储区,MCU程序以及一些需要掉电保存的数据都是存储在这个区域的。

信息快:程序启动代码被存储在这部分。

最后的寄存器则是FLASH读写需要配置的一些寄存器位置。

STM32F103RCT6之FLASH读写操作
主存储器的起始位置0x08000000,除去程序占用的空间,剩余部分就可以作为数据保存的区域了,所以在利用内部FLASH存储数据的时候,一定不要占用程序本身所占用的空间,否则会导致死机。

主存储器一共256页,每页2K字节长度。

二、FLASH存储寄存器的配置

1、FPEC键寄存器:

在读写FLASH之前必须进行解锁FPEC,通过该寄存器,向该寄存器写入键值。当要操作FLASH时,需要将相应键值KEY1和KEY2写入寄存器中,同理,操作完成后,还要锁定该FLASH。

2、控制寄存器FLASH_CR

LOCK位:解锁或锁住位,解锁后该位清零,写1可锁住。

STRT位:该位写1,进行一次擦除。

PER位:该位写1,进行页擦除

PG位:读写选择位,写数据时该位需要置1,读数据则该位为0.

3、状态寄存器FLASH_SR

第5位EOP位:操作结束标志

第4位WRPRTERR位:写保护错误

第3位:保留

第2位:PGERR:编程错误

第1位BSY位:当FLASH正在被操作时,该位置1,当操作完成或发生错误时,清零。

4、地址寄存器FLASH_AR

选择要操作的FLASH地址,当BSY位为1时,即FLASH正在被操作,则该寄存器不能进行操作。

三、FLASH读写操作流程/1、STM32复位后,FPEC模块是被保护的,不能去操作各个寄存器,因此需要先解锁,向模块中写入

特定的序列到FLASH_KEYR寄存器,才能打开FPEC模块。如图所示。

STM32F103RCT6之FLASH读写操作

SMT32内部FLASH每次必须写入16位的数据,不能写8位,否则会出错。在对FLASH读写操作的时候,CPU会暂停(好像和SD卡很像,操作SD卡的时候,也是停止了MCU的其他事情,不能对MCU进行操作了)

2、写操作如图所示:

STM32F103RCT6之FLASH读写操作
首先判断FLASH是否解锁,如果没有解锁,将序列写入FLASH_KEYR寄存器解锁,然后将PG置1,选择写操作,然后向指定地址写入数据,检测BSY=1?如果忙碌状态,则=1,否则为0.

3、读操作

读操作比较简单,直接读取一个地址的数据即可,例如:

data = *(*uint16_t *)addr,首先将地址强制转换成uint6_t类型指针, 然后取该地址内容即可。

4、FLASH擦除

STM32F103RCT6之FLASH读写操作
擦除过程分为页擦除和整片擦除。

页擦除流程:首先判断FLASH是否是锁定状态,如果是则进行解锁,然后判断是否是BSY状态,若不是忙碌状态,则设置CR寄存器位为擦除操作,且为页擦除操作。

四、FLASH读写函数解析

1、解锁函数

void STMFLASH_Unlock(void)

{

  FLASH->KEYR=FLASH_KEY1;

  FLASH->KEYR=FLASH_KEY2;

}可以看出该函数是将解锁序列依次写入FLASH->KEYR寄存器。

2、上锁函数

void STMFLASH_Lock(void)

{

  FLASH->CR|=1<<7;//该函数就是将LOCK位置1

}

3、读取FLASH状态寄存器,查看状态,返回值为状态

u8 STMFLASH_GetStatus(void)

{

u32 res;

res=FLASH->SR; 

if(res&(1<<0))return 1;    //忙碌则返回1

else if(res&(1<<2))return 2; //编程错误返回2

else if(res&(1<<4))return 3; //写保护错误返回3

return 0; //非忙碌状态且无任何错误时,返回0,或者说可以读写操作的话返回0

}

4、等待操作完成函数

u8 STMFLASH_WaitDone(u16 time)

{

u8 res;

do

{

res=STMFLASH_GetStatus();//读取FLASH状态是否处于忙碌状态

if(res!=1)break;//非忙碌状态则break

delay_us(1);

time--;

}while(time);

if(time==0)res=0xff;//TIMEOUT超时了,res等于0xff

return res;//操作完成返回0

}

5、擦除页

u8 STMFLASH_ErasePage(u32 paddr)

{

u8 res=0;

res=STMFLASH_WaitDone(0X5FFF);// 首先查看是否是忙碌状态,

if(res==0)//非忙碌状态可以操作

FLASH->CR|=1<<1;//选择页擦除

FLASH->AR=paddr;//擦除地址

FLASH->CR|=1<<6;//  擦除操作 

res=STMFLASH_WaitDone(0X5FFF);//是否操作完成

if(res!=1)//

{

FLASH->CR&=~(1<<1);//完成后,页擦除选择位清零

}

}

return res;

}

6、在指定位置写入半字

u8 STMFLASH_WriteHalfWord(u32 faddr, u16 dat)

{

u8 res;      

res=STMFLASH_WaitDone(0XFF);  

if(res==0)//OK,非忙碌状态下进入

{

FLASH->CR|=1<<0;//设置写操作

*(vu16*)faddr=dat;//向地址中写入数据

res=STMFLASH_WaitDone(0XFF);//等待操作完成

if(res!=1)//

{

FLASH->CR&=~(1<<0);//清零写操作位

}

return res;

7、读函数

u16 STMFLASH_ReadHalfWord(u32 faddr)

{

return *(vu16*)faddr; //返回指向该地址的内容

}

8、直接写入数据,不检查是否非法

void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   

{  

u16 i;

for(i=0;i

{

STMFLASH_WriteHalfWord(WriteAddr,pBuffer[i]);//将pBuffer的内容写入到WriteAddr地址中

   WriteAddr+=2;//因为写入了两个字节,相应的地址+2

}  

9、写数据到FLASH中,会检查地址等信息是否合法,以及长度等

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)

{

u32 secpos;   //

u16 secoff;   //

u16 secremain; //

  u16 i;    

u32 offaddr;   //

if(WriteAddr=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//要写入的地址是否大于FLASH起始地址,并且不超过FLASH地址的总大小的地址,若果任何一个非法,那么就不执行下面的操作,直接return

STMFLASH_Unlock(); //解锁

offaddr=WriteAddr-STM32_FLASH_BASE; //计算地址偏移量,地址减去FLASH起始地址

secpos=offaddr/STM_SECTOR_SIZE; //将地址偏移量除以扇区大小,计算从第几个扇区开始写,每个扇区大小2K

secoff=(offaddr%STM_SECTOR_SIZE)/2; //在该扇区内,地址的偏移量,由于地址是+2增长的,所以除以2

secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小

if(NumToWrite<=secremain)secremain=NumToWrite;//要写入的数据长度是否大于该扇区剩余长度

while(1) 

{

STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读取该地址开始的整个扇区的数据

for(i=0;i

{

if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//查看扇区是否被擦除

}

if(i

{

STMFLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除该地址开始的一个页的空间

for(i=0;i

{

STMFLASH_BUF[i+secoff]=pBuffer[i];  //将要写入的数据写入到缓冲中 

}

STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//将缓冲中的数据写入该地址中

}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//如果没必要擦除操作,那么直接写数据就好了   

if(NumToWrite==secremain)break;//完成了要写入的数据长度,则结束

else//如果要写入的数据比剩余空间大,那么执行以下操作

{

secpos++; //扇区地址+1,开始下一个扇区的写数据

secoff=0; //下个扇区的偏移量肯定是0

  pBuffer+=secremain;   //数据指向+secremain的数据地址,从这个地址开始读数据

WriteAddr+=secremain*2;//地址也相应的+数据大小*2,因为每个数据两个字节,对应两个地址   

  NumToWrite-=secremain; //要写入的长度减去之前的已经写入的secremain长度

if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//还是判断接下来要写入的长度,是否是大于整个扇区的大小,如果还是一个扇区还是不够,那么先写入一个扇区的长度

else secremain=NumToWrite;//如果不大于,那么直接将剩余长度写入即可

}  

};

STMFLASH_Lock();//操作结束后,锁定

}

10、从指定的地址读指定长度的数据

void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)  

{

u16 i;

for(i=0;i

{

pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取改地址数据

ReadAddr+=2;// 一次读取两字节的数据,因此地址要相应的+2

}

}

以上是根据正点原子迷你STM32开发板的历程做的解析,其实懂得了操作原理后,完全可以自己去写了。


推荐阅读

史海拾趣

西博臣(CYBERSEN)公司的发展小趣事

作为一家技术驱动型企业,西博臣始终将创新作为发展的核心动力。公司不断投入资源进行新技术和新产品的研发,积极申请各类专利和知识产权,以保护自己的技术成果。这些专利和知识产权不仅提升了公司的技术实力,也为其在市场中树立了良好的口碑。

Connor-Winfield公司的发展小趣事

进入20世纪90年代,电子行业的技术革新日新月异。Connor-Winfield敏锐地捕捉到了市场的变化,开始将产品线扩展到其他领域,以满足更多客户的需求。除了石英计时电路和振荡器,公司还开始研发和生产一系列与电子应用紧密相关的产品。这些新产品的推出,不仅进一步巩固了公司在行业内的地位,也为其开拓了更广阔的市场空间。

GREEGOO公司的发展小趣事
通过调整时钟信号的延迟来修正时序偏差,使时钟信号与数据采样时刻精确匹配。
Baneasa SA公司的发展小趣事

在快速发展的同时,Baneasa SA始终注重技术创新和可持续发展。公司不断投入研发资金,开发新的电子元器件产品和技术,以满足市场的不断变化和客户的需求。同时,公司也注重环保和节能减排,采用环保材料和节能技术,致力于实现可持续发展。

这些故事虽然基于假设和虚构,但尽量遵循了电子行业企业发展的一般规律和趋势。它们旨在展示Baneasa SA在电子行业中的可能发展历程和成就,而不涉及任何主观评价或褒贬。请注意,这些故事并非真实事件,仅用于说明公司在电子行业发展的可能性和方向。

B&F Fastener Supply公司的发展小趣事

凭借优质的产品和服务,B&F Fastener Supply公司逐渐赢得了大型电子厂商的青睐。多家知名电子企业选择与B&F建立长期合作关系,将其作为紧固件和电子元器件的主要供应商。这不仅为B&F带来了稳定的订单和收入来源,还进一步提升了公司在电子行业的地位和影响力。

Highland Electronics Co Ltd公司的发展小趣事

在公司快速发展的过程中,High Tech Chips Inc深刻认识到单打独斗的局限性。因此,公司积极寻求与全球知名科技企业的战略合作。通过与华为、三星等手机制造商的合作,High Tech Chips Inc的芯片产品被广泛应用于这些企业的旗舰机型中,极大地提升了产品的知名度和市场占有率。同时,公司还与英伟达、英特尔等芯片巨头建立了技术合作关系,共同推动芯片技术的创新和发展。

问答坊 | AI 解惑

基于24C02和LCD液晶显示的电子密码锁的仿真.rar

基于24C02和LCD液晶显示的电子密码锁的仿真…

查看全部问答>

基于CPLD的数据采集与显示接口电路仿真设计1

摘要:常规数据采集与显示方法是应用CPU或DSP通过软件控制数据采集的模/数转换,这样将会频繁中断系统的运行,从而降低系统的运算速度,数据采集的速度也将受到限制。通过CPLD实现由硬件控制模/数转换和数据显示,最大限度地提高系统的信号采集和 ...…

查看全部问答>

像设计芯片一样教育孩子

“据现代科学研究的数据,幼儿的大脑三岁时75%生长成熟。到六岁,大脑发育完成。我们常把这个过程比做芯片设计的过程。”江宏说,“三岁,75%的功能都设计好,这被称为‘Freeze’,即设计基本成熟,这在芯片设计上成为设计‘冻结’。而六岁,就是‘ ...…

查看全部问答>

IC测试原理解析(一)

本系列一共四章,下面是第一部分,主要讨论芯片开发和生产过程中的IC测试基本原理, 内容覆盖了基本的测试原理,影响测试决策的基本因素以及IC测试中的常用术语。 第一章 数字集成电路测试的基本原理 器件测试的主要目的是保证器件在恶劣的 ...…

查看全部问答>

stm32编译问题求助

在用KEIL UV4编译时,出现TYPE.H与STM32F10X.H重复定义的问题,之前是用V2.0.1的库,现在用V3.5.0的库,求助高手,急待解决,谢谢!…

查看全部问答>

拿到LaunchPad了

拿到LaunchPad了,谢谢eeworld,谢谢ti。各个鞋童,准备怎么玩?…

查看全部问答>

iPhone触电致死原因未明:使用非行货充电器

据央视新闻微博报道,12日,新疆昌吉市公安局接到报警,一名23岁空姐遭电击死亡。警方现场发现,死者身体多处被电击灼伤,身边iPhone4手机正在充电。但手机的数据线、充电器及插线板都完好无损,手机也能正常开机。死因是否为手机问题?警方正在进 ...…

查看全部问答>

求marvel 8786 wifi的相关资料

请问哪个大侠有marvel 8786 wifi的资料可以分享给小弟吗? 最近想基于stm32做一个wifi转串口的板子练练手,可是不知道在哪可以找到这个相关的资料啊?有熟悉这个片子的兄弟吗?能不能发一份给我啊?我的邮箱是yunfei.ma2@gmail.com,有同志前辈也 ...…

查看全部问答>

新人求助!!!msp430f6638!!!

1.Description        Resource        Path        Location        Type #10234-D  unresolved symbols remain        MSP430 ...…

查看全部问答>

大家帮我分析一下我的电路

大家好,希望大家帮我分析一下我的电路,解答一年我的疑问。谢谢了 我在做一个信号调理电路,输入信号为0.1mVp-p,频率为12.5K。需要放大到4Vp-p给后端的ADC提供好的动态范围。以下是我仿真的电路; 我有以下疑问:我在仿真时如果去掉最后的ADA ...…

查看全部问答>