当前位置: 首页 > news >正文

单片机FLASH深度解析和编程实践(上)

本篇文章主要针对单片机FLASH编程和FLASH基本原理进行学习分享。以STM32单片机作为实例进行编程实训。

关于FLASH操作的相关寄存器及编程,大家可以参考下一篇文章:

单片机FLASH深度解析和编程实践(下)-CSDN博客

目录

一、STM32编程方式

 二、闪存模块存储器组织(以STM32F767IGT为例)

 1、主存储器

2、系统存储器 

3、OPT区域 

4、选项字节 

 三、FLASH闪存操作

(一)、FLASH闪存的读取

注意 

(二)、FLASH闪存的编程(写)和擦除操作 

(三)、FLASH编程注意事项 

(四)、STM32的标准编程步骤

四、闪存擦除

(一)、扇区擦除的步骤 

(二)、批量擦除的步骤 

 五、FLASH中断

 六、结语


 

一、STM32编程方式

1在线编程(ICP,In-Circuit Programming):
通过JTAG/SWD协议或者系统加载程序(Bootloader)下载用户应用程序到微控制器中。


2在程序中编程(IAPIn Application Programming):

通过任何一种通信接口(如IO端口,USB, CAN,UART,I2C,SPI等)下载程序或者应用数据到存储器中。也就是说,STM32允许用户在应用程序中重新烧写闪存存储器中的内容。然而,IAP需要至少有一部分程序已经使用ICP方式烧到闪存存储器中(Bootloader).

 二、闪存模块存储器组织(以STM32F767IGT为例)

储器组织分为四个部分,分别是主存储器、系统存储器、OPT区域、选项字节。

 1、主存储器

该部分用来存放代码和数据常数(如const类型的数据)。它可以分为1个Bank或者2个Bank,可以通过选项字节的nDBANK位来设置,默认是1个bank,也就是单Bank模式。


在单Bank模式下,STM32F767的主存储器被分为8个扇区,前4个扇区为32KB大小,第五个扇区是128KB大小,剩下的3个扇区都是256KB大小,总共1M字节。


因为STM32F7的FLASH访问路径有两条:AXIM和ITCM,对应不同的地址映射,表中我们列出了这两条不同访问路径下的扇区地址范围。我们一般选择AXIM接目访问FLASH,其主存储器的起始地址就是ox08000000。


B0、B1都接GND的时候,就是从OX08000000开始运行代码的。

2、系统存储器 

这个主要用来存放STM32的bootloader代码,此代码是出厂的时候就固化在STM32里面了,专门来给主存储器下载代码的。当B0接V3.3,B1接GND的时候,从该存储器启动(即进入串口下载模式)。

3、OPT区域 

OTP区域,即一次性可编程区域,共1056字节,被划分为16个64字节的OTP 数据块和1个16字节的OTP锁定块。OTP数据块和锁定块均无法擦除。锁定块中包含16字节的 LOCKBi (0 <= i <= 15),用于锁定相应的OTP数据块(块0到15)。每个OTP数据块均可编程,除非相应的OTP锁定字节编程为0x00。锁定字节的值只能是0x0和0xFF,否则这些OTP字节无法正确使用。

4、选项字节 

用于配置读保护、BOR级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。  

闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。


在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。

 三、FLASH闪存操作

(一)、FLASH闪存的读取

STM32的FLASH读取是很简单的。例如,我们要从地址addr ,读取一个字(字节为8位,半字为16位,字为32位),可以通过如下的语句读取:

将addr强制转换为vu32指针,然后取该指针所指向的地址的值,即得到了addr地址的值。类似的,将上面的vu32改为vu16,即可读取指定地址的一个半字。相对FLASH读取来说,STM32 FLASH的写就复杂一点了,下面我们介绍STM32闪存的编程和擦除。

注意 

为了准确读取 Flash数据,必须根据CPU时钟 (HCLK)频率和器件电源电压在 Flash存取控制寄存器(FLASH ACR)中正确地设置等待周期数(LKTENCY)。Flash等待周期与CPU时钟频率之间的对应关系:

等待周期通过FLASHAC寄存器的LATENCY[3:0]四三个位设置。系统复位后,CPU时钟频率为内部16MRC振荡器,LATENCY默认是0,即1个等待周期。供电电压,我们一般是3.3V,所以,在我们设置216Mhz频率作为CPU时钟之前,必须先设置LATENCY为7,即8个等待周期,否则FLASH读写可能出错,导致死机。


正常工作时(216Mhz),虽然FLASH需要8个CPU等待周期,但是由于STM32F767具有自适应实时存储器加速器(ARTAccelerator),通过指令缓存存储器,预取指令,实现相当于0 FLASH等待的运行速度。

(二)、FLASH闪存的编程(写)和擦除操作 

在对 STM32的Flash执行写入或擦除操作期间,任何读取Flash的尝试都会导致总线阻塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从Flash中执行代码或数据获取操作。

 STM32的闪存编程由7个32位寄存器控制。

(三)、FLASH编程注意事项 

Step1:

STM32复位后,FLASH编程操作是被保护的,不能写入FLASH_CR寄存器;
通过写入特定的序列(0X45670123和OXCDEF89AB)到FLASH_KEYR寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关寄存器。FLASH_CR的解锁序列为:


1)写0X45670123 ( KEY1)到FLASH_ KEYR

2)写OXCDEF89AB(KEY2)到FLASH_KEYR


通过这两个步骤,即可解锁FLASH_CR,如果写入错误,那么FLASH_CR将被锁定,直到下次复位后才可以再次解锁。

Step2:

STM32闪存的编程位数可以通过FLASH_CR的PSIZE字段配置,PSIZE的设置必须和电源电压匹配,由于我的开发板用的电压是3.3V,所以PSIZE必须设置为10,即32位并行位数。擦除或者编程,都必须以32位为基础进行。

Step3:

STM32的FLASH在编程的时候,也必须要求其写入地址的FLASH是被擦除了的(也就是其值必须是0XFFFFFFFF ),否则无法写入。

(四)、STM32的标准编程步骤

按照以上四步操作,就可以完成一次FLASH编程。但是需要注意一下:

1、编程之前,必须确保要写入地址的FLASH已经擦除 ;

2、需要先解锁,否则不能操作FLASH;

3、编程操作对OPT区域也有效,方法一摸一样。

四、闪存擦除

我们在STM32的FLASH编程的时候,要先判断缩写地址是否被擦除了,所以,我们有必要再介绍-下STM32的闪存擦除,STM32的闪存擦除分为两种:
①扇区擦除

②整片擦除。

(一)、扇区擦除的步骤 

1、检查FLASH_CR的LOCK是否解锁,如果没有则先解锁

2、检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作
3、在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区(SNB)
4、将FLASH_CR寄存器中的STRT位置1,触发擦除操作

5、等待BSY位清零
经过以上五步,就可以擦除某个扇区!

(二)、批量擦除的步骤 

1、检查FLASH_SR寄存器中的BSY位,确保当前未执行任何FLASH操作
2、在FLASH_CR寄存器中,将MER位置1(F767/F407)

3、在FLASH_CR寄存器中,将MER和OMER1位置1(F429xx)

4、将FLASH_CR寄存器中的STRT位置1,触发擦除操作5等待BSY位清零
经过以上几个步骤,就可以批量擦除扇区。

 

 五、FLASH中断

1、如果将FLASH_CR寄存器中的操作结束中断使能位(EOPIE)置1,则在擦除或者编程操作结束时,即FLASH_SR寄存器中的繁忙位BSY清零时,将产生中断。此时FLASH_SR寄存器中的操作结束(EOP)位置1。
2、如果在请求编程,擦
除或读操作期间出现错误,则FLASH_SR寄存器中的以下错误标志位之一将置1:
PGAERR ,PGPERR ,ERSERR(编程错误标志)

WRPERR(保护错误标志)
这种情况下,FLASH_CR的
错误中断使能位(ERRIE)置1,并且如果FLASH_SR的操作错误位(OPERR)置1,则产生一个中断。
 

 六、结语

有关FLASH操作的相关知识就分享至此了,下一篇文章将会带大家深度了解FLASH相关的寄存器和寄存器的配置。

单片机FLASH深度解析和编程实践(下)-CSDN博客

相关文章:

  • PHP异世界云商系统开源源码
  • linux中tar归档与(zip,gzip,bzip格式)压缩和解压
  • Rust 语言的 for 循环用法
  • qt vs 编程 字符编码 程序从源码到编译到显示过程中存在的字符编码及隐藏的字符编码转换
  • Vue.js+SpringBoot开发天沐瑜伽馆管理系统
  • FFmpeg查看所有支持的编码/解码器/封装/解封装/媒体格式/滤镜
  • 耳机壳UV树脂制作私模定制耳塞需要哪些工具和材料呢?
  • 基于CNN多阶段图像超分+去噪(超级简单版)
  • 【NLP】如何实现快速加载gensim word2vec的预训练的词向量模型
  • 3.14-嵌入式软件实习生-面试记录
  • c 语言中指针注意事项
  • 【Miniconda】Linux系统中 .condarc 配置文件的位置一般在哪里
  • C++实验 面向对象编程
  • ES6中 字符串的方法
  • VUE+VScode+elementUI开发环境
  • 自己简单写的 事件订阅机制
  • AHK 中 = 和 == 等比较运算符的用法
  • canvas 高仿 Apple Watch 表盘
  • CSS实用技巧干货
  • DataBase in Android
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript的使用你知道几种?(上)
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • JAVA之继承和多态
  • js操作时间(持续更新)
  • MD5加密原理解析及OC版原理实现
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • QQ浏览器x5内核的兼容性问题
  • React Transition Group -- Transition 组件
  • tab.js分享及浏览器兼容性问题汇总
  • Webpack 4 学习01(基础配置)
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 百度小程序遇到的问题
  • 高性能JavaScript阅读简记(三)
  • 机器学习学习笔记一
  • 记录一下第一次使用npm
  • 来,膜拜下android roadmap,强大的执行力
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 前嗅ForeSpider采集配置界面介绍
  • 前言-如何学习区块链
  • 使用SAX解析XML
  • 怎样选择前端框架
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (06)Hive——正则表达式
  • (42)STM32——LCD显示屏实验笔记
  • (C语言)共用体union的用法举例
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (算法)Game
  • (算法)N皇后问题
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化