STM32内部flash闪存的总结

最近在做无人船和机巢远程在线升级的项目,牵扯到flash的操作,特此记录,便于以后查找。IMU也用到过,当时没记录

具体细节看
E:\Documets\AY\a-project\IMU\IMU16500\S0IMU v3.3 study\User\Driver\source eeprom.c

E:\Documets\AY\a-project\bootloader\Nest_Fdr_bootload_V8 - study\User\App iap_flash.c

参考文章:https://blog.csdn.net/jingling122/article/details/100898806
https://blog.csdn.net/m0_58168670/article/details/130599477
在这里插入图片描述

分类: 只读存储器(ROM) 只写存储器(RAM)

在这里插入图片描述
在这里插入图片描述

嵌入式 Flash:(以STM32f407为例)

内存容量: stmf407内存512k

Flash 具有以下主要特性:

● 对于 STM32F40x 和 STM32F41x,容量高达 1 MB;对于 STM32F42x 和 STM32F43x,
容量高达 2 MB
● 128 位宽数据读取
● 字节、半字、字和双字数据写入
● 某个扇区擦除与全部擦除
● 存储器组织结构
● 低功耗模式(有关详细信息,请参见参考手册的“电源控制 (PWR)”部分)

Flash 结构:
— 主存储器块,分为 4 个 16 KB 扇区、1 个 64 KB 扇区和 7 个 128 KB 扇区
— 系统存储器,器件在系统存储器自举模式下从该存储器启动
— 512 字节 OTP(一次性可编程),用于存储用户数据
OTP 区域还有 16 个额外字节,用于锁定对应的 OTP 数据块。
— 选项字节,用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或
停止模式下的复位。

在这里插入图片描述
注意:我们的f407只有3个128kb的沙扇区,对扇区进行访问或者擦除的时候需要计算出其实地址和结束地址,用户下载数据时候,是从起始地址下载进去的;
在这里插入图片描述

注意:
          用户在存储自定义的数据时候,尽量从后面开始存储数据;避免对用户数据进行干扰

内部FLASH使用方法:

1.flash解锁–>2.flash擦除–>3.flash写入–>4.flash上锁–>5.flash读取
在这里插入图片描述

第一步:Flash 控制寄存器解锁:

原因:复位后,Flash 控制寄存器 (FLASH_CR) 不允许执行写操作,以防因电气干扰等原因出现对Flash 的意外操作。
寄存器的解锁顺序如下:

  1. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY1 = 0x45670123
  2. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY2 = 0xCDEF89AB

注意:如果顺序出现错误,将返回总线错误并锁定 FLASH_CR 寄存器,直到下一次复位
在这里插入图片描述

具体步骤:

在这里插入图片描述

第二步、擦除:

擦除扇区之前需要设计编程/擦除并行位数,决定了写入的时间,Flash 擦除操作可针对扇区或整个 Flash(批量擦除)执行。执行批量擦除时,不会影响OTP 扇区或配置扇区。

扇区擦除的具体步骤如下:

  1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作
  2. 在 FLASH_CR 寄存器中,将 SER 位置 1,并从主存储块的 12 个 (STM32F405xx/07xx
    和 STM32F415xx/17xx) 或 24 个 (STM32F42xxx 和 STM32F43xxx) 扇区中选择要擦除
    的扇区 (SNB) 需要指定扇区号(0~7),通过扇区地址计算,本芯(STM32F407)片只有7个扇区
  3. 将 FLASH_CR 寄存器中的 STRT 位置 1开始擦除扇区
  4. 等待 BSY 位清零 等待擦除完成
    在这里插入图片描述

通过扇区地址判断扇区号的自定义函数:
//获取flash的扇区号 通过扇区地址进行获取

uint32_t GetSector(uint32_t Address) { uint32_t sector = 0;
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0)) {
sector = FLASH_Sector_0; } else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1)) {
sector = FLASH_Sector_1; } else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2)) {
sector = FLASH_Sector_2; } else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3)) {
sector = FLASH_Sector_3; } else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4)) {
sector = FLASH_Sector_4; } else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5)) {
sector = FLASH_Sector_5; } else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6)) {
sector = FLASH_Sector_6; } else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7)) {
sector = FLASH_Sector_7; } else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8)) {
sector = FLASH_Sector_8; } else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9)) {
sector = FLASH_Sector_9; } else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10)) {
sector = FLASH_Sector_10; }
else/(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))/ {
sector = FLASH_Sector_11; }
return sector; //把计算出来的扇区号返回 }
在这里插入图片描述

调用这个函数
if( ==FLASH_EraseSector( FLASH_Sector_10, VoltageRange_3 ==) != FLASH_COMPLETE )

第三/四步:flash写入flash上锁:

可通过软件将 FLASH_CR 寄存器中的 LOCK 位置为 1 来锁定 FLASH_CR 寄存器。

具体步骤:
在这里插入图片描述

第五步:flash读取

具体步骤:
在这里插入图片描述

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

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

相关文章

蓝桥杯每日一题2023.10.22

题目描述 灵能传输 - 蓝桥云课 (lanqiao.cn) 题目分析 发现每一次的灵能传输都是对前缀和s[i - 1]和s[i]的一次交换 故为求max(s[i], s[i - 1])的最小值&#xff08;发现当s单调时可以成立&#xff09; 由于s[0]和s[n]的位置不变&#xff0c;但是s[0]和s[n]不一定是最大值或…

怎么写一个可以鼠标控制旋转的div?

说在前面 鼠标控制元素旋转在现在也是一个很常见的功能&#xff0c;让我们从实现div元素的旋转控制开始来了解元素旋转的具体原理和实现方法吧。 效果展示 体验地址 https://code.juejin.cn/pen/7290719197439459386 实现步骤 画一个div 首先我们需要先画一个div&#xff0…

模板再认识

在前面的文章中我写了关于模板的一些简单的认识&#xff0c;现在我们来再次认识模板文章目录 1.非类型模板参数2.模板特化1). 模板特化的写法2). 类模板特化3). 函数模板特化4). 模板全/偏特化 3.模板分离编译 1.非类型模板参数 在模板中还有一种是非类型的模板参数。我们代码…

人工智能(6):机器学习基础环境安装与使用

1 库的安装 整个机器学习基础阶段会用到Matplotlib、Numpy、Pandas等库&#xff0c;为了统一版本号在环境中使用&#xff0c;将所有的库及其版本放到了文件requirements.txt当中&#xff0c;然后统一安装 新建一个用于人工智能环境的虚拟环境 mkvirtualenv ai matplotlib3.8…

DALL·E 3:OpenAI的革命性图像生成模型与ChatGPT的融合

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Unity⭐️Win和Mac安卓打包环境配置

文章目录 🟥 配置Android SDK1️⃣ 配置 SDK Platforms2️⃣ 配置 SDK Tools🎁 Android SDK Build-Tools🎁 Android SDK Command-line Tools(latest)🎁 Android SDK Tools(Obsolete)🟧 配置NDK🟩 配置JDK前情提示: 此方法适用于Windows/Mac 在配置时注意开启 🪜 …

ubuntu安装Anaconda

下载 Anaconda 进入 Ubuntu&#xff0c;自己新建下载路径&#xff0c;输入以下命令开始下载 注意&#xff0c;如果不是 x86_64&#xff0c;需要去镜像看对应的版本&#xff08;https://mirrors.bfsu.edu.cn/anaconda/archive/?CM&OA&#xff09; wget https://mirrors.…

蓝桥杯中级题目之组合(c++)

系列文章目录 数位递增数_睡觉觉觉得的博客-CSDN博客拉线开关。_睡觉觉觉得的博客-CSDN博客蓝桥杯中级题目之数字组合&#xff08;c&#xff09;_睡觉觉觉得的博客-CSDN博客 文章目录 系列文章目录前言一、个人名片二、描述三、输入输出以及代码示例1.输入2.输出3.代码示例 总…

怎么从A和B仓库执行分别fetch操作?

目录 1.问题2.描述3.解决问题 1.问题 我希望从A仓库拉代码后推送到B仓库&#xff0c;结果A仓库代码新增分支后 在执行fetch时默认仓库地址为B仓库&#xff0c;导致fetch失败。 2.描述 在实际项目开发中我们可能会出现需要将同一个服务的代码推送到不同的代码仓库&#xff0c…

【C++】C++11新特性之右值引用与移动语义

文章目录 一、左值与左值引用二、右值与右值引用三、 左值引用与右值引用比较四、右值引用使用场景和意义1.左值引用的短板2.移动构造和移动赋值3.STL中右值引用的使用 五、万能引用与完美转发1.万能引用2.完美转发 一、左值与左值引用 在C11之前&#xff0c;我们把数据分为常…

开源博客项目Blog .NET Core源码学习(5:mapster使用浅析)

开源博客项目Blog使用mapster框架映射对象&#xff0c;主要是在数据库表对象及前端数据对象之间进行映射&#xff0c;本文学习并记录项目中mapster的使用方式。   App.Hosting项目的program文件中调用builder.Services.AddMapper函数进行对象模型自动映射&#xff0c;而该函数…

【C++】:类和对象(中)之拷贝构造函数+赋值运算符重载

拷贝构造函数 概念 在现实生活中&#xff0c;可能存在一个与你一样的自己&#xff0c;我们称其为双胞胎 那在创建对象时&#xff0c;可否创建一个与已存在对象一某一样的新对象呢&#xff1f; 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用…