【STM32】读写内部Flash初步使用

基于stm32f103,作为个人学习记录使用

STM32 芯片内部有一个 FLASH 存储器,它主要用于存储代码,在紧急状态下常常会使用内部 FLASH 存储关键记录;
在这里插入图片描述

内部 FLASH 的构成

STM32 的内部 FLASH 包含主存储器系统存储器以及选项字节区域

大容量产品内部 FLASH 的构成(摘自《STM32F10x 闪存编程参考手册》
在这里插入图片描述

主存储器

一般我们说 STM32 内部 FLASH 的时候,都是指这个主存储器区域,它是存储用户应用程序的空间,芯片型号说明中的 256K FLASH、512K FLASH 都是指这个区域的大小。

主存储器分为 256 页,每页大小为 2KB,共 512KB。这个分页的概念,实质就是FLASH 存储器的扇区,与其它 FLASH 一样,在写入数据前,要先按页(扇区)擦除

不同容量的芯片,Flash的主存储器的页数量、页大小均有不同

系统存储区

系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、USB 以及 CAN 等 ISP 烧录功能。

选项字节

选项字节用于配置 FLASH 的读写保护、待机/停机复位、软件/硬件看门狗等功能,这部分共 16 字节。可以通过修改 FLASH 的选项控制寄存器修改。

查看keil工程的空间分布,确定空余空间

内部 FLASH 本身存储有程序数据,若不是有意删除某段程序代码,一般不应修改程序空间的内容。所以在使用内部 FLASH 存储其它数据前需要了解哪一些空间已经写入了程序代码,存储了程序代码的扇区都不应作任何修改。

通过.map文件,可以了解程序存储到了哪些区域。
打开方式
打开 map 文件后,查看文件最后部分的区域,可以看到一段以“Memory Map of the image”开头的记录。
在这里插入图片描述
这一段是某工程的 ROM 存储器分布映像,在 STM32芯片中,ROM 区域的内容就是指存储到内部 FLASH 的代码

1. 计算程序 ROM 的加载与执行空间

例子中
Load Region LR_ROM1:程序的加载空间 :Base 0x800 0000,Size:0x0000 17a8
Execution Region ER_IROM1:程序的执行空间: Base 0x0800 0000,Size:0x0000 177c

在芯片刚上电运行时,会加载程序及数据,例如它会从程序的存储区域加载到程序的执行区域,还把一些已初始化的全局变量从 ROM 复制到 RAM 空间,以便程序运行时可以修改变量的内容。加载完成后,程序开始从执行区域开始执行。

在上面 map 文件的描述中

加载及执行空间的基地址 (Base)都是0x08000000,它正好是 STM32 内部 FLASH 的首地址,也是 STM32 的程序存储空间就直接是执行空间;
它们的大小(Size)分别为 0x000017a8 及 0x0000177c,执行空间的 ROM 比较小的原因就是因为部分 RW-data 类型的变量被拷贝到 RAM 空间了;
拷贝RW到RAM中

最大空间(Max):0x00080000,即 512K 字节,此款STM32内部 FLASH 的最大空间。

用大的那个

计算程序占用的空间时,需要使用加载区域的大小进行计算,本例子中应用程序使用的内部 FLASH 是从 0x08000000 至(0x08000000+0x000017a8)地址的空间区域。

2. ROM 空间分布表

在加载及执行空间总体描述之后,紧接着一个ROM详细地址分布表,它列出了工程中的各个段(如函数、常量数据)所在的地址 Base Addr 及占用的空间 Size。在这里插入图片描述
Type 说明了该段的类型;
CODE 表示代码;
DATA 表示数据;
PAD 表示段之间的填充区域,它是无效的内容,PAD 区域往往是为了解决地址对齐的问题。
在这里插入图片描述
观察表中的最后一项,它的基地址是 0x0800175c,大小为 0x00000020,可知它占用的最高的地址空间为 0x0800177c,跟执行区域的最高地址 0x0000177c 一样,但它们比加载区域说明中的最高地址 0x80017a8 要小,所以我们以加载区域的大小为准。

所以这边一共使用了4k不到的空间,那么从第三页开始就可以作为其他功用了。

对内部 FLASH 的写入的一般过程

1.解锁

由于内部 FLASH 空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给控制寄存器 FLASH_CR 上锁,这个时候不允许设置FLASH 的控制寄存器,不能修改 FLASH 中的内容。
所以对 FLASH 写入数据前,需要先给它解锁。解锁的操作步骤如下:
(1) 往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 FPEC 键寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB

#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)//对 FLASH 控制寄存器解锁,使能访问
void FLASH_Unlock(void){if ((FLASH->CR & FLASH_CR_LOCK) != RESET) {/* 写入确认验证码 */FLASH->KEYR = FLASH_KEY1;FLASH->KEYR = FLASH_KEY2;}}

顺带一提,给flash上锁的方法

void FLASH_Lock(void)
{FLASH->CR |= FLASH_CR_LOCK;/* 设置 FLASH 寄存器的 LOCK 位 */
}

2. 页擦除

在写入新的数据前,需要先擦除存储区域,STM32 提供了页(扇区)擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
页擦除的过程:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活页擦除寄存器位 PER ”置 1;
(3) 用 FLASH_AR 寄存器选择要擦除的页;
(4) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(5) 等待 BSY 位被清零时,表示擦除完成。

/**
* @brief 擦除指定的页
* @param Page_Address: 要擦除的页地址.
* @retval FLASH Status:
可能的返回值: FLASH_BUSY, FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{FLASH_Status status = FLASH_COMPLETE;/* 检查参数 */assert_param(IS_FLASH_ADDRESS(Page_Address));/*...此处省略 XL 超大容量芯片的控制部分*//* 等待上一次操作完成 */status = FLASH_WaitForLastOperation(EraseTimeout);if (status == FLASH_COMPLETE) {/* 若上次操作完成,则开始页擦除 */FLASH->CR|= CR_PER_Set;FLASH->AR = Page_Address;FLASH->CR|= CR_STRT_Set;/* 等待操作完成 */status = FLASH_WaitForLastOperation(EraseTimeout);/* 复位 PER 位 */FLASH->CR &= CR_PER_Reset;}return status; /* 返回擦除结果 */
}

3. 写入数据

擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 向指定的 FLASH 存储器地址执行数据写入操作,每次只能以 16 位的方式写入;
(4) 等待 BSY 位被清零时,表示写入完成。

/**
* @brief 向指定的地址写入一个字的数据(32 位)
* @param Address: 要写入的地址
* @param Data: 要写入的数据
* @retval FLASH Status:
可能的返回值: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data){FLASH_Status status = FLASH_COMPLETE;__IO uint32_t tmp = 0;/* 检查参数 */assert_param(IS_FLASH_ADDRESS(Address));/*...此处省略 XL 超大容量芯片的控制部分*//* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(ProgramTimeout);if (status == FLASH_COMPLETE) {/* 若上次操作完成,则开始页入低 16 位的数据(输入参数的第 1 部分) */FLASH->CR |= CR_PG_Set;*(__IO uint16_t*)Address = (uint16_t)Data;/* 等待上一次操作完成 */status = FLASH_WaitForLastOperation(ProgramTimeout);if (status == FLASH_COMPLETE) {/* 若上次操作完成,则开始页入高 16 位的数据(输入参数的第 2 部分) */tmp = Address + 2;*(__IO uint16_t*) tmp = Data >> 16;/* 等待操作完成 */status = FLASH_WaitForLastOperation(ProgramTimeout);/* 复位 PG 位 */FLASH->CR &= CR_PG_Reset;} else {/* 复位 PG 位 */FLASH->CR &= CR_PG_Reset;}}return status; /* 返回写入结果 */}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Unity下tga和png格式图片打包成AB包大小和加载速度测试

测试素材 测试素材,一张tga格式,一张png格式,他们的图像尺寸一样都是8K图。 两张图在AssetBundles里显示 Tga格式的图明显大很多,我们打包成ab包看看。 在PC 打包后看,明显大小一样,我们进行ab包加载&am…

文心一言 VS 讯飞星火 VS chatgpt (101)-- 算法导论9.3 7题

七、用go语言,设计一个 O(n)时间的算法,对于一个给定的包含n个互异元素的集合 S 和一个正整数k≤n,该算法能够确定 S 中最接近中位数的k个元素。 文心一言: 要设计一个 O(n) 时间的算法来找到集合 S 中最接近中位数的 k 个元素&…

idea创建同级项目-纠结是SB

idea创建同级项目-纠结是SB 创建方法:

从C语言到C++:C++入门知识(1)

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关C语言的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数…

Linux:进程概念的引入和理解

文章目录 进程的初步理解进程的实质理解查看进程 前面对操作系统有了一个基础的认知,从中得出的最重要的一个思想是,在认识一个新事物前要先描述,再组织,有了这样的思想也可以用于学习进程的概念 进程的初步理解 有了前面的思想…

学习路之PHP--lumen安装配置

一、下载lumen源码 composer create-project --prefer-dist laravel/lumen blog 安装lumen-generator composer require flipbox/lumen-generator 二、配置 bootstrap\app.php 97行 $app->register(Flipbox\LumenGenerator\LumenGeneratorServiceProvider::class);三、生成…

VS CODE中的筛选器如何打开?

最近更新了vscode1.82版本,发现在git管理界面有一个“筛选器”功能,十分好用,后来关掉了,找了好久都没有找到办法打开这个筛选器功能,今天无意中不知道按到了哪个快捷键,打开了,就是下图这个&am…

buuctf-[网鼎杯 2020 朱雀组]phpweb

1.打开网站,吓我一跳 2.查看源代码,主要看到timezone,然后这个页面是五秒就会刷新一次 一开始去搜了这个,但是没什么用 3.使用bp抓包 会发现有两个参数,应该是用func来执行p 4.修改func和p file_get_contents&#…

全新UI基于Thinkphp的最新自助打印系统/云打印小程序源码/附教程

这是一款全新的基于Thinkphp的最新自助打印系统,最新UI界面设计的云打印小程序源码,带有简单的教程。 下载地址:https://bbs.csdn.net/topics/617324130

3分钟,免费制作一个炫酷实用的数据可视化大屏!

在当前大数据时代背景下,数据已成为在工业革命中如同煤炭、石油一般宝贵的资源。但是由于数据越来越庞大、越来越复杂,导致数据的可读性也越来越低。因此,对数据可视化的需求也越来越高,需要解决的问题也越来越复杂,而…

进程的内存映像

组成部分 代码段:即程序的二进制代码,只读,可被多个进程共享数据段:包括全局变量和静态变量进程控制块PCB:在系统区(内核区),操作系统通过PCB来控制和管理进程堆:用来存放…

Docker部署ActiveMQ消息中间件

1、准备工作 docker pull webcenter/activemq:5.14.3 Pwd"/data/software/activemq" mkdir ${Pwd}/data -p2、运行容器 docker run -d --name activemq \-p 61616:61616 \-p 8161:8161 \-v ${Pwd}/data:/opt/activemq/data \-v /etc/localtime:/etc/localtime \--r…

4+机器学习+实验验证

今天给同学们分享一篇4机器学习实验验证的生信文章“Identification and Analysis of Neutrophil Extracellular Trap-Related Genes in Osteoarthritis by Bioinformatics and Experimental Verification”,这篇文章于2023年8月31日发表在 J Inflamm Res 期刊上&am…

HTMl案例二:注册页面

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>综合案例-注册页面</title> </head><…

网络编程

一、什么是网络编程 二、基本的通信架构 三、网络通信的三要素 1.IP地址 1.IPv4&#xff0c;IPv6 2.IP域名 3.公网IP &#xff0c;内网IP&#xff0c;本机IP 4.InetAddress import java.net.InetAddress;public class InetAddressTest {public static void main(String[] args)…

Hadoop、Spark、Storm、Flink区别及选择

hadoop、spark、storm、flink如何选择 hadoop和spark是更偏向于对大量离线数据进行批量计算&#xff0c;提高计算速度storm和flink适用于实时在线数据&#xff0c;即针对源源不断产生的数据进行实时处理。至于storm和flink之间的区别在于flink的实时性和吞吐量等要比storm高。…

Java中的泛型

一. 泛型简介 泛型&#xff0c;即“参数化类型”。 作为Java中常用且重要的一个概念&#xff0c;泛型帮我们实现了代码重用&#xff0c;也保证了类型安全。但关于它的详细内容&#xff0c;目前很多同学还不清楚&#xff0c;所以接下来就带各位来学习这个重要的知识点。 背景 …

利用fiddler正向代理前端请求到本地后端

前景&#xff1a;在实际开发测试环境中&#xff0c;&#xff08;前后端均已上线到测试服务器或前端以上线而后端还在开发中)。在测试过程中&#xff08;前端页面点击&#xff0c;功能测试&#xff09;发现了bug或异常点。 正常排查问题可能是先利用浏览器检查工具查看接口的返回…

flv怎么转换成mp4格式?准备3个方法给大家

flv怎么转换成mp4格式&#xff1f;FLV是一种流行的视频文件格式&#xff0c;最初由Adobe公司开发&#xff0c;用于在Web上播放和传输视频内容。FLV格式以其较小的文件大小和较高的压缩比而闻名&#xff0c;并广泛应用于在线视频分享平台、流媒体服务和网络广告等领域。能够提供…

驱动开发---基于gpio子系统编写LED灯的驱动

一、GPIO子系统相关API 1.解析GPIO相关的设备树节点 struct device_node *of_find_node_by_path(const char *path) 功能&#xff1a;根据设备树节点路径解析设备树节点信息 参数&#xff1a; path&#xff1a;设备树所在的节点路径 /mynode0X12345678 返回值&#xff1a;成…