STM32-FLASH

本内容基于江协科技STM32视频学习之后整理而得。

1. FLASH

1.1 简介

  • STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程。(系统存储器是原厂写入的Bootloader程序,不允许我们修改的,)
  • 读写FLASH的用途:
    • 利用程序存储器的剩余空间来保存掉电不丢失的用户数据
    • 通过在程序中编程(IAP),实现程序的自我更新
  • 在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
  • 在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序
类型起始地址存储器用途
ROM0x0800 0000程序存储器Flash存储C语言编译后的程序代码和常量·
0x1FFF F000系统存储器存储BootLoader,用于串口下载
0x1FFF F800选项字节存储一些独立于程序代码的配置参数
RAM0x2000 0000运行内存SRAM存储运行过程中的临时变量
0x4000 0000外设寄存器存储各个外设的配置参数
0xE000 0000内核外设寄存器存储内核各个外设的配置参数

1.2 闪存模块组织

image.png

  • 闪存存储器接口寄存器并不属于闪存,就是一个普通的外设,存储介质也都是RAM。闪存存储器接口寄存器是上面的(主存储器和信息块)的管理员,擦除和编程就是通过读写这些寄存器完成的。
  • 主存储器和信息块是真正的闪存。主存储器就是程序存储器,启动程序代码就是系统存储器。用户选择字节就是选项字节,系统存储器和选项字节又可合称为信息块。
  • 擦除和写保护都是以页为单位的。
  • 写入前必须擦除,擦除必须以最小单位进行,擦除后数据位全变为1,数据只能1写0,不能0写1。擦除和写入之后都需要等待忙。
  • 地址只要以000、400、800、C00结尾的,都一定是页的起始地址。
  • 系统存储器容量是2K。
  • 选项字节容量是16K。

1.3 FLASH基本结构

image.png
选项字节里面有很大一部分配置位,其实是配置主程序存储器的读写保护的。

1.4 FLASH解锁

  • FPEC(闪存编程和擦除控制器)共有三个键值:

    RDPRT键 = 0x000000A5(解除读保护的密钥)
    KEY1 = 0x45670123
    KEY2 = 0xCDEF89AB

  • 解锁:

    复位后,FPEC被保护,不能写入FLASH_CR
    在FLASH_KEYR先写入KEY1,再写入KEY2,解锁
    错误的操作序列会在下次复位前锁死FPEC和FLASH_CR

  • 加锁:

    设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR
    image.png

1.5 使用指针访问存储器

  • 使用指针读指定地址下的存储器:(不需要解锁)

    uint16_t Data = *((__IO uint16_t *)(0x08000000));
    首先使用指针读指定地址0x08000000下的存储器,要读取该地址下的数据就把这个地址写在这。在该地址前加上强制类型转换(__IO uint16_t *),转换成了uint16_t的指针类型,__IO 是宏定义,对应C语言的关键字volatile(易变的数据),加上该关键字是防止编译器优化。

  • 使用指针写指定地址下的存储器:(需要提前解锁,还需要加上程序存储器编程的流程,但如果是写入SRAM的,可以直接写入,因为SRAM是可读可写的。)

    *((__IO uint16_t *)(0x08000000)) = 0x1234;

  • 其中:

    #define __IO volatile

1.6 程序存储器编程–写入

image.png

  • 字:32位;半字:16位;字节:8位
  • 擦除之后,就可以执行写入的流程了。STM32的闪存在写入之前会检查指定地址有没有擦除,如果没有擦除就写入,STM32则不执行写入操作,除非写入的全是0,这一个数据是例外,因为不擦除就写入,可能会写入错误,但全写入0的话,写入肯定是没问题的,
  • 第一步也是解锁,第二步要置控制寄存器的PG位=1,表示要写入数据。然后就是在指定的地址写入半字,这时需要用到“使用指针写指定地址下的存储器*((__IO uint16_t *)(0x08000000)) = 0x1234;“。写入操作只能以半字的形式写入,写入半字之后,芯片会处于忙状态,等待一下BSY清0,这样写入数据的过程就完成了。

1.7 程序存储器页擦除

image.png
PER=1是页擦除,
STRT=1是触发条件,存储器开始干活,PER=1表明接下来要的活是页擦除,由于闪存不止一页,页擦除,芯片就要知道具体要擦哪一页,所以它要继续看AR寄存器的数据,AR寄存器要提前写入一个页起始地址,这样芯片就会把我们指定的一页给擦除掉。擦除开始之后,也要等待BSY位。

1.8 程序存储器全擦除

image.png
解锁过程:在FLASH_KEYR先写入KEY1,再写入KEY2,解锁。解锁后,首先置控制寄存器里的MER(Mass Erase)位为1,然后再置STRT(Start)位为1,STRT=1是触发条件,存储器开始干活,MER=1表明接下来要的活是全擦除,这样内部电路就会自动执行全擦除的过程。擦除也是需要花一段时间的,所以擦除过程开始后,程序要执行等待,判断状态寄存器的BSY位是否为1,BSY位表示芯片是否处于忙状态,BSY位=1表示忙。如果BSY为1,就跳转回来,继续循环判断,直到BSY=0,跳出循环。最后读出并验证所有页的数据是测试程序才要做的。正常情况下,全擦除完成了,默认就是成功了。

1.9 选项字节

image.png

  • RDP:写入RDPRT键(0x000000A5)后解除读保护
  • USER:配置硬件看门狗和进入停机/待机模式是否产生复位
  • Data0/1:用户可自定义使用
  • WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)。4个字节总共32位,一位保护4页,总共保护32*4=128页

带n的是写入反码。意思是当你在写入RDP数据时,要同时在nRDP写入数据的反码。
image.png

1.10 选项字节编程

  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作
  • 解锁FLASH_CR的OPTWRE位
  • 设置FLASH_CR的OPTPG位为1(即将写入选项字节)
  • 写入要编程的半字到指定的地址(指针写入操作)
  • 等待BSY位变为0
  • 读出写入的地址并验证数据

1.11 选项字节擦除

  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作(第一步也是解锁,这一步相当于事前等待)
  • 解锁FLASH_CR的OPTWRE位(选项字节的解锁)(解锁闪存后还要再解锁选项字节,之后才能操作选项字节)(解锁选项字节,时再OPTKEYR里先写入KEY1,再写入KEY2)
  • 设置FLASH_CR的OPTER位为1(即将擦除选项字节)
  • 设置FLASH_CR的STRT位为1(触发芯片,开始干活,这样芯片就会启动擦除选项字节的工作)
  • 等待BSY位变为0
  • 读出被擦除的选择字节并做验证

1.12 器件电子签名(ID号)

  • 电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名(STM32的ID号)

  • 闪存容量寄存器:

    基地址:0x1FFF F7E0
    大小:16位

  • 产品唯一身份标识寄存器:

    基地址: 0x1FFF F7E8
    大小:96位

1.13 FLASH库函数

// 解锁
void FLASH_Unlock(void);
// 加锁
void FLASH_Lock(void);
// 擦除某一页
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
// 全擦除
FLASH_Status FLASH_EraseAllPages(void);
// 擦除选项字节
FLASH_Status FLASH_EraseOptionBytes(void);
// 指定地址写入字
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
// 指定地址写入半字
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
// 选项字节的写入,自定义的Data0和Data1
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);
// 选项字节写保护
FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);
// 选项字节读保护
FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);
// 选项字节用户选项的三个配置位
FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);
// 获取选项字节当前的状态,获取用户选项的状态位
uint32_t FLASH_GetUserOptionByte(void);
// 获取写保护状态
uint32_t FLASH_GetWriteProtectionOptionByte(void);
// 获取读保护状态
FlagStatus FLASH_GetReadOutProtectionStatus(void);
// 获取预取缓冲区状态
FlagStatus FLASH_GetPrefetchBufferStatus(void);
// 中断使能
void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);
// 获取标志位
FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);
// 清除标志位
void FLASH_ClearFlag(uint32_t FLASH_FLAG);
// 获取状态
FLASH_Status FLASH_GetStatus(void);
// 等待上一次操作,等待忙,等待BSY为0
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值