STM32补充——FLASH

目录

1.内部FLASH构成(F1)

2.FLASH读写过程(F1)

2.1内存的读取

2.2闪存的写入

2.3FLASH接口寄存器(写入 & 擦除相关)

3.FLASH相关HAL库函数简介(F1/F4/F7/H7)

4.编程实战

代码:


1.内部FLASH构成(F1)

闪存模块的子部分

作用

主存储器

用来存放代码和数据常数(如const类型到的数据)

信息块

分为两个部分:系统存储(启动程序代码)、选项字节(用户选择字节)

闪存存储器接口寄存器

用于控制闪存读写等,是整个闪存模块的控制结构

主存储器:地址范围为0x0800 0000~0x0807 FFFF,分为256页(代码中把页或扇区统称为扇区),每页2KB(小/中容量为1K)(F4/ F7/H7一个扇区为16K)。当BOOT0接地,系统将从0x0800 0000地址处开始读取代码(从主存储器启动)

信息块:
(1)系统存储大小为2KB,用来存储ST自带的启动程序,用来串口下载代码。
(2)选项字节大小为16B,一般用于设置内存的写保护、读保护当BOOT0接VCC,BOOT1接GND (串口下载程序) ,系统运行的就是这部分代码


2.FLASH读写过程(F1)

对FLASH的核心操作就是读和写。

FLASH的物理特性:只能写0,不能写1,写1靠擦除
 

2.1内存的读取

CPU运行速度比FLASH快得多,STM32F103的FLASH最快访问速度≤24MHz,CPU频率超过这个速度,得加入等待时间,否则读写FLASH可能出错,导致死机等情况。

频率范围

等待周期数(LATENCY)

 SYSCLK < 24MHz

0个等待周期

24MHz  SYSCLK ≤ 48MHz

1个等待周期

48MHz  SYSCLK ≤ 72MHz

2个等待周期

正确设置好等待周期后,从地址addr,读取数据(字节为8位,半字为16位,字为32位)

data = *(volatile uint8_t *)addr;		/* 读取一个字节数据 */
data = *(volatile uint16_t *)addr;		/* 读取一个半字数据 */
data = *(volatile uint32_t *)addr;		/* 读取一个字数据 */

 将addr强制转换为uintx_t指针,然后取该指针所指向地址的值,即可获得addr地址的数据。

注意: 在进行写或擦除操作时,不能进行代码或数据的读取操作。


2.2闪存的写入

闪存编程是由FPEC(闪存编程和擦除控制器)模块处理的。

写操作有四步:解锁、擦除、写数据、上锁:

  1. 解锁:将两个特定的解锁序列号(KEY1:0x45670123、KEY2:0xCDEF89AB)依次写入FLASH_KEYR
  2. 擦除:FLASH物理特性(只能写0,不能写1),所以写FLASH之前需要擦除,将要写入的区域变为0xFFFF。擦除操作分为:页擦除和批量擦除
  3. 写数据:擦除完成,可以向FLASH写数据,每次只能以16位方式写入
  4. 上锁:写入数据完成,需要设置FLASH_CR[LOCK]位1,重新上锁,以防数据不小心被修改。

 闪存的擦除:

闪存的写入:(注意是写半字

2.3FLASH接口寄存器(写入 & 擦除相关)

FLASH寄存器

作用

FLASH_ACR

用于使能/关闭加速功能(DCEN/ICEN/PRFTEN),且可根据fCPU控制FLASH访问时间(LATENCY)

FLASH_KEYR

用来解锁FLASH_CR,需依次写入特定序列(KEY1:0x45670123KEY2:0xCDEF89AB)

FLASH_SR

用来提供正在执行的编程和擦除操作的相关信息(BSY位指示FLASH操作正在进行)

FLASH_CR

用于配置和启动FLASH操作(LOCK/STRT/PSIZE/SNB/SER/PG

对于H7还有FLASH_CCR 清除与控制寄存器用于清除相关错误。 

 FLASH_CR各位:

  1. LOCK:指示FLASH_CR寄存器是否被锁住(1锁 0未锁)
  2. STRT:用于开始一次擦除操作(1开始)
  3. PSIZE:用于设置编程宽度(3.3V PSIZE为2)
  4. SNB:用于选择要擦除的扇区编号 SER:用于选择扇区擦除操作(页擦除置1)
  5. PG:用于选择编程操作,往FLASH写数据需置1



3.FLASH相关HAL库函数简介(F1/F4/F7/H7)

驱动函数

关联寄存器

功能描述

HAL_FLASH_Unlock(…)

FLASH_KEYR

用于解锁FLASH_CR的访问

HAL_FLASH_Lock(…)

FLASH_CR

用于锁定FLASH_CR的访问

HAL_FLASH_Program(…)

FLASH_CR

用于FLASH的写入

HAL_FLASHEx_Erase(…)

FLASH_CR/AR

用于大量擦除或擦除指定的闪存扇区

FLASH_WaitForLastOperation(…)

FLASH_SR

等待操作完成

FLASH相关结构体:FLASH_EraseInitTypeDef

F1: 
uint32_t    TypeErase         /* 擦除类型 */
uint32_t    Banks                /* 擦除的bank编号(整片擦除) */
uint32_t    PageAddress    /* 擦除页面地址 */

uint32_t    NbPages           /* 擦除的页面数 */

F4/F7/H7:
uint32_t    TypeErase         
uint32_t    Banks        
uint32_t     Sector    
uint32_t     NbSectors
uint32_t    VoltageRange    



4.编程实战

F103ZET6 stmflash_write思路:

每个扇区(页)是2KB,也就是2048个地址

写任何一个地址前,如果该地址的值并不是0xFF,需先擦除再写


  1. 根据w_addr,确定No.sector号以及w_addr在该sector的偏移
  2. 根据w_addr和length,确定写入的内容是否跨sector
  3. 确定好要操作的sector以及sector的地址范围
  4. 遍历要写的地址区域数据是否都是0xFF,如果都是不用擦除,否则需要先读出保存在buf后擦除
  5. 把该sector要操作的数据,也写到buf,最后一次性把buf写入到这个对应的sector即可

跨扇区:需要注意偏移(扇区地址 / 扇区中的偏移 / 写入数据的偏移 / 写地址偏移 / 写入长度) 


代码:

/*** @brief       从指定地址读取一个半字 (16位数据)* @param       faddr   : 读取地址 (此地址必须为2的倍数!!)* @retval      读取到的数据 (16位)*/
uint16_t stmflash_read_halfword(uint32_t faddr)
{return *(volatile uint16_t *)faddr;
}
/*** @brief       从指定地址开始读出指定长度的数据* @param       raddr : 起始地址* @param       pbuf  : 数据指针* @param       length: 要读取的半字(16位)数,即2个字节的整数倍* @retval      无*/
void stmflash_read(uint32_t raddr, uint16_t *pbuf, uint16_t length)
{uint16_t i;for (i = 0; i < length; i++){pbuf[i] = stmflash_read_halfword(raddr);    /* 读取2个字节 */raddr += 2; /* 偏移2个字节 */}
}
/*** @brief       不检查的写入这个函数的假设已经把原来的扇区擦除过再写入* @param       waddr   : 起始地址 (此地址必须为2的倍数!!,否则写入出错!)* @param       pbuf    : 数据指针* @param       length  : 要写入的 半字(16位)数* @retval      无*/
void stmflash_write_nocheck(uint32_t waddr, uint16_t *pbuf, uint16_t length)
{uint16_t i;for (i = 0; i < length; i++){HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, waddr, pbuf[i]);waddr += 2;     /* 指向下一个半字 */}
}
/*** @brief       在FLASH 指定位置, 写入指定长度的数据(自动擦除)*   @note      该函数往 STM32 内部 FLASH 指定位置写入指定长度的数据*              该函数会先检测要写入的扇区是否是空(全0XFFFF)的?, 如果*              不是, 则先擦除, 如果是, 则直接往扇区里面写入数据.*              数据长度不足扇区时,自动被回擦除前的数据* @param       waddr   : 起始地址 (此地址必须为2的倍数!!,否则写入出错!)* @param       pbuf    : 数据指针* @param       length  : 要写入的 半字(16位)数* @retval      无*/
uint16_t g_flashbuf[STM32_SECTOR_SIZE / 2]; /* 最多是2K字节 */
void stmflash_write(uint32_t waddr, uint16_t *pbuf, uint16_t length)
{uint32_t secpos;        /* 扇区地址 */uint16_t secoff;        /* 扇区内偏移地址(16位字计算) */uint16_t secremain;     /* 扇区内剩余地址(16位字计算) */uint16_t i;uint32_t offaddr;       /* 去掉0X08000000后的地址 */FLASH_EraseInitTypeDef flash_eraseop;uint32_t erase_addr;    /* 擦除错误,这个值为发生错误的扇区地址 */if (waddr < STM32_FLASH_BASE || (waddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE))){return;     /* 非法地址 */}HAL_FLASH_Unlock();     /* FLASH解锁 */offaddr = waddr - STM32_FLASH_BASE;             /* 实际偏移地址. */secpos = offaddr / STM32_SECTOR_SIZE;           /* 扇区地址  0~255 for STM32F103ZET6 */secoff = (offaddr % STM32_SECTOR_SIZE) / 2;     /* 在扇区内的偏移(2个字节为基本单位.) */secremain = STM32_SECTOR_SIZE / 2 - secoff;     /* 扇区剩余空间大小 */if (length <= secremain){secremain = length; /* 不大于该扇区范围 */}while (1){stmflash_read(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE, g_flashbuf, STM32_SECTOR_SIZE / 2); /* 读出整个扇区的内容 */for (i = 0; i < secremain; i++)                                                              /* 校验数据 */{if (g_flashbuf[secoff + i] != 0XFFFF){break;      /* 需要擦除 */}}if (i < secremain)  /* 需要擦除 */{ flash_eraseop.TypeErase = FLASH_TYPEERASE_PAGES;     /* 选择页擦除 */flash_eraseop.NbPages = 1;flash_eraseop.PageAddress = secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE;  /* 要擦除的扇区 */HAL_FLASHEx_Erase( &flash_eraseop, &erase_addr);for (i = 0; i < secremain; i++)         /* 复制 */{g_flashbuf[i + secoff] = pbuf[i];}stmflash_write_nocheck(secpos * STM32_SECTOR_SIZE + STM32_FLASH_BASE, g_flashbuf, STM32_SECTOR_SIZE / 2); /* 写入整个扇区 */}else{stmflash_write_nocheck(waddr, pbuf, secremain); /* 写已经擦除了的,直接写入扇区剩余区间. */}if (length == secremain){break; /* 写入结束了 */}else       /* 写入未结束 */{secpos++;               /* 扇区地址增1 */secoff = 0;             /* 偏移位置为0 */pbuf += secremain;      /* 指针偏移 */waddr += secremain * 2; /* 写地址偏移(16位数据地址,需要*2) */length -= secremain;    /* 字节(16位)数递减 */if (length > (STM32_SECTOR_SIZE / 2)){secremain = STM32_SECTOR_SIZE / 2; /* 下一个扇区还是写不完 */}else{secremain = length; /* 下一个扇区可以写完了 */}}}HAL_FLASH_Lock(); /* 上锁 */
}

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

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

相关文章

PyTorch使用教程(8)-一文了解torchvision

一、什么是torchvision torchvision提供了丰富的功能&#xff0c;主要包括数据集、模型、转换工具和实用方法四大模块。数据集模块内置了多种广泛使用的图像和视频数据集&#xff0c;如ImageNet、CIFAR-10、MNIST等&#xff0c;方便开发者进行训练和评估。模型模块封装了大量经…

python学opencv|读取图像(三十九 )阈值处理Otsu方法

【1】引言 前序学习了5种阈值处理方法&#xff0c;包括(反)阈值处理、(反)零值处理和截断处理&#xff0c;还学习了一种自适应处理方法&#xff0c;相关文章链接为&#xff1a; python学opencv|读取图像&#xff08;三十三&#xff09;阈值处理-灰度图像-CSDN博客 python学o…

(一)相机标定——四大坐标系的介绍、对应转换、畸变原理以及OpenCV完整代码实战(C++版)

一、四大坐标系介绍 1&#xff0c;世界坐标系 从这个世界&#xff08;world&#xff09;的视角来看物体 世界坐标系是3D空间坐标&#xff0c;每个点的位置用 ( X w , Y w , Z w ) (X_w,Y_w,Z_w) (Xw​,Yw​,Zw​)表示 2&#xff0c;相机坐标系 相机本身具有一个坐标系&…

从CRUD到高级功能:EF Core在.NET Core中全面应用(三)

目录 IQueryable使用 原生SQL使用 实体状态跟踪 全局查询筛选器 并发控制使用 IQueryable使用 在EFCore中IQueryable是一个接口用于表示可查询的集合&#xff0c;它继承自IEnumerable但具有一些关键的区别&#xff0c;使得它在处理数据库查询时非常有用&#xff0c;普通集…

STM32之CubeMX图形化工具开发介绍(十七)

STM32F407 系列文章 - STM32CubeMX&#xff08;十七&#xff09; 目录 前言 一、CubeMX 二、下载安装 1.下载 2.安装 3.图解步骤 三、用户界面 1.项目配置 2.项目生成 3.项目文件解释 4.新建工程 5.查看原工程 四、FAQ 总结 前言 STMCube源自意法半导体&#xf…

idea中远程调试中配置的参数说明

Ⅰ 远程调试中配置的端口号与服务本身端口号区别 一、远程调试中配置端口号的作用 在 IDEA 中进行远程调试时配置的端口号主要用于建立开发工具&#xff08;如 IDEA&#xff09;和远程服务之间的调试连接。当你启动远程调试时&#xff0c;IDEA 会监听这个配置的端口号&#xf…

gitlab使用多数据库

1. 说明 默认情况下&#xff0c;GitLab 使用一个单一的应用数据库&#xff0c;称为主数据库。为了扩展 GitLab&#xff0c;您可以将 GitLab 配置为使用多个应用数据库。 设置多个数据库后&#xff0c;GitLab 将使用第二个应用数据库用于 CI/CD 功能&#xff0c;称为 CI 数据库…

【博客之星2024】技术创作与成长的全景回顾与突破 —— “千里之行,始于足下“

《热爱生命》 汪国真 我不去想是否能够成功 既然选择了远方 便只顾风雨兼程 我不去想能否赢得爱情 既然钟情于玫瑰 就勇敢地吐露真诚 我不去想身后会不会袭来寒风冷雨 既然目标是地平线 留给世界的只能是背影 我不去想未来是平坦还是泥泞 只要热爱生命 一切&#xff0c;都在意料…

leetcode刷题记录(七十二)——146. LRU 缓存

&#xff08;一&#xff09;问题描述 146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09;146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类&#xff1a; * LRUCache(int capacity)…

两份PDF文档,如何比对差异,快速定位不同之处?

PDF文档比对是通过专门的工具或软件&#xff0c;自动检测两个PDF文件之间的差异&#xff0c;并以可视化的方式展示出来。这些差异可能包括文本内容的修改、图像的变化、表格数据的调整、格式的改变等。比对工具通常会标记出新增、删除或修改的部分&#xff0c;帮助用户快速定位…

TongESB7.1.0.0如何使用dockercompose运行镜像(by lqw)

文章目录 安装准备安装 安装准备 1.安装好docker和dockercompose&#xff1a; docker、docker-compose安装教程&#xff0c;很详细 2.上传好安装相关文件 安装 使用以下命令导入管理端镜像和运行时镜像 docker load -i tongesb_manage_7100.tar docker load -i tongesb_se…

Java基于SSM框架的社区团购系统小程序设计与实现(附源码,文档,部署)

Java基于SSM框架的社区团购系统小程序设计与实现 博主介绍&#xff1a;✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f4…

【Linux】gawk编辑器二

一、变量 gawk编程语言支持两种变量&#xff1a;内建变量和自定义变量。 1、内建变量 gawk使用内建变量来引用一些特殊的功能。 字段和记录分隔符变量 数据字段变量 此变量允许使用美元符号&#xff08;$&#xff09;和字段在记录中的位置值来引用对应的字段。要引用记录…

【Linux】Linux入门(三)权限

目录 前提权限概念whoami指令 Linux权限管理文件访问者的分类&#xff08;人&#xff09;file指令权限信息权限的表示方法 chmod指令 更改权限chown指令 修改文件&#xff0c;文件夹所属用户和用户组 权限掩码umask&#xff08;权限掩码&#xff09; 粘滞位 前提 请先看下面这…

Low-Level 大一统:如何使用Diffusion Models完成视频超分、去雨、去雾、降噪等所有Low-Level 任务?

Diffusion Models专栏文章汇总:入门与实战 前言:视频在传输过程中常常因为各种因素(如恶劣天气、噪声、压缩和传感器分辨率限制)而出现质量下降,这会严重影响计算机视觉任务(如目标检测和视频监控)的性能。现有的视频修复方法虽然取得了一些进展,但通常只能针对特定的退…

生产环境中常用的设计模式

生产环境中常用的设计模式 设计模式目的使用场景示例单例模式保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点- 日志记录器- 配置管理器工厂方法模式定义一个创建对象的接口&#xff0c;让子类决定实例化哪个类- 各种工厂类&#xff08;如视频游戏工厂模式创…

点云目标检测训练数据预处理---平面拟合与坐标转换(python实现)

在做centerpoint训练之前&#xff0c;需要先对点云数据进行标注&#xff0c;然后制作kittti数据集。不用nuScenes或者waymo数据集的理由也很简单&#xff0c;因为麻烦&#xff0c;没有kitti数据集直观。 kitti数据集的格式如下&#xff0c;可以看到数据集中只有航向角&#xff…

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用 1. 建议按文章顺序从头看是看 第一篇&#xff1a;一文大白话讲清楚啥是个webpack第二篇&#xff1a;一文大白话讲清楚webpack基本使用——1——完成webpack的初步构建然后看本篇&#xff0c;Loader的配置…

Python基于OpenCV和PyQt5的人脸识别上课签到系统【附源码】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

2024年第十五届蓝桥杯青少组国赛(c++)真题—快速分解质因数

快速分解质因数 完整题目和在线测评可点击下方链接前往&#xff1a; 快速分解质因数_C_少儿编程题库学习中心-嗨信奥https://www.hixinao.com/tiku/cpp/show-3781.htmlhttps://www.hixinao.com/tiku/cpp/show-3781.html 若如其他赛事真题可自行前往题库中心查找&#xff0c;题…