一、stm32寄存器地址介绍
二、FLASH简介
(1)STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口可以对程序存储器和选项字节进行擦除和编程
(2) 读写FLASH的用途:利用程序存储器的剩余空间来保存掉电不丢失的用户数据;通过在程序中编程(IAP),实现程序的自我更新
(3)在线编程(In-Circuit Programming -ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
(4)在程序中编程(In-Application Programming - IAP)可以使用微控制器支持的任—种通信接口下载程序。(首先在 程序更新后不影响的地方自己写一个bootloader程序,需要更新程序之后,程序跳转到自定义的bootloader程序,然后通过任意一种通信接口接收数据,然后在通过对flash的读写,将接受到的数据放到程序正常运行的地方)
三、闪存模块组织
四、flash解锁和加锁
FPEC共有三个键值:
- RDPRT键=Ox000000A5
- KEY1 = Ox45670123
- KEY2 = OxCDEF89AB
解锁步骤:
复位后,FPEC被保护,不能写入FLASH_CR
在FLASH_KEYR先写入KEY1,再写入KEY2,解锁
错误的操作序列会在下次复位前锁死FPEC和FLASH_CR
加锁步骤:
设置FLASH_CR中的LOCK位(置1) 锁住FPEC和FLASH_CR
加锁和解锁的目的是防止误操作
五、使用指针访问存储器
#define _IO volatile
使用指针读指定地址下的存储器:
uint16_t Data = *((_I0 uint16_t *)(0×08000000)) ;
使用指针写指定地址下的存储器:
*((___IO uint16_t*)(0x0800ee0e)) = ox1234;
六、编程过程
针对以上编程过程,库函数已经帮我们写好了,我们只需要调用函数接口即可
七、选项字节
当往RDP里面写入数据之后,需要往nRDP里面写入对应的补码,如果检测到RDP和nRDP的数据不是补码关系, 那么解除读保护错误。但是此操作硬件会自动帮我们完成
八、器件电子签名
电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名
闪存容量寄存器:
基地址:Ox1FFF F7EO 大小: 16位
产品唯一身份标识寄存器:
基地址: Ox1FFF F7E8 大小: 96位
九、代码书写
#include "MyFLASH.h"
uint32_t MyFLASH_Readword (uint32_t Address)
{
return *( (__Io uint32_t *)(Address) );
}
uint16_t MyFLASH_ReadHalfword (uint32_t Address)
{
return *((__1o uint16_t *)(Address) );
}
uint8_t MyFLASH_ReadByte (uint32_t Address)
{
return * ( (__Io uint8_t * ) (Address)) ;
}
void MyFLASH_EraseAllPages (void)
{
FLASH_Unlock () ;
FLASH_EraseAllPages ( ) ;
FLASH_Lock () ;
}
void MyFLASH_ErasePage (uint32_t PageAddress)
{
FLASH_Unlock ( );
FLASH_ErasePage (PageAddress ) ;
FLASH_Lock ();
}
void MyFLASH_Programword (uint32_t Address, uint32_t Data)
{
FLASH_Unlock ( ) ;
FLASH_Programword (Address,Data) ;
FLASH_Lock ( ) ;
}
void MyFIASH_ProgramHalfword (uint32_t Address,uint16_t Data)
{
FLASH_unlock ( ) ;
FLASH_ProgramHalfword (Address,Data) ;
FLASH_Lock ();
}
#include "MyFLASH.h"
#include "store.h"
uint16_t store_Data [ 512];
//上电调用初始化函数,然后就可以加载之前存储在flash中的数据
void store_Init (void)
{
//0x0800Fc00最后一页的首地址;OxA5A5为了判断之前是否存储数据
if (MyFLASH_ReadHalfword(0x0800Fc00)!= OxA5A5)
{
MyFLASH_ErasePage (0x0800FC00);
MyFLASH_ProgramHalfword (0x0800FC00,0xA5A5);
// 一页的大小是1K,存储数据数组大小是半字。第一位存储标志位,后面数据位清0
for (uint16_t i = l; i < 512; i ++)
{
MyFLASH_ProgramHalfword (0x0800FC00 + i * 2,0x0000);
}
}
for (uint16_t i = 0; i <512; i ++)
{
store_Data [i] = MyFLASH_ReadHalfword (0x0800FCO0 + i * 2);
}
}
//调用保存函数就会将数据写入flash存储器中
void store_save (void)
{
MyFLASH_ErasePage (0x080OFC00) ;
for (uint16_t i = 0; i < 512; i ++)
{
MyFLASH_ProgramHalfword (0x0800Fc00 + i * 2,store_Data[i]);
}
}
void store_clear (void)
{
for (uint16_t i = 1; i < 512; i ++)
{
store_Data[i] = 0x0000;
}
store_save () ;
}