STM32学习笔记--闪存Flash

news/2024/6/3 18:48:36 标签: stm32, 学习, 笔记

        STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程。

        读写FLASH的用途:利用程序存储器的剩余空间来保存掉电不丢失的用户数据 ,通过在程序中编程(IAP),实现程序的自我更新,在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAGSWD协议或系统加载程序(Bootloader)下载程序,在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序。

 FPEC模块处理闪存的编程和擦除操作,它包括7个32位的寄存器:

FPEC键寄存器(FLASH_KEYR)
选择字节键寄存器(FLASH_OPTKEYR)
闪存控制寄存器(FLASH_CR)
闪存状态寄存器(FLASH_SR)
闪存地址寄存器(FLASH_AR)
选择字节寄存器(FLASH_OBR)
写保护寄存器(FLASH_WRPR)

 使用指针读指定地址下的存储器:

          uint16_t Data = *((__IO uint16_t *)(0x08000000));

使用指针写指定地址下的存储器:

          *((__IO uint16_t *)(0x08000000)) = 0x1234;

其中:

          #define    __IO    volatile

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

 STM32—Flash读写详解_stm32写入flash-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zhuxinmingde/article/details/131972752?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-131972752-blog-123402701.235^v39^pc_relevant_3m_sort_dl_base1&spm=1001.2101.3001.4242.2&utm_relevant_index=4
        下文代码中STMFLASH_Read(FLASH_ADDR,Temporary_storage,size);这里FLASH_ADDR是我们要读取的起始地址,Temporary_storage是16位的指针变量,存放我们读取到的内容,size是我们要读取的大小,值得注意的是,size是半字大小,也就是有多少个两个字节。比如我们要读取100个字节,size就可以填50。

FLASH的读取
直接读取某一地址的内容
因为读取FLASH并不需要解锁,我们可以直接用指针指向所读的地址,之后读取此地址的内容即可。

p = (uint32_t *)(0x08008000);
printf("\r\n读取内部FLASH该地址存储的内容为:0x%x",*p);
此程序就是先将0x08008000赋给指针变量P,之后将P指向地址的内容以16进制的格式输出出来。

读取选定位置的选定大小的内容
1. 首先我们编写一个函数,用以读取指定地址的半字(16位数据)。

u16 STMFLASH_ReadHalfWord(u32 faddr)
{
	return *(vu16*)faddr; 
}
2. 从指定地址开始读出指定长度的数据

LReadAddr:起始地址

pBuffer:数据指针

NumToWrite:半字(16位)数

void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   	
{
	u16 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
		ReadAddr+=2;//偏移2个字节.	
	}
}
当我们想读取FLASH内容时,只需要直接调用上面的函数即可。

共有三个键值:
RDPRT键 = 0x000000A5

        RDP:读出保护选择字节
        读出保护功能帮助用户保护存在闪存中的代码。该功能由设置信息块中的一个选择字节启用。
        写入正确的数值(RDPRT键=0x00A5)到这个选择字节后,闪存被开放允许读出访问。

KEY1 = 0x45670123
KEY2 = 0xCDEF89AB

解除闪存锁
        复位后,FPEC模块是被保护的,不能写入FLASH_CR寄存器;通过写入特定的序列到FLASH_KEYR寄存器可以打开FPEC模块,这个特定的序列是在FLASH_KEYR写入两个键值(KEY1和KEY2);错误的操作序列都会在下次复位前锁死FPEC模块和FLASH_CR寄存器。
        写入错误的键序列还会产生总线错误;总线错误发生在第一次写入的不是KEY1,或第一次写入的是KEY1但第二次写入的不是KEY2时;FPEC模块和FLASH_CR寄存器可以由程序设置FLASH_CR寄存器中的LOCK位锁住,这时可以通过在FLASH_KEYR中写入正确的键值对FPEC解锁。

主闪存编程

        对主闪存编程每次可以写入16位。当FLASH_CR寄存器的PG位为’1’时,在一个闪存地址写入一个半字将启动一次编程;写入任何非半字的数据,FPEC都会产生总线错误。在编程过程中(BSY位为’1’),任何读写闪存的操作都会使CPU暂停,直到此次闪存编程结束。

 标准的闪存编程顺序如下:(即上图详细过程文字描述)
        检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作;
        设置FLASH_CR寄存器的PG位为’1’;
        在指定的地址写入要编程的半字;
        等待BSY位变为’0’;
        读出写入的地址并验证数据。
注意: 当FLASH_SR寄存器的BSY位为’1’时,不能对任何寄存器执行写操作。

        这种模式下CPU以标准的写半字的方式烧写闪存,FLASH_CR寄存器的PG位必须置’1’。FPEC先读出指定地址的内容并检查它是否被擦除,如未被擦除则不执行编程并在FLASH_SR寄存器的PGERR位提出警告(唯一的例外是当要烧写的数值是0x0000时,0x0000可被正确烧入且PGERR位不被置位);如果指定的地址在FLASH_WRPR中设定为写保护,则不执行编程并在FLASH_SR寄存器的WRPRTERR位置’1’提出警告。FLASH_SR寄存器的EOP为’1’时表示编程结束。

闪存擦除

 页擦除
闪存的任何一页都可以通过FPEC的页擦除功能擦除;擦除一页应遵守下述过程:
        检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
        设置FLASH_CR寄存器的PER位为’1’;
        用FLASH_AR寄存器选择要擦除的页;
        设置FLASH_CR寄存器的STRT位为’1’;
        等待BSY位变为’0’;
        读出被擦除的页并做验证。

 整片擦除
可以用整片擦除功能擦除所有用户区的闪存,信息块不受此操作影响。建议使用下述过程:
        检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
        设置FLASH_CR寄存器的MER位为’1’;
        设置FLASH_CR寄存器的STRT位为’1’;
        等待BSY位变为’0’;
        读出所有页并做验证。

选择字节说明:
        选择字节共有8个字节,由用户根据应用的需要配置;例如:可以选择使用硬件模式的看门狗或软件的看门狗。
        在选择字节中每个32位的字被划分为下述格式:

        每次系统复位后,选择字节装载器读出信息块的数据并保存在寄存器中;每个选择位都在信息块中有它的反码位,在装载选择位时反码位用于验证选择位是否正确,如果有任何的差别,将产生一个选择字节错误标志(OPTERR)。当发生选择字节错误时,对应的选择字节被强置为0xFF。当选择字节和它的反码均为0xFF时(擦除后的状态),则关闭上述验证功能。 

•RDP:写入RDPRT键(0x000000A5)后解除读保护
•USER:配置硬件看门狗和进入停机/待机模式是否产生复位
•Data0/1:用户可自定义使用
•WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)

 STM32单片机bootloader扫盲_stm32 bootloader-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_42378319/article/details/120896348

BootLoader和APP之间的关系
        APP就是平时写的单片机上的应用程序,而BootLoader本质上和APP一样,也是平时写的应用程序。BootLoader只不过是拥有从外部接收数据,更新Flash(也就是APP),跳转至APP功能的特殊APP罢了。

        以STM32F103为例,如果没有BootLoader,flash分布就如下图左半部分。如果有BootLoader,就如下图右半部分,将flash分为两部分(这里举例用0x800 4000做分界线),存储了两个应用程序(BootLoader和APP)

 


http://www.niftyadmin.cn/n/5231037.html

相关文章

模糊C均值(Fuzzy C-means,FCM)聚类的python程序代码的逐行解释,看完你也会写!!

文章目录 前言一、本文的原始代码二、代码的逐行详细解释总结 前言 接上一篇博客&#xff0c;详细解释FCM聚类的程序代码&#xff01;&#xff01; 一、本文的原始代码 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets import skfuzzy as…

使用git filter: clean,smudge管理思源笔记的单行json文件`.sy`,减少冲突,方便合并,同时保证性能

文章目录 原理/动机缺点配置步骤脚本代码/可执行文件 原理/动机 思源笔记的单行json文件.sy&#xff0c;相比多行json文件&#xff0c;据说可提高30~50%的读写、解析效率&#xff0c;但是单行文件用git管理时很容易发生冲突&#xff0c;diff, merge效率也很低。 使用git filt…

代码随想录训练营第五十二天300.最长递增子序列674. 最长连续递增序列718. 最长重复子数组

300.最长递增子序列 题目链接 300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; 讲解链接 代码随想录 (programmercarl.com) 定义dp数组dp[i]为以num[i]为结尾的增长数组的最大长度&#xff1b; 此时dp[0]1; i遍历nums数组的长度&#xff0c;逐渐形成以每个元素结…

卡码网15 .链表的基本操作III

链表的基础操作III 时间限制&#xff1a;1.000S 空间限制&#xff1a;128MB 题目描述 请编写一个程序&#xff0c;实现以下链表操作&#xff1a;构建一个单向链表&#xff0c;链表中包含一组整数数据。 1. 实现在链表的第 n 个位置插入一个元素&#xff0c;输出整个链表的…

2023-12-01 事业-代号s-如何装修“高转化“首页

摘要: 2023-12-01 事业-代号s-如何装修"高转化"首页 如何装修"高转化"首页 影响独立站转化率6大因素:产品、素材、受众、落地页、结算流程、复购。 今天就来分享下,独立站高转化首页如何装修?整个网站首页框架应该放置什么内容? 传统设计 VS 8P设计 …

JSON详细教程

&#x1f60a;JSON详细教程 &#x1f6a9;JSON简介☃️JSON语法规则&#x1f50a;JSON和JavaScript对象的区别 ☃️JSON数据类型字符串&#x1f50a;数字&#x1f50a;布尔值&#x1f50a;数组&#x1f50a;对象&#x1f50a;Null ☃️JSON对象&#x1f50a;访问JSON对象的值&a…

TA-Lib学习研究笔记——Price Transform (五)

TA-Lib学习研究笔记——Price Transform &#xff08;五&#xff09; 1.AVGPRICE Average Price 函数名&#xff1a;AVGPRICE 名称&#xff1a;平均价格函数 语法&#xff1a; real AVGPRICE(open, high, low, close) df[AVGPRICE] tlb.AVGPRICE(df[open],df[high],df[low…

python 使用reportlab打造29页图文并茂pdf(全网reportlab最强pdf自动化生成代码)

python 使用reportlab打造29页图文并茂pdf(全网reportlab最强pdf自动化生成代码&#xff09; 这次项目所使用的代码如果同志们可以灵活使用&#xff0c;基本上可以解决百分之九十以上的pdf模板自动化生成。 最近博主&#xff0c;做了一个项目&#xff0c;使用reportlab制作pd…