FLASH闪存(擦除、编译)

FLASH闪存

文章目录

  • FLASH闪存
    • 1.存储器映像位置
    • 2.FLASH简介
    • 3.闪存模块组织
      • 3.2闪存的共性:
    • 4.FLASH基本结构
      • 4.1FLASH解锁
      • 4.2使用指针访问寄存器
    • 5.选项字节
      • 5.1选项字节编程
      • 5.2选项字节擦除
    • 6.相关函数介绍
    • 7.读取内部FLASH(实操)
      • 7.1接线图
      • 7.2工程结构
      • 7.3代码
    • 8.读取芯片ID(实操)
      • 8.1接线图
      • 8.2代码

闪存是一个通用的名词,表示一种非易失性,掉电不丢失的存储器。比如PSI的W25Q64芯片。

本节的内容是stm32的内部闪存,也就是我们下载程序的时候,这个程序所存储的地方。

1.存储器映像位置

存储器映像

类型起始地址存储器用途
ROM0x0800 0000程序存储器Flash存储C语言编译后的程序代码
0x1FFF F000系统存储器存储BootLoader,用于串口下载
0x1FFF F800选项字节存储一些独立于程序代码的配置参数
RAM0x2000 0000运行内存SRAM存储运行过程中的临时变量
0x4000 0000外设寄存器存储各个外设的配置参数
0xE000 0000内核外设寄存器存储内核各个外设的配置参数

其中程序存储器是空间最大,最主要的部分,称作主存储器。

2.FLASH简介

  • STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程
  • 读写FLASH的用途:
    • **利用程序存储器的剩余空间来保存掉电不丢失的用户数据 **
    • 通过在程序中编程(IAP),实现程序的自我更新
  • 在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
  • 在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序

JTAG、SWD协议就是仿真器下载程序,就是目前使用的ST_Link使用SWD下载程序。每次下载都是把整个程序完全更新掉。

Bootloader串口下载,也是更新整个程序,这就是ICP下载方式。

3.闪存模块组织

C8T6的闪存容量是64K,属于中容量产品。

闪存组织模块

启动程序代码:系统存储器,存放的是原厂写入的Bootloader,用于串口下载

用户选择字节:也就是选项字节,存放一些独立的参数

闪存存储器接口寄存器,实际上并不属于闪存,地址都是40开头的,说明这个存储器接口寄存器,就是一个普通的外设和GPIO、定时器,串口等等都是一个性质的东西,都是SARM。

简言之,闪存存储器接口寄存器就是上面那些闪存的管理员,这些寄存器就是用来控制擦除和编程这个过程的

闪存的基本单位为页,共128K,而C8T6只有一半,为64页,共64K。所说的闪存的容量也只是主存储器的容量。

3.2闪存的共性:

  1. 写入前必须擦除
  2. 擦除必须以最小单位进行
  3. 擦除后数据位全变为1
  4. 数据只能1写0,不能0写1
  5. 擦除和写入之后都需要等待忙

4.FLASH基本结构

分为程序存储器,系统存储器和选项字节三部分。

FLASH基本结构

4.1FLASH解锁

  • FPEC共有三个键值:
    • RDPRT键 = 0x000000A5
    • KEY1 = 0x45670123
    • KEY2 = 0xCDEF89AB
  • 解锁:
    • 复位后,FPEC被保护,不能写入FLASH_CR
    • 在FLASH_KEYR先写入KEY1,再写入KEY2,解锁
    • 错误的操作序列会在下次复位前锁死FPEC和FLASH_CR
  • 加锁: 设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR(就是LOCK位写入1就好了)

4.2使用指针访问寄存器

  • 使用指针读指定地址下的存储器:
    • uint16_t Data = *((__IO uint16_t *)(0x08000000));
  • 使用指针写指定地址下的存储器:
    • *((__IO uint16_t *)(0x08000000)) = 0x1234;
  • 其中:
    • #define __IO volatile

读直接读写入,写需要先解锁。

5.选项字节

选项字节

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

写入RDP存储器时,要在对应的存储器写入反码。(写入RDP时要在nRDP写入对应的反码)。如果不是反码的关系,则代表数据无效,对应功能不执行。

5.1选项字节编程

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

5.2选项字节擦除

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

6.相关函数介绍

void FLASH_SetLatency(uint32_t FLASH_Latency);
void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
//与内核运行代码有关不需要太多了解。
void FLASH_Unlock(void);//解锁
void FLASH_Lock(void);//加锁,LOCK位设置为1
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);//用户选项的三个配置位
//上面4个是选项字节的写入
//对主闪存和选项字节,进行擦除和编程的函数
uint32_t FLASH_GetUserOptionByte(void);//获取用户选项的三个配置位
uint32_t FLASH_GetWriteProtectionOptionByte(void);//获取写保护状态
FlagStatus FLASH_GetReadOutProtectionStatus(void);//获取读保护状态
//获取选项字节当前的状态
FlagStatus FLASH_GetPrefetchBufferStatus(void);//获取预取缓冲区状态
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);//中断使能
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);//等待上一次操作,系统内部会调用,所以不用单独调用

7.读取内部FLASH(实操)

7.1接线图

读写内部FLASH

7.2工程结构

这里打算弄两个底层模块:

最底层叫MY_FLASH:这里实现闪存最基本的三个功能:读取、擦除和编程

上面层叫STORE:实现参数数据的读写和数据管理,定义一个SRAM数组,需要掉电不丢失的参数就写到SRAM数组里,最后调用保存的函数,这个SRAM数组就自动备份到闪存里,上电后store初始化,会自动再把闪存里的数据读回到SRAM数组里

最终实现的功能是:任意读写参数,并且这些参数是掉电不丢失的

7.3代码

代码部分主要就是对封装完的库函数进行调用。将数据封装到,数组,再将数组的内容写到闪存,在重新上电后再写回去实现掉电不丢失。

主程序main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"
#include "Store.h"uint16_t KeyNum = 0;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];void Store_Init(void){//判断是不是第一次使用if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS)!=0xA5A5){//A5A5不是固定的,只是判断是不是某个你设置的值,唯一,标志,IDMyFLASH_ErasePage(STORE_START_ADDRESS);MyFLASH_ProgramHalfWord(STORE_START_ADDRESS,0xA5A5);for(uint16_t i = 1;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,0x0000);}}for(uint16_t i = 0;i<STORE_COUNT;i++){Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS+i*2);}
}//保存:擦除界面后将数组的数据读取到闪存界面
void Store_Save(void){MyFLASH_ErasePage(STORE_START_ADDRESS);//擦除指定页for(uint16_t i = 0;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS+i*2,Store_Data[i]);//将数组数据备份到闪存}
}//手动清除操作
void Store_Clear(void){for(uint16_t i = 1;i<STORE_COUNT;i++){Store_Data[i] = 0x0000;}Store_Save();
}

Store.h

#ifndef __STORE_H
#define __STORE_Hextern uint16_t Store_Data[];void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);#endif

MyFLASH.c

#include "stm32f10x.h"                  // Device header//获取32位的字
uint32_t MyFLASH_ReadWord(uint32_t Address){//stm32的地址都是32位的return *((__IO uint32_t * )(Address));
}//获取16位的半字
uint16_t MyFLASH_ReadHalfWord(uint32_t Address){return *((__IO uint16_t * )(Address));
}
//获取一字节
uint8_t MyFLASH_ReadByte(uint32_t Address){return *((__IO uint8_t * )(Address));//使用指针访问
}//全擦除
void MyFLASH_EraseAllPages(void){FLASH_Unlock();//解锁FLASH_EraseAllPages();//全擦除FLASH_Lock();//加锁
}//页擦除
void MyFLASH_ErasePage(uint32_t PageAddress){FLASH_Unlock();FLASH_ErasePage(PageAddress);FLASH_Lock();
}//写入32位字
void MyFLASH_ProgramWord(uint32_t Address,uint32_t Data){FLASH_Unlock();FLASH_ProgramWord(Address,Data);FLASH_Lock();
}//写入16位半字
void MyFLASH_ProgramHalfWord(uint32_t Address,uint16_t Data){FLASH_Unlock();FLASH_ProgramHalfWord(Address,Data);FLASH_Lock();
}

MyFLASH.h

#ifndef __MY_FLASH
#define __MY_FLASHuint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);#endif

8.读取芯片ID(实操)

8.1接线图

读取芯片ID

8.2代码

主程序部分主要是读取 STM32F10x 系列微控制器的唯一设备标识符(UID)并通过 OLED 显示。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
//#include "OLED_Font.h"int main(void){OLED_Init();OLED_ShowHexNum(1,8,*((__IO uint16_t *)(0x1FFFF7E0)),4);OLED_ShowString(2,1,"U_ID:");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/diannao/82736.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/82736.shtml

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

相关文章

PostgreSQL 序列(Sequence) 与 Oracle 序列对比

PostgreSQL 序列(Sequence) 与 Oracle 序列对比 PostgreSQL 和 Oracle 都提供了序列(Sequence)功能&#xff0c;但在实现细节和使用方式上存在一些重要差异。以下是两者的详细对比&#xff1a; 一 基本语法对比 1.1 创建序列 PostgreSQL: CREATE [ { TEMPORARY | TEMP } |…

12.2.2 allocator类

allocator类将分配内存空间、调用构造函数、调用析构函数、释放内存空间这4部分操作分开&#xff0c;全部交给程序员来执行&#xff0c;不像new和delete #include <iostream> #include <string>int main() {const int n 10;std::allocator<std::string> al…

Android 中 Handler (创建时)内存泄漏问题及解决方案

一、Handler 内存泄漏核心原理 真题 1&#xff1a;分析 Handler 内存泄漏场景 题目描述&#xff1a; 在 Activity 中使用非静态内部类 Handler 发送延迟消息&#xff0c;旋转屏幕后 Activity 无法释放&#xff0c;分析原因并给出解决方案。 内存泄漏链路分析&#xff1a; 引…

SSTI记录

SSTI(Server-Side Template Injection&#xff0c;服务器段模板注入) 当前使用的一些框架&#xff0c;如python的flask、php的tp、java的spring&#xff0c;都采用成熟的MVC模式&#xff0c;用户的输入会先进入到Controller控制器&#xff0c;然后根据请求的类型和请求的指令发…

探索边缘计算:赋能物联网的未来

摘要 随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;越来越多的设备接入网络&#xff0c;产生了海量的数据。传统的云计算模式在处理这些数据时面临着延迟高、带宽不足等问题&#xff0c;而边缘计算的出现为解决这些问题提供了新的思路。本文将深入探讨边缘…

tabs切换#

1、html <el-tabs v-model"tabValue" tab-change"handleTabClick"><el-tab-pane label"集群" name"1"></el-tab-pane><el-tab-pane label"节点" name"2"></el-tab-pane></el-ta…

JSON 实体属性映射的最佳实践

一、结构与命名规范 ‌保持字段命名一致性‌ JSON 字段名与实体属性名应遵循统一的命名规则&#xff08;如驼峰命名或下划线分隔&#xff09;&#xff0c;避免因大小写差异导致映射失败。 // 使用 JsonProperty 显式指定映射关系&#xff08;Jackson&#xff09; public class …

hiveserver2与beeline进行远程连接hive配置及遇到的问题

1、hiveserver2 参与用户模拟功能&#xff0c;因为开启后才能保证各用户之间的权限隔离。 1.1、配置 $HADOOP_HOME/etc/hadoop/core-site.xml <!--配置所有节点的root用户都可作为代理用户--> <property><name>hadoop.proxyuser.root.hosts</name>&…

硅基计划2.0 学习总结 壹 Java初阶

一、初见Java &#xff08;1&#xff09;Java简介 首先不得不承认Java是一门优秀的程序设计语言 其系列的计算机软件和跨平台体系包括国内的生态链完善是C/C语言难以弥补的 &#xff08;2&#xff09;Java SE 全称Java Standard Edition&#xff0c;是Java体系的基础 &am…

nRF5_SDK_17.1.0_ddde560之ble_app_uart_c 出错

Error #541: ARM::CMSIS:CORE:5.3.0 component is missing (previously found in pack ARM.CMSIS.5.6.0) Error #541: NordicSemiconductor::Device:Startup:8.40.3 component is missing (previously found in pack NordicSemiconductor.nRF_DeviceFamilyPack.8.40.3) 下载n…

基于大模型预测的多发性硬化综合诊疗方案研究报告大纲

目录 一、引言二、文献综述三、大模型预测系统构建四、术前预测与手术方案制定五、术中监测与决策支持六、术后护理与并发症预测七、麻醉方案智能优化八、统计分析与技术验证九、实验验证与证据支持十、健康教育与指导系统十一、结论与展望一、引言 (一)研究背景与意义 多发…

bootstrap自助(抽样)法

一&#xff0c;概念 一言以蔽之&#xff1a;从训练集中有放回的均匀抽样——》本质就是有放回抽样&#xff1b; 自助法&#xff08;bootstrap&#xff09;是一种通过从数据集中重复抽样来估计统计量分布的非参数方法。它可用于构建假设检验&#xff0c;当对参数模型的假设存在…

用1W字讲透数据预处理,数据增强

大家好&#xff01;我是我不是小upper~ 今天咱们来聊聊数据增强 —— 这个在机器学习领域堪称 “数据魔法” 的实用技术&#xff01; 在深度学习的世界里&#xff0c;数据就像模型的 “养分”。数据的质量和数量&#xff0c;直接决定了模型最终能达到的 “高度”。当数据不足时…

无人机空中物流优化:用 Python 打造高效配送模型

友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…

C++核心编程解析:模板、容器与异常处理全指南

文章目录 一、模板1.1 定义1.2 作用1.3 函数模版1.3.1 格式 1.4 类模版1.4.1 格式1.4.2 代码示例1.4.3 特性 二、容器2.1 概念2.2 容器特性2.3 分类2.4 向量vector2.4.1 特性2.4.2 初始化与操作2.4.3 插入删除 2.5 迭代器2.6 列表&#xff08;list&#xff09;2.6.1 遍历方式2.…

JWT的介绍与在Fastapi框架中的应用

什么是JWT JWT (JSON Web Token) 是一个开放标准 ( RFC 7519 )&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间安全地以 JSON 对象的形式传输信息。由于这些信息经过数字签名&#xff0c;因此可以被验证和信任。JWT 可以使用密钥&#xff08;采用HMAC算…

dfs第二次加训 详细题解 下

目录 B4158 [BCSP-X 2024 12 月小学高年级组] 质数补全 思路 B4279 [蓝桥杯青少年组国赛 2023] 数独填数、 思路 P5198 [USACO19JAN] Icy Perimeter S 思路 P5429 [USACO19OPEN] Fence Planning S 思路 P6111 [USACO18JAN] MooTube S 思路 P6207 [USACO06OCT] Cows …

配置Hadoop集群环境准备

&#xff08;一&#xff09;Hadoop的运行模式 一共有三种&#xff1a; 本地运行。伪分布式完全分布式 &#xff08;二&#xff09;Hadoop的完全分布式运行 要模拟这个功能&#xff0c;我们需要做好如下的准备。 1&#xff09;准备3台客户机&#xff08;关闭防火墙、静态IP、…

Python60日基础学习打卡D12【虫豸版】

退火算法 物理现象&#xff1a;退火现象指物体逐渐降温的物理现象&#xff0c;温度愈低&#xff0c;物体的能量状态会低&#xff1b;温度足够低后&#xff0c;液体开始冷凝与结晶&#xff0c;在结晶状态时&#xff0c;系统的能量状态最低。大自然在缓慢降温(即退火)时&#xf…

1.3.1 Linux音频框架alsa详细介绍

ALSA作为对旧OSS系统的替代方案&#xff0c;始于1998年。当时OSS还闭源商业化&#xff0c;因此社区开始开发开源的ALSA。经过多年的发展&#xff0c;ALSA成为Linux内核中音频架构的标准。 结构和架构 ALSA由以下几个主要部分组成&#xff1a; 内核模块&#xff1a; 这是ALSA的…