- 存储器大小:我们说的flash大小,指的是主存储器的大小
- 信息块:
- 启动程序代码,用于存储ST自带的启动程序,用于串口下载代码
- 用户选择字节一般用于配置读保护和写保护等功能
- 接口寄存器:用于配置flash读写等
在开发板上有两个跳线帽,可以用来切换B0(Boot0)和B1(Boot1),模式如下
B0 | B1 | 描述 |
---|---|---|
GND | GND | 从0x8000000运行(主存储器基地址) |
3.3 | GND | 从信息块运行 |
- 只有解除写保护才能 *** 作相关寄存器(检查FLASH_CR的LOCK是否解锁)
- flash编程时确保没有其他正在进行的编程 *** 作(检查FLASH_SR的BSY位)
- 每次编程必须写入半字,否则会出错(设置FLASH_CR寄存器的PG位为1)
- flash编程时,写入地址的flash必须是被擦除的,否则无法写入
- 设置CR寄存器的PER为1
- 配置AR寄存器选择擦除页
- 配置CR寄存器的STRT为1
- 等待SR的BSY为0
- 读出验证
- 设置CR的MER为1
- 设置CR的STAT为1
- 等待SR的BSY为0
- 读出验证
- KEYR寄存器写入FPEC解锁键
- CR寄存器:锁,开始等
- SR寄存器:检查忙
- AR寄存器:写地址
#ifndef __STMFLASH_H__
#define __STMFLASH_H__
#include "sys.h"
#define STM32_FLASH_SIZE 256 //定义flash大小
#define STM32_FLASH_WREN 1 //允许写
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH基地址
u16 STMFLASH_ReadHalfWord(u32 faddr); //读半字(2字节)
void STMFLASH_WriteLenByte(u32 WriteAddr,u32 DataToWrite,u16 Len); //ָ写指定长度字节
u32 STMFLASH_ReadLenByte(u32 ReadAddr,u16 Len); //ָ读给定长度字节
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite); //写
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead); //读
//�����
void Test_Write(u32 WriteAddr,u16 WriteData);
#endif
stm32flash.c
#include "stmflash.h"
#include "delay.h"
u16 STMFLASH_ReadHalfWord(u32 faddr)//给地址读取半字
{
return *(vu16*)faddr;
}
#if STM32_FLASH_WREN
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)//进行不检查的写
{
u16 i;
for(i=0;i<NumToWrite;i++)//写numtowrite个半字
{
FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
WriteAddr+=2;//写地址+2(由于是半字)
}
}
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024 //�ֽ�
#else
#define STM_SECTOR_SIZE 2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)//写
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u32 offaddr;
if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//在可写空间之外写
FLASH_Unlock(); //解锁flash
offaddr=WriteAddr-STM32_FLASH_BASE;//计算偏移地址
secpos=offaddr/STM_SECTOR_SIZE; //计算所在sector的地址
secoff=(offaddr%STM_SECTOR_SIZE)/2; //计算sector的偏移量
secremain=STM_SECTOR_SIZE/2-secoff; //计算sector-sector偏移量
if(NumToWrite<=secremain)secremain=NumToWrite;
while(1)
{
STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);
for(i=0;i<secremain;i++)
{
if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;
}
if(i<secremain)
{
FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除页
for(i=0;i<secremain;i++)
{
STMFLASH_BUF[i+secoff]=pBuffer[i]; //写
}
STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);
}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);
if(NumToWrite==secremain)break;
else
{
secpos++;
secoff=0;
pBuffer+=secremain;
WriteAddr+=secremain;
NumToWrite-=secremain;
if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;
else secremain=NumToWrite;
}
};
FLASH_Lock();
}
#endif
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)//将数据读到缓存数组里
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);
ReadAddr+=2;
}
}
void Test_Write(u32 WriteAddr,u16 WriteData)//测试写一个半字
{
STMFLASH_Write(WriteAddr,&WriteData,1);
}
主函数调用
#include "delay.h"
#include "sys.h"
#include "key.h"
#include "oled.h"
#include "stmflash.h"
const u8 TEXT_Buffer[]={"STM32 FLASH TEST"};
#define SIZE sizeof(TEXT_Buffer) //数组长度
#define FLASH_SAVE_ADDR 0X08020000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
int main(void)
{
u8 datatemp[SIZE];
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
KEY_Init(); //按键初始化
OLED_Init();
while(1)
{
if(KEY0)
{
OLED_Refresh();
//OLED_Refresh();
OLED_ShowString(0,0,"start write",16,1);
STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE);
OLED_ShowString(0,16,"write finished",16,1);
OLED_ShowString(0,32," ",16,1);
OLED_Refresh();
}
if(!KEY0){
OLED_Refresh();
OLED_ShowString(0,0,"start read ",16,1);
STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,SIZE);
OLED_ShowString(0,16,"read data is ",16,1);
OLED_ShowString(0,32,datatemp,16,1);
OLED_Refresh();
}
}
}
学习目标
作业
- 阅读flash库
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)