目录
一.FLASH简介
二.代码实现
(1)读写内部FLASH
(2)读取芯片ID
一.FLASH简介
存储器地址要记得累
系统存储器是原厂写入的Bootloader程序(用于串口下载),是不允许修改的
闪存存储器接口是外设,用于管理FLASH
OTA,程序升级
IAP:自定义一个Bootloader在FLASH中,当需要更新程序时,就从程序代码跳转到Bootloader,接收程序更新数据然后覆盖原程序,重新再跳回到原程序
整个升级过程,都可以自主完成
整块擦除,信息块的内容不受影响
FPEC会自动计算反码
在编程过程中,任何读写闪存的操作都会使CPU暂停,会导致中断函数执行的暂停
当闪存保护选项由“保护”变为“未保护”时,会自动执行整片擦除
二.代码实现
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);
//选项字节的写入
FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);自定义的Data0和1
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);用户选项的配置位操作返回的状态
typedef enum
{ FLASH_BUSY = 1,忙FLASH_ERROR_PG,编程错误FLASH_ERROR_WRP,写保护错误FLASH_COMPLETE,FLASH_TIMEOUT等待超时
}FLASH_Status;uint32_t FLASH_GetUserOptionByte(void);//获取用户选项的3个配置位
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);//获取状态
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);//等待上一次操作,等待BUSY为0
(1)读写内部FLASH
MyFLASH.c
#include "stm32f10x.h" // Device header
uint32_t MyFLASH_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address));//这里的括号逻辑要规范
}
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)//在32中地址永远是32位的
{return *((__IO 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_ErasePages(uint32_t Address)
{FLASH_Unlock();FLASH_ErasePage(Address);FLASH_Lock();
}
void MyFLASH_ProgramWord(uint32_t Address,uint32_t Data)
{FLASH_Unlock();FLASH_ProgramWord(Address,Data);FLASH_Lock();
}
void MyFLASH_ProgramHalfWord(uint32_t Address,uint16_t Data)
{FLASH_Unlock();FLASH_ProgramHalfWord(Address,Data);FLASH_Lock();}
Store.c
#include "stm32f10x.h" // Device header
#include "MyFLASH.h"
#define STORE_START_ADDRESS 0x0800FC00
#define STORE_COUNT 512
//利用SRAM缓存数组来管理FLASH的最后一页
uint16_t Store_Data[STORE_COUNT];//512个数据每个数据16位,2个字节,对应闪存的一页1024字节
void Store_Init(void)
{uint16_t i;//下面的地址一定要写对,查了半天if(MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)//规定标志位,判断是否第一次读写该页{MyFLASH_ErasePages(STORE_START_ADDRESS);MyFLASH_ProgramHalfWord(STORE_START_ADDRESS,0xA5A5);for(i = 1;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2,0x0000);}}for(i = 0;i<STORE_COUNT;i++){Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i*2);}}
void Store_Save(void)
{uint16_t i;MyFLASH_ErasePages(STORE_START_ADDRESS);for(i = 0;i<STORE_COUNT;i++){MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i*2,Store_Data[i]);}
}
void Store_Clear(void)
{uint16_t i;for(i = 1;i<STORE_COUNT;i++)//这里不要将标志位清零{Store_Data[i] = 0x0000;}Store_Save();//保证数组和闪存数据一样
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"
uint8_t Num;
int main()
{Key_Init();OLED_Init();Store_Init();OLED_ShowString(1,1,"Flag:");OLED_ShowString(2,1,"Data:");Store_Save();while(1){Num = Keynum();if(Num == 1){Store_Data[1] ++;Store_Data[2] +=2;Store_Data[3] +=3;Store_Data[4] +=4;Store_Save();}else if (Num == 2){Store_Clear();}OLED_ShowHexNum(1,6,Store_Data[0],4);OLED_ShowHexNum(3,1,Store_Data[1],4);OLED_ShowHexNum(3,6,Store_Data[2],4);OLED_ShowHexNum(4,1,Store_Data[3],4);OLED_ShowHexNum(4,6,Store_Data[4],4);}
}
注:
使用完
要记得断开连接,避免STM32被占用,keil无法下载程序
小端模式存储:低位字节存储在低位地址
OLED有显存,可以保存最后一次显示的内容
页擦除后,程序损坏,也没有办法自动运行
前3个数相加得到的就是程序占用闪存的大小
后两个数相加得到的就是占用SRAM的大小
(2)读取芯片ID
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
int main()
{OLED_Init();OLED_ShowString(1,1,"FSIZE:");OLED_ShowHexNum(1,7,*((__IO uint16_t *)(0x1FFFF7E0)),4);//存储器时16位的OLED_ShowString(2,1,"UID:");OLED_ShowHexNum(2,5,*((__IO uint16_t *)(0x1FFFF7E8)),4);//存储器可以以半字,字,字节读取OLED_ShowHexNum(2,11,*((__IO uint16_t *)(0x1FFFF7E8+0x02)),4);//要加上地址偏移OLED_ShowHexNum(3,1,*((__IO uint32_t *)(0x1FFFF7E8+0x04)),8);//OLED_ShowHexNum(4,1,*((__IO uint32_t *)(0x1FFFF7E8+0x08)),8);//while(1){}
}