FLASH简介

  • STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程,读取指定寄存器直接使用指针读即可

  • 读写FLASH的用途:

              利用程序存储器的剩余空间来保存掉电不丢失的用户数据

              通过在程序中编程(IAP),实现程序的自我更新,类似于OTA

  • 在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
  • 在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序

STM32F10xxx闪存编程参考手册

闪存模块组织

        特征与W25Q64类似

       这里的存储器分化:只有一个页,每页大小都是1K字节。地址范围:起始地址:只要以000、400、800、C00结尾的。

FLASH基本结构

FLASH解锁

  • FPEC共有三个键值:

               RDPRT键 = 0x000000A5——解除读保护的密钥

                KEY1 = 0x45670123——这是自定义的密码

                KEY2 = 0xCDEF89AB

  • 解锁:

               复位后,FPEC被保护,不能写入FLASH_CR

               在FLASH_KEYR先写入KEY1,再写入KEY2,解锁

               错误的操作序列会在下次复位前锁死FPEC和FLASH_CR

  • 加锁:

               设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR

读取:

使用指针访问存储器,因为STM32的内部存储器是挂载在总线上的

  • 使用指针读指定地址下的存储器:
       uint16_t Data = *((__IO uint16_t *)(0x08000000));
  • 使用指针写指定地址下的存储器:——需要解锁等提高权限
     *((__IO uint16_t *)(0x08000000)) = 0x1234;
  • 其中:
   #define  __IO  volatile      //防止编译器优化

程序存储器编程

程序存储器页擦除

程序存储器全擦除

选项字节

  • RDP:写入RDPRT键(0x000000A5)后解除读保护
  • USER:配置硬件看门狗和进入停机/待机模式是否产生复位
  • Data0/1:用户可自定义使用
  • WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)
  • 带n,当写入USER时要同时在nUSET写入数据的反码,这样才是有效的——一般函数会自动执行

选项字节编程

  • 解锁闪存
  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作
  • 解锁FLASH_CR的OPTWRE位
  • 设置FLASH_CR的OPTPG位为1
  • 写入要编程的半字到指定的地址
  • 等待BSY位变为0
  • 读出写入的地址并验证数据

选项字节擦除

  • 解锁闪存
  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作
  • 解锁FLASH_CR的OPTWRE位
  • 设置FLASH_CR的OPTER位为1
  • 设置FLASH_CR的STRT位为1
  • 等待BSY位变为0
  • 读出被擦除的选择字节并做验证

器件电子签名

  • 电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名
  • 闪存容量寄存器:

              基地址:0x1FFF F7E0

              大小:16位

  • 产品唯一身份标识寄存器:

              基地址: 0x1FFF F7E8

              大小:96位

接线图:

15-1 读写内部FLASH

最底层模块MyFALSH实现读取、擦除和编程

再此模块上建Store模块,实现参数数据的读写和存储管理:任意读写参数,并且这些参数是掉电不丢失的-定义SRAM数组,把需要掉电不丢失的数据放入到SRAM中,之后调用保存的函数使SRAM数组自动备份到闪存里;上电后,Store初始化,自动会把闪存里的数据读回SRAM数组里——闪存管理策略

使用STM32 ST-LINK Utility进行调试:可以看到闪存里的数据;

       注:使用完,记得断开连接不然设备占用,导致程序运行不了

思路:

闪存不需要初始化

读取:直接使用指针

擦除:先解锁,调用全擦除函数或页擦除函数,之后加锁

编程:先解锁,调用函数,之后加锁

选项字节的操作与闪存类似,有对应的函数,但是同时是用软件进行图形化修改

FLASH相关函数:系统分为三大部分的库函数——对应不同的配置,此实验只用第一部分

void FLASH_Unlock(void);           //解锁

void FLASH_Lock(void);              //加锁

//对主闪存和选项字节的操作配置,返回值FLASH_Status一个执行状态

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);             //闪存擦除某一页

FLASH_Status FLASH_EraseAllPages(void);              //全擦除

FLASH_Status FLASH_EraseOptionBytes(void);        //擦除选项字节

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);        //在指定地址写入字

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);        //在指定地址写入半字

//选项字节的写入

FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);            //自定义的Data0和Data1

FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);          //写保护

FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);         //读保护

FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);         //用户选项的三个配置位

//获取选项字节当前的状态

uint32_t FLASH_GetUserOptionByte(void);       //获取用户选项的三个配置位

uint32_t FLASH_GetWriteProtectionOptionByte(void);           //获取写保护

FlagStatus FLASH_GetReadOutProtectionStatus(void);          //获取写保护

//状态位

FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);

void FLASH_ClearFlag(uint32_t FLASH_FLAG);

FLASH_Status FLASH_GetStatus(void);             //获取状态

FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);           等待上一次操作——在前面的函数中自调用了,一般不需要单独调用


配置闪存地址空间——keil魔术棒里Debug对应设备的接口

手动分配闪存尾部的数据空间,给自己用;

擦除模式


判断程序大小

分别是:代码;只读数据、读写数据、零初始化数据


main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"uint8_t KeyNum;					//定义用于接收按键键码的变量int main(void)
{/*模块初始化*/OLED_Init();				//OLED初始化Key_Init();					//按键初始化Store_Init();				//参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失/*显示静态字符串*/OLED_ShowString(1, 1, "Flag:");OLED_ShowString(2, 1, "Data:");while (1){KeyNum = Key_GetNum();		//获取按键键码if (KeyNum == 1)			//按键1按下{Store_Data[1] ++;		//变换测试数据Store_Data[2] += 2;Store_Data[3] += 3;Store_Data[4] += 4;Store_Save();			//将Store_Data的数据备份保存到闪存,实现掉电不丢失}if (KeyNum == 2)			//按键2按下{Store_Clear();			//将Store_Data的数据全部清0}OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//显示Store_Data的第一位标志位OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//显示Store_Data的有效存储数据OLED_ShowHexNum(3, 6, Store_Data[2], 4);OLED_ShowHexNum(4, 1, Store_Data[3], 4);OLED_ShowHexNum(4, 6, Store_Data[4], 4);}
}
Store.c
#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"#define STORE_START_ADDRESS		0x0800FC00		//存储的起始地址
#define STORE_COUNT				512				//存储数据的个数uint16_t Store_Data[STORE_COUNT];				//定义SRAM数组/*** 函    数:参数存储模块初始化* 参    数:无* 返 回 值:无*/
void Store_Init(void)
{/*判断是不是第一次使用*/if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//读取第一个半字的标志位,if成立,则执行第一次使用的初始化{MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定页MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循环STORE_COUNT次,除了第一个标志位{MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了标志位的有效数据全部清0}}/*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循环STORE_COUNT次,包括第一个标志位{Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//将闪存的数据加载回SRAM数组}
}/*** 函    数:参数存储模块保存数据到闪存* 参    数:无* 返 回 值:无*/
void Store_Save(void)
{MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定页for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,包括第一个标志位{MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//将SRAM数组的数据备份保存到闪存}
}/*** 函    数:参数存储模块将所有有效数据清0* 参    数:无* 返 回 值:无*/
void Store_Clear(void)
{for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,除了第一个标志位{Store_Data[i] = 0x0000;							//SRAM数组有效数据清0}Store_Save();										//保存数据到闪存
}MyFLASH.c
#include "stm32f10x.h"                  // Device header/*** 函    数:FLASH读取一个32位的字* 参    数:Address 要读取数据的字地址* 返 回 值:指定地址下的数据*/
uint32_t MyFLASH_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}/*** 函    数:FLASH读取一个16位的半字* 参    数:Address 要读取数据的半字地址* 返 回 值:指定地址下的数据*/
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
}/*** 函    数:FLASH读取一个8位的字节* 参    数:Address 要读取数据的字节地址* 返 回 值:指定地址下的数据*/
uint8_t MyFLASH_ReadByte(uint32_t Address)
{return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
}/*** 函    数:FLASH全擦除* 参    数:无* 返 回 值:无* 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在*/
void MyFLASH_EraseAllPages(void)
{FLASH_Unlock();					//解锁FLASH_EraseAllPages();			//全擦除FLASH_Lock();					//加锁
}/*** 函    数:FLASH页擦除* 参    数:PageAddress 要擦除页的页地址* 返 回 值:无*/
void MyFLASH_ErasePage(uint32_t PageAddress)
{FLASH_Unlock();					//解锁FLASH_ErasePage(PageAddress);	//页擦除FLASH_Lock();					//加锁
}/*** 函    数:FLASH编程字* 参    数:Address 要写入数据的字地址* 参    数:Data 要写入的32位数据* 返 回 值:无*/
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();							//解锁FLASH_ProgramWord(Address, Data);		//编程字FLASH_Lock();							//加锁
}/*** 函    数:FLASH编程半字* 参    数:Address 要写入数据的半字地址* 参    数:Data 要写入的16位数据* 返 回 值:无*/
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();							//解锁FLASH_ProgramHalfWord(Address, Data);	//编程半字FLASH_Lock();							//加锁
}

15-2 读取芯片ID

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
//#include "OLED_Font.h"
//4-1 OLED显示屏
int main(void){OLED_Init();OLED_ShowString(1,1,"F_SIZE:");OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4);//ID地址:0x1FFFF7E0//显示UIDOLED_ShowString(2,1,"UID:");//偏移量OLED_ShowHexNum(2,6,*((__IO uint16_t *)(0x1FFFF7E8)),4);OLED_ShowHexNum(2,11,*((__IO uint16_t *)(0x1FFFF7E8+0x02)),4);OLED_ShowHexNum(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x04)),8);OLED_ShowHexNum(4,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);while(1){}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94192.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94192.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94192.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电蚊拍的原理及电压电容参数深度解析:从高频振荡到倍压整流的完整技术剖析

1. 引言在炎炎夏日&#xff0c;蚊虫成为人们生活中的一大困扰。电蚊拍作为一种高效、环保的物理灭蚊工具&#xff0c;凭借其便携性和实用性在全球范围内得到了广泛应用。然而&#xff0c;许多用户对这种看似简单的小家电背后的工作原理知之甚少。电蚊拍是一种新型的灭蚊小家电&…

Mac简单测试硬盘读写速度

一、下载软件 Blackmagic Disk Speed Test 「达芬奇 磁盘速度测试」二、选中测试位置可以随便选个文件比如“下载”目录三、开始测速

⸢ 零 ⸥ ⤳ 安全体系构建内容结构

&#x1f44d;点「赞」&#x1f4cc;收「藏」&#x1f440;关「注」&#x1f4ac;评「论」在金融科技深度融合的背景下&#xff0c;信息安全已从单纯的技术攻防扩展至架构、合规、流程与创新的系统工程。作为一名从业十多年的老兵&#xff0c;系统阐述数字银行安全体系的建设路…

XP系统安装Android Studio 3.5.3并建立Java或Native C++工程,然后在安卓手机上运行

第一节 安装Android Studio 3.5.3Android Studio 3.5.3下载地址&#xff1a;Android Studio 3.5.3 December 5, 2019 Windows (32-bit): android-studio-ide-191.6010548-windows32.zip (756.1 MB) https://redirector.gvt1.com/edgedl/android/studio/ide-zips/3.5.3.0/androi…

calchash.exe和chckhash.exe计算pe文件hash值的两个实用小工具

第一部分&#xff1a; C:\WINDOWS\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\NT5.CAT t部分内容B B D 0 2 2 2 1 A A 6 5 5 6 2 8 F 4 9 5 F 6 C D 3 0 3 9 0 8 B B E 0 0 F 9 5 9 5 第二部分&#xff1a; D:\>calchash.exe pidgen.dll BB D0 22 21 AA 65 …

lanczso算法中的额外正交化代码解释

额外正交化 定义&#xff1a;在Lanczos算法中&#xff0c;由于浮点误差&#xff0c;生成的向量可能不完全正交&#xff0c;需要额外正交化步骤。代码实现&#xff1a;def extra_orthogonalization(v, basis):for u in basis:v - u * (v.dot(u) / u.dot(u))

Rabbit 实战指南-学习笔记

第 4 章 RabbitMQ 进阶 mandatory 参数 Returning | RabbitMQ 当 mandatory 参数设为 true 时&#xff0c;交换器无法根据自身的类型和路由键找到一个符合条件的队列&#xff0c;那么RabbitMQ 会调用 Basic.Return 命令将消息返回给生产者,通过调用channel.addReturnListener …

BEVDet4D

1. BEVDet4D算法动机及开创性思路 1&#xff09;BEVDet算法概述输入输出&#xff1a;输入为6视角图像&#xff08;NuScenes数据集&#xff09;&#xff0c;输出为3D检测结果核心模块&#xff1a; 图像编码器&#xff1a;由Backbone网络和多尺度特征融合网络组成&#xff0c;处理…

当 AI 学会 “理解” 人类:自然语言处理的进化与伦理边界

大家可以去我的资源看看&#xff0c;有很多关于AI的免费资源可以下载&#xff0c;不下载也可以看看&#xff0c;真的对你有用引言&#xff1a;从 “对话” 到 “理解”——AI 语言能力的时代跃迁现实锚点&#xff1a;以日常场景切入&#xff08;如 ChatGPT 流畅回应复杂问题、A…

WPF控件随窗体大宽度高度改变而改变

前台控件中&#xff1a;Width"{Binding RelativeSource{RelativeSource AncestorTypeWindow}, PathWidth}"后台代码&#xff1a;定义在加载事件里面this.SizeChanged ProductData_SizeChanged;private void ProductData_SizeChanged(object sender, SizeChangedEven…

E10 通过RPC实现账号批量锁定与解锁

需求背景&#xff1a;账号信息由三方系统管理&#xff0c;包含账号状态&#xff0c;所以需要通过提供给三方的 Rest 接口中&#xff0c;实现账号锁定与解锁。参考基线版本&#xff1a;10.0.2506.01&#xff0c;过低的版本可能无法使用。 锁定分为两种&#xff1a; &#xff08;…

什么是AI宠物

什么是AI宠物AI宠物是由AI大脑驱动的生命体AI产品。它能主动产生情绪和意图&#xff0c;并通过情绪和意图去驱动自己的动作和行为。它根据自己的意愿和用户互动&#xff0c;不受用户控制。从一定意义上讲&#xff0c;它拥有了人工生命和自由意志。它有自己的行为逻辑&#xff0…

简单AI:搜狐公司旗下AI绘画产品

本文转载自&#xff1a;简单AI&#xff1a;搜狐公司旗下AI绘画产品 - Hello123工具导航 ** 一、平台定位与技术特性 搜狐简单 AI 是搜狐推出的多模态 AI 创作平台&#xff0c;基于自研大模型提供文生图、文生文等能力。它专注于零门槛内容生成&#xff0c;用户无需专业技能即…

vue3 3d饼图

完整3D饼图项目下载 https://download.csdn.net/download/weixin_54645059/91716476 只有一个vue文件 直接下滑到完整代码就阔以 本文介绍了如何使用ECharts和ECharts-GL插件实现3D饼图效果&#xff0c;并提出了数值显示未解决的问题。主要包含以下内容&#xff1a; 安装所需…

全球电商业财一体化趋势加速,巨益科技助力品牌出海精细化运营

行业背景&#xff1a;跨境电商进入品牌化发展新阶段随着国内电商市场竞争日趋激烈&#xff0c;跨境电商已成为中国品牌寻求增长突破的重要赛道&#xff0c;在TikTok、Temu等平台出海浪潮推动下&#xff0c;越来越多的中国品牌开始布局全球市场。然而&#xff0c;从单一市场的铺…

【序列晋升】13 Spring Cloud Bus微服务架构中的消息总线

Spring Cloud Bus作为微服务架构中的关键组件&#xff0c;通过消息代理实现分布式系统中各节点的事件广播与状态同步&#xff0c;解决了传统微服务架构中配置刷新效率低下、系统级事件传播复杂等问题。它本质上是一个轻量级的事件总线&#xff0c;将Spring Boot Actuator的端点…

[激光原理与应用-314]:光学设计 - 光学系统设计与电子电路设计的相似或相同点

光学系统设计与电子电路设计虽分属不同工程领域&#xff0c;但在设计理念、方法论和工程实践中存在诸多相似或相同点。这些共性源于两者均需解决复杂系统的优化问题&#xff0c;并遵循工程设计的通用规律。以下是具体分析&#xff1a;一、设计流程的相似性需求分析与规格定义光…

Linux学习:信号的保存

目录1. 进程的异常终止与core dump标志位1.1 进程终止的方式1.2 core方案的作用与使用方式2. 信号的保存2.1 信号的阻塞2.2 操作系统中的sigset_t信号集类型2.3 进程PCB中修改block表的系统调用接口2.4 信号阻塞的相关问题验证1. 进程的异常终止与core dump标志位 1.1 进程终止…

数据分析编程第二步: 最简单的数据分析尝试

2.1 数据介绍有某公司的销售数据表 sales.csv 如下:第一行是标题&#xff0c;解释每一列存了什么东西。第二行开始每一行是一条数据&#xff0c;对应一个订单。这种数据有个专业的术语&#xff0c;叫结构化数据。这是现代数据处理中最常见的数据类型。整个表格的数据统称为一个…

UDP报文的数据结构

主要内容参照https://doc.embedfire.com/net/lwip/zh/latest/doc/chapter14/chapter14.html#id6&#xff0c;整理出来自用。 1. UDP 报文首部结构体&#xff08;udp_hdr&#xff09; 为清晰定义 UDP 报文首部的各个字段&#xff0c;LwIP 设计了udp_hdr结构体&#xff0c;其包含…