#stm32整理(一)flash读写

以这篇未开始我将进行stm32学习整理为期一个月左右完成stm32知识学习整理内容顺序没有一定之规写到哪想到哪想到哪写到哪,主要是扫除自己知识上的盲区完成一些基本外设操作。

以stm32f07为例子进行flash读写操作

stm32flash简介

参考资料正点原子和野火开发手册 stm32f4中文参考手册和datasheet

Flash 接口可管理 CPU 通过 **AHB I-Code(指令指令总线) 和 D-Code (数据总线)**对 Flash 进行的访问。该接口可针对 Flash 执行擦除和编程操作,并实施读写保护机制。Flash 接口通过指令预取和缓存机制加速
代码执行。
关于这两条总线先不细说参考链接 AHB I-Code(指令指令总线) 和 D-Code (数据总线)请参考 Cortex-M3 I-Code,D-Code,系统总线及其他总线接口

主要特性

● Flash 读操作
● Flash 编程/擦除操作
● 读/写保护
● I-Code 上的预取操作
● I-Code 上的 64 个缓存(128 位宽)
● D-Code 上的 8 个缓存(128 位宽)

结构框图

在这里插入图片描述

Flash 具有以下主要特性:
● 对于 STM32F40x 和 STM32F41x,容量高达 1 MB;对于 STM32F42x 和 STM32F43x,
容量高达 2 MB
● 128 位宽数据读取
字节、半字、字和双字数据写入
扇区擦除与全部擦除
● 存储器组织结构
Flash 结构如下:
— 主存储器块,分为 4 个 16 KB 扇区、1 个 64 KB 扇区和 7 个 128 KB 扇区
— 系统存储器,器件在系统存储器自举模式下从该存储器启动
— 512 字节 OTP(一次性可编程),用于存储用户数据
OTP 区域还有 16 个额外字节,用于锁定对应的 OTP 数据块。
— 选项字节,用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或
停止模式下的复位。
● 低功耗模式(有关详细信息,请参见参考手册的“电源控制 (PWR)”部分)

在这里插入图片描述

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

系统存储区
系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、USB 以及 CAN 等 ISP 烧录功能 ISP烧录就是,芯片通过某些方式进入芯片内部预置的ISP升级程序,开启升级功能,然后与外部通信,然后通过相关的协议,完成程序区的擦除,写入,校验和相关的配置等一些列操作的过程.

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

OTP介绍
OTP:one-time programmable,只允许一次编程,也就是只能从1写0,不能从0写1。这里可能有人要问,这不是flash的特性么?需要注意的是,flash是允许擦除的,是允许从0写1的。而OTP不允许擦除,就算在ICP烧录代码时,也不会丢。

3接口

在这里插入图片描述

4读写操作

执行任何 Flash 编程操作(擦除或编程)时,CPU 时钟频率 (HCLK) 不能低于 1 MHz。如果
在 Flash 操作期间发生器件复位,无法保证 Flash 中的内容。
在对 STM32F4xx 的 Flash 执行写入或擦除操作期间,任何读取 Flash 的尝试都会导致总线
阻塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能
从 Flash 中执行代码或数据获取操作。也就是说读写之间不能操作

4.1解锁

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

  1. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY1 = 0x45670123
  2. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY2 = 0xCDEF89AB
  3. 如果顺序出现错误,将返回总线错误并锁定 FLASH_CR 寄存器,直到下一次复位。
    也可通过软件将 FLASH_CR 寄存器中的 LOCK 位置为 1 来锁定 FLASH_CR 寄存器。

当 FLASH_SR 寄存器中的 BSY 位为 1 时,将不能在写模式下访问 FLASH_CR 寄存器。
BSY 位为 1 时,对该寄存器的任何写操作尝试都会导致 AHB 总线阻塞,直到 BSY 位清零。

4.2擦除/编程位数

通过 FLASH_CR 寄存器中的 PSIZE 字段配置并行位数。并行位数表示每次对 Flash 进行写
操作时将编程的字节数。PSIZE 受限于电源电压以及是否使用外部 VPP 电源。因此,在进行
任何编程/擦除操作前,必须在 FLASH_CR 寄存器中对其进行正确配置。
编程就是读写 擦除受外部电压影响
Flash 擦除操作只能针对扇区或整个 Flash(批量擦除)执行。擦除时间取决于 PSIZE 编程
值。有关擦除时间的详细信息,请参见器件数据手册的电气特性部分。
在这里插入图片描述
DW:64 W:32 HW:16 Byte:8位

写到这我想先写一个关于stm32程序存在了哪这涉及到了程序编译过程我先写这个但是排在第二篇吧!
#stm32整理(二)关于MDK的编译过程及文件类型全解

4.3擦除

Flash 擦除操作可针对扇区或整个 Flash(批量擦除)执行。执行批量擦除时,不会影响 OTP 扇区或配置扇区。
扇区擦除
扇区擦除的具体步骤如下:

  1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作
  2. 在 FLASH_CR 寄存器中,将 SER 位置 1,并从主存储块的 12 个 (STM32F405xx/07xx
    和 STM32F415xx/17xx) 或 24 个 (STM32F42xxx 和 STM32F43xxx) 扇区中选择要擦除
    的扇区 (SNB)
  3. 将 FLASH_CR 寄存器中的 STRT 位置 1
  4. 等待 BSY 位清零
    批量擦除
    要执行批量擦除,建议采用以下步骤:
  5. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作
  6. 将 FLASH_CR 寄存器中的 MER 位置 1(STM32F405xx/07xx 和 STM32F415xx/17xx
    器件)
  7. 将 FLASH_CR 寄存器中的 MER 和 MER1 位置 1(STM32F42xxx 和 STM32F43xxx
    器件)
    . 将 FLASH_CR 寄存器中的 STRT 位置 1
  8. 等待 BSY 位清零
    注意: 如果 FLASH_CR 寄存器中的 MERx 位和 SER 位均置为 1,则无法执行扇区擦除和批量擦除。

这里写一段flash 扇区删除的代码

Flash 状态寄存器 (FLASH_SR)
Flash status register
Flash 状态寄存器提供正在执行的编程和擦除操作的相关信息。
偏移地址:0x0C
复位值:0x0000 0000
访问:无等待周期,按字、半字和字节访问
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
用于 STM32F405xx/07xx 和 STM32F415xx/17xx 的 Flash 控制寄存器
(FLASH_CR)

Flash control register
Flash 控制寄存器用于配置和启动 Flash 操作。
偏移地址:0x10
复位值:0x8000 0000
访问:当前未执行任何 Flash 操作时无等待周期,按字、半字和字节访问。

注意FLASH的值擦完是FF写的时候是把1变0
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作 这相当于第一步
/*** @brief       得到FLASH的错误状态* @param       无* @retval      执行结果*   @arg       0   : 已完成*   @arg       其他 : 错误编号*/
static uint8_t stmflash_get_error_status(void)
{uint32_t res = 0;res = FLASH->SR;if (res & (1 << 16)) return 1;  /* BSY=1, 繁忙 */if (res & (1 << 7))  return 2;  /* PGSERR=1,编程序列错误 */if (res & (1 << 6))  return 3;  /* PGPERR=1,编程并行位数错误 */if (res & (1 << 5))  return 4;  /* PGAERR=1,编程对齐错误 */if (res & (1 << 4))  return 5;  /* WRPERR=1,写保护错误 */return 0;   /* 没有任何状态/操作完成. */
}
/*** @brief       等待操作完成* @param       time : 要延时的长短* @retval      执行结果*   @arg       0   : 已完成*   @arg       0XFF: 超时*   @arg       其他 : 错误编号*/
static uint8_t stmflash_wait_done(uint32_t time)
{uint8_t res;do{res = stmflash_get_error_status();  if (res != 1){break;      /* 非忙, 无需等待了, 直接退出 */}time--;} while (time);if (time == 0)res = 0XFF;   /* 超时 */return res;
}/*** @brief       获取某个地址所在的flash扇区* @param       faddr   : flash地址* @retval      0~11, 即addr所在的扇区*/
static uint8_t stmflash_get_flash_sector(uint32_t addr)
{if (addr < ADDR_FLASH_SECTOR_1)return 0;else if (addr < ADDR_FLASH_SECTOR_2)return 1;else if (addr < ADDR_FLASH_SECTOR_3)return 2;else if (addr < ADDR_FLASH_SECTOR_4)return 3;else if (addr < ADDR_FLASH_SECTOR_5)return 4;else if (addr < ADDR_FLASH_SECTOR_6)return 5;else if (addr < ADDR_FLASH_SECTOR_7)return 6;else if (addr < ADDR_FLASH_SECTOR_8)return 7;else if (addr < ADDR_FLASH_SECTOR_9)return 8;else if (addr < ADDR_FLASH_SECTOR_10)return 9;else if (addr < ADDR_FLASH_SECTOR_11)return 10;return 11;
}static uint8_t stmflash_erase_sector(uint32_t saddr)
{uint8_t res = 0;res = stmflash_wait_done(0XFFFFFFFF);   /* 等待上次操作结束 */ //1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作if (res == 0){FLASH->CR &= ~(3 << 8);             /* 清除PSIZE原来的设置 */ //默认8位编程FLASH->CR |= 2 << 8;                /* 设置为32bit宽,确保VCC=2.7~3.6V之间!! */FLASH->CR &= ~(0X1F << 3);          /* 清除原来的设置 */FLASH->CR |= saddr << 3;            /* 设置要擦除的扇区 */FLASH->CR |= 1 << 1;                /* 扇区擦除 */ // SER置1 激活扇区擦除FLASH->CR |= 1 << 16;               /* 开始擦除 */res = stmflash_wait_done(0XFFFFFFFF);   /* 等待操作结束 */ //位 16 STRT:启动 (Start) 该位置 1 后可触发擦除操作。//  **注意这里没有设置MER,MER是按块擦除这里是按扇区擦除**if (res != 1)                       /* 非忙 */{FLASH->CR &= ~(1 << 1);         /* 清除扇区擦除标志 */// SER:扇区擦除 (Sector Erase)}}return res;
}

4.4编程(写)

Flash 编程顺序如下:

  1. 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何主要 Flash 操作。
  2. 将 FLASH_CR 寄存器中的 PG 位置 1。
  3. 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作:
    — 并行位数为 x8 时按字节写入
    — 并行位数为 x16 时按半字写入
    — 并行位数为 x32 时按字写入
    — 并行位数为 x64 时按双字写入
  4. 等待 BSY 位清零

注意: 把 Flash 的单元从“1”写为“0”时,无需执行擦除操作即可进行连续写操作。把 Flash 的
单元从“0”写为“1”时,则需要执行 Flash 擦除操作。
如果同时发出擦除和编程操作请求,首先执行擦除操作。

这里放一段写代码

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
void Flash_Write(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite)
{uint8_t status = 0;uint32_t addrx =0;uint32_t endaddr=0;uint8_t sector;if(WriteAddr<STM32_FLASH_BASE||WriteAddr%2||WriteAddr>(STM32_FLASH_BASE+STM32_FLASH_SIZE))//判断地址是否符合这里我们需注意基地址和flash大小可以根据手册查{return;//return 语句是提前结束函数的唯一办法。return 后面可以跟一份数据,表示将这份数据返回到函数外面;return 后面也可以不跟任何数据,表示什么也不返回,仅仅用来结束函数。}FLASH_Unlock();//解锁之前介绍过 直接用库函数中的函数FLASH_DataCacheCmd(DISABLE);//关闭数据缓存,这里不关闭数据缓存擦除时可能会发生缓存不一致现象 这里我没验证相关可以参考 https://shequ.stmicroelectronics.cn/thread-621109-1-1.htmladdrx=WriteAddr;//开始地址endaddr=WriteAddr+NumToWrite*2;//结束地址sector=stmflash_get_flash_sector(addrx);//获取扇区if(addrx<0X1FFF0000)//地址0x1FFF 0000是系统存储器的地址{while(addrx<endaddr){if(Flash_ReadHalfWord(addrx)!=0XFFFF)//读到非零擦除{status = stmflash_erase_sector(sector);if(status)break;}else{addrx+=2;}}}if(status==0){status = stmflash_wait_done(0XFFFFF);//这一句其实没用while(WriteAddr<endaddr){if(stmflash_wait_done(0XFFFFF)==0)status=FLASH_ProgramHalfWord(WriteAddr,*pBuffer);//半字写入elsebreak;WriteAddr+=2;pBuffer++;}}   									//这里缺一点如果写入错误应该如何判断写入问题FLASH_DataCacheCmd(ENABLE);//使能数据缓冲FLASH_Lock();//上锁}

读函数

//读取指定地址的半字(16位数据)
//faddr:读地址
//返回值:对应数据.
static uint16_t Flash_ReadHalfWord(uint32_t faddr)
{return *(vu16 *)faddr;//(vu16 *)将32位地址强制转换为16为__IO uint16_t 16位地址 第二个*才是返回该地址所存储的值。
}

关于f1的和这个不一样先不写了先写到这里但是流程是差不多的。

1、这里注意我们在进行擦除和写入时操作的基本单元是sector 所以在进行操作时哪怕对某一个地址中的值进行修改需要先将扇区中的值读出来然后更改这个值再写进去,所以当数据量特别大的时候我们也需要一个特别大的全局buffer现将值读出来有点不实用,这里我想了一个思路还是要计算当前要写的字节在sector的大小然后把他给到一个临时buffer中然后修改临时buffer的值将buffer再写回sector中,但是同样存在临时buffer太大栈溢出导致硬件中断错误
2、注意这里我们写的数据没有超过该secotr的大小如果超过了那么就坏了,还要根据扇区大小不同判断剩余字节数

先写到这吧

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

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

相关文章

自动曝光算法(第二讲)

序言 第一章说了&#xff0c;自动曝光算法的目的&#xff1a;已知当前raw图亮度、当前曝光时间、当前增益和目标亮度&#xff0c;当环境光发生变化的时候&#xff0c;是通过控制增益、曝光时间和光圈使raw图的亮度&#xff0c;保持在目标亮度附近。本章想讲一下目标亮度的相关…

路由器基础(九):防火墙基础

防火墙 (Fire Wall) 是网络关联的重要设备&#xff0c;用于控制网络之间的通信。外部网络用户的访问必须先经过安全策略过滤&#xff0c;而内部网络用户对外部网络的访问则无须过滤。现在的防火墙还具有隔离网络、提供代理服务、流量控制等功能。 一、三种防火墙技术 常见的…

hadoop进程启停管理(看这一篇就足够了!)

一、一键启停脚本 Hadoop HDFS组件内置了HDFS集群的一键启停脚本 $HADOP_HOME/sbin/start-all.sh,一键启动HDFS集群 执行原理&#xff1a; 在执行此脚本的机器上&#xff0c;启动SecondaryNameNode 读取core-site.xml内容(fs.defaultFS项)&#xff0c;确认NameNode所在机器&…

【MySQL索引与优化篇】数据库的设计规范

数据库的设计规范 文章目录 数据库的设计规范1. 范式2. 键和相关属性的概念3. 第一范式4. 第二范式5. 第三范式6. 小结7. 反范式化7.1 概述7.2 反范式的新问题7.3 反范式适用场景 8. 巴斯范式9. 第四范式、第五范式和域键范式 1. 范式 在关系型数据库中&#xff0c;关于数据表…

【Docker】Linux路由连接两个不同网段namespace,连接namespace与主机

如果两个namespace处于不同的子网中&#xff0c;那么就不能通过bridge进行连接了&#xff0c;而是需要通过路由器进行三层转发。然而Linux并未像提供虚拟网桥一样也提供一个虚拟路由器设备&#xff0c;原因是Linux自身就具备有路由器功能。 路由器的工作原理是这样的&#xff…

Qt控件 UI设计 QPushbutton、QToolButton、QMenu

Qt控件 UI设计 QPushbutton、QToolButton、QMenu 个人设计QToolButton效果设计效果运行效果 Chapter1 Qt控件 UI设计 QPushbutton、QToolButton、QMenu1.QPushbutton和QToolButton的关联和区别&#xff1a;2.QMenu 可以配合QPushbutton做个下拉菜单3.点击按钮的功能&#xff0c…

k8s:endpoint

在 Kubernetes 中&#xff0c;Endpoint 是一种 API 对象&#xff0c;它用于表示集群内某个 Service 的具体网络地址。换句话说&#xff0c;它连接到一组由 Service 选择的 Pod&#xff0c;从而使它们能够提供服务。每个 Endpoint 对象都与相应的 Service 对象具有相同的名称&am…

【C语言初学者周冲刺计划】5.1C语言知识点小总结

目录 1知识点一&#xff1a; 2知识点二&#xff1a; 3知识点三&#xff1a; 4代码&#xff1a; 5总结&#xff1a; 1知识点一&#xff1a; 1 C语言中要求对变量作强制定义的主要理由是( )。 便于确定类型和分配空间 2 【单选题】若有定义&#xff1a;int m7; float x…

云安全-云原生k8s攻击点(8080,6443,10250未授权攻击点)

0x00 k8s简介 k8s&#xff08;Kubernetes&#xff09; 是容器管理平台&#xff0c;用来管理容器化的应用&#xff0c;提供快速的容器调度、弹性伸缩等诸多功能&#xff0c;可以理解为容器云&#xff0c;不涉及到业务层面的开发。只要你的应用可以实现容器化&#xff0c;就可以部…

Webpack搭建本地服务器

一、搭建webpack本地服务 1.为什么要搭建本地服务器&#xff1f; 目前我们开发的代码&#xff0c;为了运行需要有两个操作&#xff1a; 操作一&#xff1a;npm run build&#xff0c;编译相关的代码&#xff1b;操作二&#xff1a;通过live server或者直接通过浏览器&#x…

Leetcode刷题详解——反转链表

1. 题目链接&#xff1a;206. 反转链表 2. 题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1…

炫云客户端信用额度如何修改?

现在炫云新注册用户信用额度是100元&#xff0c;但是有人觉得信用额度太高了&#xff0c;想修改信用额度&#xff0c;不知道炫云的信用额度如何修改&#xff0c;今天就教大家如何修改炫云的信用额度。炫云的信用额度在炫云官网和客户端都可以修改。 我们先来看炫云官网如何修改…

【数据结构】归并排序 的递归实现与非递归实现

归并排序 前言一、归并排序递归实现&#xff08;1&#xff09;归并排序的核心思路&#xff08;2&#xff09;归并排序实现的核心步骤&#xff08;3&#xff09;归并排序码源详解&#xff08;4&#xff09;归并排序效率分析1&#xff09;时间复杂度 O&#xff08;N*logN&#xf…

matlab双目标定中基线物理长度获取

在MATLAB进行双目摄像机标定时,通常会获得相机的内参,其中包括像素单位的焦距(focal length)以及物理单位的基线长度(baseline)。对于应用中的深度估计和测量,基线长度的物理单位非常重要,因为它直接影响到深度信息的准确性。有时候,您可能只能获取像素单位的焦距和棋…

FPGA 如何 固化程序到 FLASH中

1、导出Hardware 2、导出bit文件 3、打开SDK 4、 点击Ok 5、创建工程 6、 输入工程名称&#xff1a;guhua 7、选择 Zynq FSBL 8、单击 guhua、然后点击 build 点击&#xff1a;build all 9、 右键之后&#xff0c;点击&#xff1a;Creat Boot Image 10、点击 Cr…

水库大坝可视化智能远程监管方案,助力安全监测智能巡检

一、背景需求 水库大坝作为防洪度汛的重要设施&#xff0c;其安全问题直接关系到人民群众的生命财产安全。因此&#xff0c;必须加强对大坝水库的安全管理&#xff0c;对水库除险加固和运行管护要消除存量隐患&#xff0c;实现常态化管理&#xff0c;同时要配套完善重点小型水…

Leetcode—485.最大连续1的个数【简单】

2023每日刷题&#xff08;十五&#xff09; Leetcode—485.最大连续1的个数 实现代码 int findMaxConsecutiveOnes(int* nums, int numsSize){int max 0;int i;int flag 0;int cnt 0;for(i 0; i < numsSize; i) {if(nums[i] 1) {if(flag 0) {flag 1;cnt 1;} else {…

ARM 版 OpenEuler 22.03 部署 KubeSphere v3.4.0 不完全指南续篇

作者&#xff1a;运维有术 前言 知识点 定级&#xff1a;入门级KubeKey 安装部署 ARM 版 KubeSphere 和 KubernetesARM 版 KubeSphere 和 Kubernetes 常见问题 实战服务器配置 (个人云上测试服务器) 主机名IPCPU内存系统盘数据盘用途ks-master-1172.16.33.1661650200KubeSp…

3D人像手办定制业务再掀热潮,这一次有怎样的革新?(方法篇)

最近&#xff0c;3D真人手办热潮再起&#xff0c;最出圈的一次当属亚运会的3D打印元宇宙体验舱里面各国运动员带火的真人手办定制项目。作为3D技术推广者&#xff0c;博雅仔也在后台接受了很多朋友的询问—— ◆ 技术已经成熟了吗&#xff1f; ◆ 个人定做3D真人手办市场价格…

百度百科怎么创建?百科创建需要注意哪些(一文看懂品牌/企业/人物百科创建)

随着互联网的不断发展&#xff0c;许多企业或品牌都选择创建百度百科作为一种很好的展示方式。百度百科可以被视为一张网络名片&#xff0c;拥有它能够提高人物、企业、品牌的知名度和影响力。那么人物百科、企业百科、品牌百科到底怎么创建呢&#xff1f; 大家创建百科前建议先…