总体来说与STM32F4操作是一样的,就是扇区大小变化了,测试过程中发现当PG=1之后立即写入数据到flash会造成编程顺序错误,通过增加一个nop的延时即可解决此问题,还可以通过将多个数据连续烧写的方式避免此问题,就是当PG=1之后,把所有数据都烧写完成后再将PG=0,不要频繁的开关。
/*************************************************************************************************************
* 文件名: stm32f7_flash.c
* 功能: STM32F7 内部FLASH编程驱动函数
* 作者: [email protected]
* 创建时间: 2013-10-20
* 最后修改时间: 2020-02-07
* 详细: 用于STM32F7内部flash读写驱动
默认为3.3V供电,并且宽度为32bit;
扇区擦除最长时间:32KB扇区500ms;128KB扇区1.1秒;256KB扇区:2秒
修复STM32F7开始写入数据时,PG=1后没有延时导致异常,增加批量写入多个字的数据函数STM32FLASH_WriteMultipledWord()支持。
*************************************************************************************************************/
#include "stm32f7_flash.h"
#include "system.h"
#if(SYS_WDG_EN_) //使能了看门狗
#include "wdg.h"
#endif //SYS_WDG_EN_
/*************************************************************************************************************************
* 函数 : void STM32FLASH_Unlock(void)
* 功能 : 解锁STM32的FLASH
* 参数 : 无
* 返回 : 无
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2013-10-20
* 说明 :
*************************************************************************************************************************/
void STM32FLASH_Unlock(void)
{
FLASH->KEYR=FLASH_KEY1; //写入解锁序列.
FLASH->KEYR=FLASH_KEY2;
}
/*************************************************************************************************************************
* 函数 : void STM32FLASH_Lock(void)
* 功能 : 上锁STM32的FLASH
* 参数 : 无
* 返回 : 无
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2018-01-13
* 说明 :
*************************************************************************************************************************/
void STM32FLASH_Lock(void)
{
FLASH->CR|=(u32)1<<31; //上锁
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_GetStatus(void)
* 功能 : 得到FLASH状态
* 参数 : 无
* 返回 : STM32FLASH_STATUS
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2018-01-03
* 说明 :
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_GetStatus(void)
{
u32 temp=FLASH->SR;
if(temp&(1<<16))return STM32FLASH_BUSY; //忙
else if(temp&(1<<4))return STM32FLASH_WPRERR; //写保护错误
else if(temp&(1<<5))return STM32FLASH_PGAERR; //编程对齐错误
else if(temp&(1<<6))return STM32FLASH_PGPERR; //并行位数错误
else if(temp&(1<<7))return STM32FLASH_PGSERR; //擦除顺序错误
else if(temp&(1<<1))return STM32FLASH_OPERR; //操作错误
return STM32FLASH_OK; //操作完成
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_WaitDone(u32 time)
* 功能 : 等待操作完成
* 参数 : time:要延时的长短,单位us
* 返回 : STM32FLASH_STATUS
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2018-01-03
* 说明 : 2018-03-24:增加清除看门狗功能
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_WaitDone(u32 time)
{
STM32FLASH_STATUS status;
if(time < 1) time = 1;
do
{
status=STM32FLASH_GetStatus(); //获取状态
if(status!=STM32FLASH_BUSY)break; //非忙,无需等待了,直接退出.
Delay_US(1);
time--;
#if(SYS_WDG_EN_) //使能了看门狗
IWDG_Feed();
#endif //SYS_WDG_EN_
}while(time);
return status;
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_EraseSector(u8 sectoraddr)
* 功能 : 扇区擦除
* 参数 : sectoraddr:扇区地址,0-11
* 返回 : STM32FLASH_STATUS
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2018-01-03
* 最后修改时间 : 2018-01-03
* 说明 : 扇区大小:0~3:16KB扇区;4:64KB扇区;5~11:128KB扇区
128KB扇区擦除足最大2秒
2018-01-16:修复扇区擦除时没有解锁问题
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_EraseSector(u8 sectoraddr)
{
STM32FLASH_STATUS status;
if(FLASH->SR) //有错误,需要清除,测试过程中,发现偶尔启动后会有错误出现
{
DEBUG("需要清除flash错误标记,FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
FLASH->SR |= FLASH->SR;
DEBUG("FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
}
status=STM32FLASH_WaitDone(2100000); //等待上次操作完成,最大时间2秒,如果已经操作完成了会直接跳过
STM32FLASH_Unlock(); //解锁
if(status==STM32FLASH_OK) //没有错误
{
FLASH->CR&=~(3<<8); //清除PSIZE原来的设置
FLASH->CR|=2<<8; //设置为32bit宽,确保VCC=2.7~3.6V之间!!
FLASH->CR&=~(0XF<<3); //清除原来的设置
FLASH->CR|=(sectoraddr&0x7)<<3; //设置要擦除的扇区
FLASH->CR|=1<<1; //扇区擦除
FLASH->CR|=1<<16; //开始擦除
status=STM32FLASH_WaitDone(2300000);//等待操作结束,最大2s
if(status!=STM32FLASH_BUSY) //非忙
{
FLASH->CR&=~(1<<1); //清除扇区擦除标志.
}
}
//DEBUG("扇区擦除状态:%d\r\n", status);
//DEBUG("FLASH_SR=0x%X FLASH_CR=0x%X\r\n", FLASH->SR, FLASH->CR);
STM32FLASH_Lock(); //上锁
if(status != STM32FLASH_OK)
{
DEBUG("擦除扇区%d失败(错误:%d) FLASH_SR=0x%X FLASH_CR=0x%X\r\n",sectoraddr, status, FLASH->SR, FLASH->CR);
}
return status; //返回状态
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_WritedWord(u32 faddr, u32 data)
* 功能 : 在FLASH指定地址写入一个字的数据(32bit写入)
* 参数 : faddr:指定地址(此地址必须为4的倍数!!);data:要写入的数据
* 返回 : STM32FLASH_STATUS
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2018-01-03
* 最后修改时间 : 2018-01-03
* 说明 : 警告,地址必须为4的倍数
2020-02-08执行PG=1须增加延时,否则可能出现顺序错误,不会执行flash解锁
不会判断是否能写入
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_WritedWord(u32 faddr, u32 data)
{
STM32FLASH_STATUS status;
status=STM32FLASH_WaitDone(200); //判断状态
if(status==STM32FLASH_OK) //没有错误
{
FLASH->CR&=~(3<<8); //清除PSIZE原来的设置
FLASH->CR|=2<<8; //设置为32bit宽,确保VCC=2.7~3.6V之间!!
FLASH->CR|=1<<0; //编程使能,测试发现使能编程后不延时会出现编程顺序错误
nop;nop;nop;nop; //2020-02-08 此处必须增加延时,否则可能出现顺序错误
*(vu32*)faddr=data; //写入数据
status=STM32FLASH_WaitDone(200); //等待操作完成,一个字编程,最多100us.
if(status!=STM32FLASH_BUSY) //非忙
{
FLASH->CR&=~(1<<0); //清除PG位
}
}
if(status != STM32FLASH_OK)
{
DEBUG("FLASH写入错误(%d)FLASH_SR=0x%X FLASH_CR=0x%X\r\n",status, FLASH->SR, FLASH->CR);
}
return status;
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_WriteMultipledWord(u32 faddr, u32 data[], u32 dWordCount)
* 功能 : 在FLASH指定地址写入多个字的数据(32bit连续写入,提高效率)
* 参数 : faddr:指定地址(此地址必须为4的倍数);data:要写入的数据
* 返回 : STM32FLASH_STATUS
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2020-02-08
* 最后修改时间 : 2020-02-08
* 说明 : 警告,地址必须为4的倍数
2020-02-08执行PG=1须增加延时,否则可能出现顺序错误,不会执行flash解锁
不会判断是否能写入
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_WriteMultipledWord(u32 faddr, u32 data[], u32 dWordCount)
{
STM32FLASH_STATUS status;
status=STM32FLASH_WaitDone(200); //判断状态
if(status==STM32FLASH_OK) //没有错误
{
FLASH->CR&=~(3<<8); //清除PSIZE原来的设置
FLASH->CR|=2<<8; //设置为32bit宽,确保VCC=2.7~3.6V之间!!
FLASH->CR|=1<<0; //编程使能,测试发现使能编程后不延时会出现编程顺序错误
nop;nop;nop;nop; //2020-02-08 此处必须增加延时,否则可能出现顺序错误
while(dWordCount --)
{
*(vu32*)faddr=*data++; //写入数据
faddr +=4; //地址自增+4
status=STM32FLASH_WaitDone(200); //等待操作完成,一个字编程,最多100us.
if(status!=STM32FLASH_OK) //有错误
{
break;
}
}
if(status!=STM32FLASH_BUSY) //非忙
{
FLASH->CR&=~(1<<0); //清除PG位
}
}
if(status != STM32FLASH_OK)
{
DEBUG("FLASH写入错误(%d)FLASH_SR=0x%X FLASH_CR=0x%X\r\n",status, FLASH->SR, FLASH->CR);
}
return status;
}
/*************************************************************************************************************************
* 函数 : u32 STM32FLASH_ReadWord(u32 faddr)
* 功能 : 读取指定地址的一个字(32位数据)
* 参数 : faddr:指定地址(此地址必须为4的倍数!!);
* 返回 : 数据
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2018-01-03
* 最后修改时间 : 2018-01-03
* 说明 : 警告:地址必须是4的整数倍
*************************************************************************************************************************/
__inline u32 STM32FLASH_ReadWord(u32 faddr)
{
return *(vu32*)faddr;
}
/*************************************************************************************************************************
* 函数 : u8 STM32FLASH_GetFlashSector(u32 faddr)
* 功能 : 获取某个地址所在的扇区
* 参数 : faddr:指定地址
* 返回 : 删除编号,0-6,如果超出了也会限制到6
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2018-01-03
* 最后修改时间 : 2018-01-03
* 说明 : 地址请不要超出范围
*************************************************************************************************************************/
u8 STM32FLASH_GetFlashSector(u32 faddr)
{
if(faddrSR) //有错误,需要清除,测试过程中,发现偶尔启动后会有错误出现
{
DEBUG("需要清除flash错误标记,FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
FLASH->SR |= FLASH->SR;
DEBUG("FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
}
status = STM32FLASH_WriteMultipledWord(WriteAddr, pBuffer, NumToWrite); //写入多个字的数据
STM32FLASH_Lock(); //上锁
return status;
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_WritedWord_NoCheck(u32 WriteAddr,u32 data)
* 功能 : 不检查的写入一个字
* 参数 : WriteAddr:起始地址(必须是4个整数倍);data:要写入的数据值
* 返回 : 状态
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2020-02-08
* 最后修改时间 : 2020-02-08
* 说明 : 地址必须为4对齐,如果出现了非FF写入程序会报错并返回(由于STM32硬件会对写入区域进行检查,非FF区域不允许写入)
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_WritedWord_NoCheck(u32 WriteAddr,u32 data)
{
STM32FLASH_STATUS status;
if(WriteAddrSR) //有错误,需要清除,测试过程中,发现偶尔启动后会有错误出现
{
DEBUG("需要清除flash错误标记,FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
FLASH->SR |= FLASH->SR;
DEBUG("FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
}
status = STM32FLASH_WritedWord(WriteAddr, data); //写入1个字的数据
STM32FLASH_Lock(); //上锁
return status;
}
/*************************************************************************************************************************
* 函数 : STM32FLASH_STATUS STM32FLASH_Write(u32 WriteAddr,u32 *pBuffer,u16 NumToWrite)
* 功能 : 从指定地址开始写入指定长度的数据(数据长度字为单位)
* 参数 : WriteAddr:起始地址(此地址必须为4的倍数!!);pBuffer:数据指针;NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
* 返回 : 0:完成;1:忙;2:错误;3:写保护
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2016-01-07
* 说明 : 警告:由于STM32F4的扇区太大,无法使用内存进行缓存,如果要写入的位置有非FF,会直接将整个扇区进行擦除,并丢失其它的数据
如果需要保存其他的数据,请在应用层进行实现(比如:先读取扇区,修改扇区,擦除扇区,写入扇区,需要大内存支持)
*************************************************************************************************************************/
STM32FLASH_STATUS STM32FLASH_Write(u32 WriteAddr,u32 *pBuffer,u16 NumToWrite)
{
STM32FLASH_STATUS status;
u32 addrx=0;
u32 endaddr=0;
if(WriteAddrACR&=~(1<<10); //FLASH擦除期间,必须禁止数据缓存!!!搞了我两晚上才发现这个问题!
addrx=WriteAddr; //写入的起始地址
endaddr=WriteAddr+NumToWrite*4; //写入的结束地址
if(addrx<0X1FFF0000) //只有主存储区,才需要执行擦除操作!!
{
while(addrxSR) //有错误,需要清除,测试过程中,发现偶尔启动后会有错误出现
{
DEBUG("需要清除flash错误标记,FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
FLASH->SR |= FLASH->SR;
DEBUG("FLASH_SR=0x%X FLASH_CR=0x%X\r\n",FLASH->SR, FLASH->CR);
}
status = STM32FLASH_WriteMultipledWord(WriteAddr, pBuffer, NumToWrite); //写入多个字的数据
STM32FLASH_Lock(); //上锁
}
FLASH->ACR|=1<<10; //FLASH擦除结束,开启数据fetch
return status;
}
/*************************************************************************************************************************
* 函数 : u16 STM32FLASH_Read(u32 ReadAddr,u32 *pBuffer,u16 NumToRead)
* 功能 : 从指定地址开始读出指定长度的数据
* 参数 : ReadAddr:起始地址;pBuffer:数据指针;NumToWrite:字(32位)数
* 返回 : 读取的数据长度(字为单位)
* 依赖 : 底层
* 作者 : [email protected]
* 时间 : 2013-10-20
* 最后修改时间 : 2016-01-07
* 说明 : 地址必须为4对齐
*************************************************************************************************************************/
u16 STM32FLASH_Read(u32 ReadAddr,u32 *pBuffer,u16 NumToRead)
{
u16 i;
u16 cnt = 0;
if(ReadAddr
/*************************************************************************************************************
* 文件名: stm32f7_flash.H
* 功能: STM32F7 内部FLASH编程驱动函数
* 作者: [email protected]
* 创建时间: 2013-10-20
* 最后修改时间: 2020-02-07
* 详细: 用于STM32F7内部flash读写驱动
*************************************************************************************************************/
#ifndef __STM32F7_FLASH_H__
#define __STM32F7_FLASH_H__
#include "system.h"
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址
//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0 ((u32)0x08000000) //扇区0起始地址, 32 Kbytes
#define ADDR_FLASH_SECTOR_1 ((u32)0x08008000) //扇区1起始地址, 32 Kbytes
#define ADDR_FLASH_SECTOR_2 ((u32)0x08010000) //扇区2起始地址, 32 Kbytes
#define ADDR_FLASH_SECTOR_3 ((u32)0x08018000) //扇区3起始地址, 32 Kbytes
#define ADDR_FLASH_SECTOR_4 ((u32)0x08020000) //扇区4起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_5 ((u32)0x08040000) //扇区5起始地址, 256 Kbytes
#define ADDR_FLASH_SECTOR_6 ((u32)0x08080000) //扇区6起始地址, 256 Kbytes
#define ADDR_FLASH_SECTOR_7 ((u32)0x080C0000) //扇区7起始地址, 256 Kbytes
//FLASH解锁键值
#define RDP_KEY 0x00A5
#define FLASH_KEY1 0X45670123
#define FLASH_KEY2 0XCDEF89AB
#define FLASH_OPT_KEY1 0x08192A3B
#define FLASH_OPT_KEY2 0x4C5D6E7F
//STM32F7 Flash操作状态
typedef enum
{
STM32FLASH_OK = 0, //操作完成
STM32FLASH_BUSY = 1, //忙
STM32FLASH_WPRERR = 2, //写保护错误
STM32FLASH_PGAERR = 3, //编程对齐错误,必须128位对齐
STM32FLASH_PGPERR = 4, //并行位数错误
STM32FLASH_PGSERR = 5, //擦除顺序错误
STM32FLASH_OPERR = 6, //操作错误
}STM32FLASH_STATUS;
//常用接口
STM32FLASH_STATUS STM32FLASH_EraseSector(u8 sectoraddr); //擦除扇区
STM32FLASH_STATUS STM32FLASH_Write_NoCheck(u32 WriteAddr,u32 *pBuffer,u16 NumToWrite) ; //不检查的写入多个字的数据
STM32FLASH_STATUS STM32FLASH_WritedWord_NoCheck(u32 WriteAddr,u32 data) ; //不检查的写入一个字的数据
STM32FLASH_STATUS STM32FLASH_Write(u32 WriteAddr,u32 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据(数据长度字为单位)
u16 STM32FLASH_Read(u32 ReadAddr,u32 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据
//不常用接口
void STM32FLASH_Unlock(void); //FLASH解锁
void STM32FLASH_Lock(void); //FLASH上锁
STM32FLASH_STATUS STM32FLASH_GetStatus(void); //获得状态
#endif //__STM32F7_FLASH_H__