嵌入式_基于STM32F4标准库的Flash读写操作

嵌入式_基于STM32F4标准库的Flash读写操作



前言

在STM32芯片内有一个Flash存储器断电后数据不会丢失,所以Flash中经常存储一些关键数据,例如:运行的程序、属性文件、密钥、累计运行时间、故障日志等,所以Falsh读写操作非常重要。

<1>、硬件平台:STM32F407
<2>、软件平台:本例程是基于使用标准STM32F4xx_DSP_StdPeriph_Lib_V1.4.0固件库编写,


一、STM32F4的 Flash 简介

不同型号的 STM32 的FLASH 容量也有所不同,最小的只有 128K 字节,最大的则达到了 1024K 字节。我们使用的是STM32F407ZGT6 的 FLASH 容量为 1024K 字节,其 STM32F40xx/41xx 的闪存模块组织如图 所示:
在这里插入图片描述
主存储器:该部分用来存放代码和数据常数(如 const 类型的数据)。分为 12 个扇区,前 4个扇区为 16KB 大小,然后扇区 4是 64KB 大小,扇区5~11 是 128K 大小,不同容量的 STM32F4,拥有的扇区数不一样,比如我们的 STM32F407ZGT6,则拥有全部 12 个扇区。从上图可以看出主存储器的起始地址就是 0X08000000, B0、 B1 都接 GND 的时候,就是从 0X08000000 开始运行代码的。

系统存储器:其主要存放 STM32F4 出厂就被固化的bootloader 代码,专门来给主存储器下载代码的。当 B0 和B1分别 接 3.3v、GND 的时候,从该存储器启动(即进入串口下载模式)。

OTP 区域:即一次性可编程区域,共 528 字节,被分成两个部分,前面 512 字节(32 字节为 1 块,分成 16 块),用来存储一些用户数据(一次性的,写完一次,永远不可以擦除!!),后16 字节,用于锁定对应块。

选项字节:用于配置读保护、 BOR 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。

二、闪存的读写操作

1.闪存的读取

STM32F4 可通过内部的 I-Code 指令总线或 D-Code 数据总线访问内置闪存模块,我们通过 D-Code 数据总线来访问内部闪存模块进行读写。 为了准确读取 Flash 数据,必须根据 CPU 时钟 (HCLK) 频率和器件电源电压在 Flash 存取控制寄存器 (FLASH_ACR)中正确地设置等待周期数 (LATENCY)。当电源电压低于 2.1V 时,必须关闭预取缓冲器。 Flash等待周期与 CPU 时钟频率之间的对应关系所示:
在这里插入图片描述
等待周期通过 FLASH_ACR 寄存器的 LATENCY[2:0]三个位设置。系统复位后, CPU 时钟频率为内部 16M RC 振荡器, LATENCY 默认是 0,即 1 个等待周期。供电电压,我们一般是3.3V,所以,在我们设置 168Mhz 频率作为 CPU 时钟之前,必须先设置 LATENCY 为 5,否则
FLASH 读写可能出错,导致死机。
正常工作时(168Mhz),虽然 FLASH 需要 6 个 CPU 等待周期,但是由于 STM32F4 具有自适应实时存储器加速器(ART Accelerator),通过指令缓存存储器,预取指令,实现相当于 0 FLASH 等待的运行速度,根据这个特性,可以在写入后再读出来对比写入数据是否正确。
STM23F4 的 FLASH 读取是非常简单的。例如,我们要从地址 addr,读取一个字(字节为 8位, 半字为 16 位,字为 32 位),可以通过如下的语句读取:
d a t a = ∗ ( u i n t 32 ∗ ) a d d r data=*(uint32*)addr data=(uint32)addr
将 addr 强制转换为 uint32 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。类似的,将上面的 uint32 改为 uint6或者uint8,即可读取指定地址的一个半字。

代码如下(示例):

/************************************************************************************
*@fuction	:InFlashReadWord
*@brief		:get a word
*@param		:32-bit address
*@return	:word
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
uint32_t InFlashReadWord(const uint32_t VaddressStart)
{
	return *(uint32_t*)VaddressStart;
}

/************************************************************************************
*@fuction	:InFlashReadByte
*@brief		:get a Byte
*@param		:32-bit address
*@return	:Byte
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
uint8_t InFlashReadByte(const uint32_t VaddressStart)
{
	return *(uint8_t*)VaddressStart;
}

扩展一下读取多个字或多个字节的函数如下代码所示:


/************************************************************************************
*@fuction	:InFlashReadWordData
*@brief		:
*@param		:32-bit address
*@return	:
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashReadWordData(uint32_t VaddressStart,uint32_t *V_Data,uint32_t Datalen)
{
	ReturnType ret = E_OK;

	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || ((VaddressStart%4) != 0))
	{
		/*地址非法*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		u32 i;
		for(i = 0;i < Datalen;i++)
		{
			V_Data[i]=InFlashReadWord(VaddressStart);//读取 4 个字节.
			VaddressStart += 4;//地址偏移 4 个字节.
		}
	}
	else
	{
		return ret;
	}

	return ret;
}
/************************************************************************************
*@fuction	:InFlashReadByteData
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashReadByteData(uint32_t VaddressStart,uint8_t *Pbuffer,uint32_t Bufflen)
{
	uint32_t iread; 
	ReturnType ret = E_OK;
	
	if(Bufflen == 0)
	{
		ret = E_NOT_OK;
	}
	if(ret != E_NOT_OK)
	{
		for(iread = 0;(iread < Bufflen) && (VaddressStart < FLASH_MAIN_MEMADDR_END);iread++)
		{
			Pbuffer[iread] = InFlashReadByte(VaddressStart);
			VaddressStart++;
		}
	}
	return ret;
}

2.闪存的解锁、擦除和写入

STM32F4 FLASH 的写就稍微复杂一点了,在介绍写解锁、擦除和写入之前先介绍一下Flash状态寄存器(FLASH_SR),因为解锁、擦除和写入都是环环相扣的,执行每一步都必须通过判断Flash状态寄存器的值来判断上一步操作是否正常结束,否则无法执行下一步。

获取 FLASH 状态主要调用的函数是:

FLASH_Status FLASH_GetStatus(void)

返回值是通过枚举类型定义的:

typedef enum
{
FLASH_BUSY = 1,//操作忙
FLASH_ERROR_RD,//读保护错误
FLASH_ERROR_PGS,//编程顺序错误
FLASH_ERROR_PGP,//编程并行位数错误
FLASH_ERROR_PGA,//编程对齐错误
FLASH_ERROR_WRP,//写保护错误
FLASH_ERROR_PROGRAM,//编程错误
FLASH_ERROR_OPERATION,//操作错误
FLASH_COMPLETE//操作结束
}FLASH_Status;

有一点非常重要即在写入之前必须保证需要写入的页面是被擦除的,下面我们介绍 STM32F4 闪存的擦除和写入操作:

1.闪存解锁

1.解锁原理:STM32F4 复位后, 其Flash 编程操作是被保护的,不能写入 FLASH_CR 寄存器;通过写入
特定的序列(0X45670123 和 0XCDEF89AB) 到 FLASH_KEYR 寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关寄存器。

2.注意事项:
通过上述这两个步骤,即可解锁 FLASH_CR,如果写入错误,那么 FLASH_CR 将被锁定,直到下次复位后才可以再次解锁。

3.操作步骤:
FLASH_CR 的解锁序列为:
1, 写 0X45670123 到 FLASH_KEYR
2, 写 0XCDEF89AB 到 FLASH_KEYR

这个在标准库中有现成的解锁函数:

/** @defgroup FLASH_Keys 
  * @{
  */ 
#define RDP_KEY                  ((uint16_t)0x00A5)
#define FLASH_KEY1               ((uint32_t)0x45670123)
#define FLASH_KEY2               ((uint32_t)0xCDEF89AB)
#define FLASH_OPT_KEY1           ((uint32_t)0x08192A3B)
#define FLASH_OPT_KEY2           ((uint32_t)0x4C5D6E7F)
/**
  * @brief  Unlocks the FLASH control register access
  * @param  None
  * @retval None
  */
void FLASH_Unlock(void)
{
  if((FLASH->CR & FLASH_CR_LOCK) != RESET)
  {
    /* Authorize the FLASH Registers access */
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
  }  
}

2.闪存擦除

1.擦除原理:根本原因是Flash物理特性决定的,flash芯片是浮动栅极晶体管,写操作只能将1变为0,而不能将0变为1,擦除之后,flash中是全1的状态,若想将0变为1则只能通过擦除操作。

2.注意事项:
(1)执行任何 Flash 编程操作(擦除或编程)时, CPU 时钟频率 (HCLK)不能低于 1 MHz。
(2)如果在 Flash 操作期间发生器件复位,无法保证 Flash 中的内容。
(3)在对 STM32F4 的 Flash 执行写入或擦除操作期间,任何读取 Flash 的尝试都会导致总线阻塞。
(4)写/擦除操作进行期间不能从Flash 中执行代码或数据获取操作。

3.操作步骤:
(1)检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁
(2)检查 FLASH_SR 寄存器中的 BSY 位,确保当前未执行任何 FLASH 操作
(3)在 FLASH_CR 寄存器中,将 SER 位置 1,并从主存储块的 12 个扇区中选择要擦除的扇区 (SNB)
(4)将 FLASH_CR 寄存器中的 STRT 位置 1,触发擦除操作
(5)等待 BSY 位清零

这个在标准库中有现成的扇区擦除函数:

FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector, uint8_t VoltageRange)

参数为所要擦除的扇区编号和设备匹配电压,在本文最后给出的完成代码中,我们也从新包装了擦除函数,即给出随意合法地址,然后自动算出该地址所在扇区并进行解锁擦除该扇区

3.闪存写入

1.写入接口:
解锁和擦除完毕,即可对Flash进行写入操作
在标准库中有现成的字写入函数和字节写入函数(注意区分):

FLASH_Status FLASH_ProgramByte(uint32_t Address, uint8_t Data); //字节写入
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);//半字写入
FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);//字写入

2.注意事项:
(1)写入地址必须是用户代码区以外的地址,否则可能擦除用户代码导致程序异常
(2)循环写入时候注意地址递增值,比如按照字写入,地址应该递 +4;按字节写入,地址递增+1。

三、完整代码

头文件定义了每个扇区的起始地址,以便根据地址查找所在扇区,并且写入一般以该扇区首地址写入,

头文件:

#ifndef __FLASH_H
#define __FLASH_H

#include "stdio.h"
#include "string.h"
#include "Config.h"


/*Private typedef*/
typedef enum{FAILED = 0,PASSED = !FAILED}TestStatus;

/***********************************************************************
 *功能块说明:Flash存储宏定义 @Yw
 ***********************************************************************/
#define FLASH_EORROR_CODE0 ((uint8_t)0xE0)
#define FLASH_EORROR_CODE1 ((uint8_t)0xE1)
#define FLASH_EORROR_CODE3 ((uint8_t)0xE2)
/***********************************************************************
 *功能块说明:Flash存储宏定义 @Yw
 ***********************************************************************/
#define STM32_FLASH_SIZE   1024 //1M = 1024*1k
#define STM32_FLASH_WREN	 1

#if STM32_FLASH_SIZE < 256 /*小容量的产品*/
	#define FLASH_PAGE_SIZE ((uint_16)0x400)/*页的大小为1K*/
#elif (STM32_FLASH_SIZE >= 256) && (STM32_FLASH_SIZE < 1024)
	#define FLASH_PAGE_SIZE ((uint_16)0x800)/*页的大小为2K*/
#else 
	/* Base address of the Flash sectors */ 
	#define ADDR_FLASH_SECTOR_0     	((uint32_t)0x08000000) /* Base address of Sector 0, 16 Kbytes   */
	#define ADDR_FLASH_SECTOR_1    		((uint32_t)0x08004000) /* Base address of Sector 1, 16 Kbytes   */
	#define ADDR_FLASH_SECTOR_2     	((uint32_t)0x08008000) /* Base address of Sector 2, 16 Kbytes   */
	#define ADDR_FLASH_SECTOR_3     	((uint32_t)0x0800C000) /* Base address of Sector 3, 16 Kbytes   */
	#define ADDR_FLASH_SECTOR_4     	((uint32_t)0x08010000) /* Base address of Sector 4, 64 Kbytes   */
	#define ADDR_FLASH_SECTOR_5     	((uint32_t)0x08020000) /* Base address of Sector 5, 128 Kbytes  */
	#define ADDR_FLASH_SECTOR_6     	((uint32_t)0x08040000) /* Base address of Sector 6, 128 Kbytes  */
	#define ADDR_FLASH_SECTOR_7     	((uint32_t)0x08060000) /* Base address of Sector 7, 128 Kbytes  */
	#define ADDR_FLASH_SECTOR_8     	((uint32_t)0x08080000) /* Base address of Sector 8, 128 Kbytes  */
	#define ADDR_FLASH_SECTOR_9     	((uint32_t)0x080A0000) /* Base address of Sector 9, 128 Kbytes  */
	#define ADDR_FLASH_SECTOR_10    	((uint32_t)0x080C0000) /* Base address of Sector 10, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_11    	((uint32_t)0x080E0000) /* Base address of Sector 11, 128 Kbytes */
	#define FLASH_SECTOR_11_ENDADDR		((uint32_t)0x08100000)/*End address of Sector 11*/
	#define	FLASH_SECTOR_NUMBER				(12U)
	
	#if defined (USE_STM324x7I_EVAL) || defined (USE_STM324x9I_EVAL) 
	#define ADDR_FLASH_SECTOR_12     	((uint32_t)0x08100000) /* Base address of Sector 12, 16 Kbytes  */
	#define ADDR_FLASH_SECTOR_13     	((uint32_t)0x08104000) /* Base address of Sector 13, 16 Kbytes  */
	#define ADDR_FLASH_SECTOR_14     	((uint32_t)0x08108000) /* Base address of Sector 14, 16 Kbytes  */
	#define ADDR_FLASH_SECTOR_15     	((uint32_t)0x0810C000) /* Base address of Sector 15, 16 Kbytes  */
	#define ADDR_FLASH_SECTOR_16     	((uint32_t)0x08110000) /* Base address of Sector 16, 64 Kbytes  */
	#define ADDR_FLASH_SECTOR_17     	((uint32_t)0x08120000) /* Base address of Sector 17, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_18     	((uint32_t)0x08140000) /* Base address of Sector 18, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_19     	((uint32_t)0x08160000) /* Base address of Sector 19, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_20     	((uint32_t)0x08180000) /* Base address of Sector 20, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_21     	((uint32_t)0x081A0000) /* Base address of Sector 21, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_22     	((uint32_t)0x081C0000) /* Base address of Sector 22, 128 Kbytes */
	#define ADDR_FLASH_SECTOR_23     	((uint32_t)0x081E0000) /* Base address of Sector 23, 128 Kbytes */
	#define FLASH_SECTOR_23_ENDADDR		((uint32_t)0x0820000)	/*End address of Sector 24*/
	#define	FLASH_BIG_SECTOR_NUMBER		(24U)

	#endif /* USE_STM324x7I_EVAL or USE_STM324x9I_EVAL */

	#define DATA_32                 	((uint32_t)0x12345678)

#endif

/**/

/*Flash主存储区起始地址*/
#define FLASH_MAIN_MEMADDR_BASE 							((uint32_t)0x08000000)
/*系统存储区起始地址*/
#define FLASH_SYS_MemADDR_BASE 								((uint32_t)0x1FFF0000)
/*OTP区域起始地址*/
#define FLASH_OTP_MemADDR_BASE 								((uint32_t)0x1FFF7800)
/*选项字节起始地址*/
#define FLASH_OPTIONBYTE_MemADDR_BASE 						((uint32_t)0x1FFFC000)
/*Flash结束地址*/
#if defined (USE_STM324x7I_EVAL) || defined (USE_STM324x9I_EVAL) 
	#define FLASH_MAIN_MEMADDR_END			 				FLASH_SECTOR_23_ENDADDR
	#define FLASH_SECTOR_MAXNUMBER							FLASH_BIG_SECTOR_NUMBER
#else
	#define FLASH_MAIN_MEMADDR_END			 				FLASH_SECTOR_11_ENDADDR
	#define FLASH_SECTOR_MAXNUMBER							FLASH_SECTOR_NUMBER
#endif

/*APP代码存储区域大小32k*/
#define CODE_FLASH_SIZE										((uint32_t)((STM32_FLASH_SIZE/64)*0x400))
/*其他数据存储区起始地址0x08004000*/
#define USERDATA_START_FLASH_ADDR							(FLASH_MAIN_MemADDR_BASE + CODE_FLASH_SIZE)


/***********************************************************************
 *功能块说明:Flash存储API @Yw
 ***********************************************************************/
extern void InFlashInit(void);

extern ReturnType Flash_EraseFlash(uint32_t VaddressStart,uint32_t VaddressEnd);

extern uint8_t InFlashReadByte(const uint32_t VaddressStart);
extern uint32_t InFlashReadWord(const uint32_t VaddressStart);
extern ReturnType InFlashReadByteData(uint32_t VaddressStart,uint8_t *Pbuffer,uint32_t Bufflen);
extern ReturnType InFlashReadWordData(uint32_t VaddressStart,uint32_t *V_Data,uint32_t Datalen);

extern ReturnType InFlashWriteByte(uint32_t VaddressStart,uint8_t Data);
extern ReturnType InFlashWriteWord(uint32_t VaddressStart,uint32_t Data);
extern ReturnType InFlashWriteByteData(uint32_t VaddressStart,uint8_t *DataSoruce,uint32_t Datalen);
extern ReturnType InFlashWriteWordData(uint32_t VaddressStart,uint32_t *DataSoruce,uint32_t Datalen);

#endif

.C文件:

#include "Flash_Dev.h"


volatile uint16_t InFlash_SectorTable[FLASH_SECTOR_MAXNUMBER] = 
{
	FLASH_Sector_0, FLASH_Sector_1, FLASH_Sector_2,FLASH_Sector_3, 
	FLASH_Sector_4, FLASH_Sector_5, FLASH_Sector_6, FLASH_Sector_7, 
	FLASH_Sector_8, FLASH_Sector_9, FLASH_Sector_10,FLASH_Sector_11

	#if defined (USE_STM324x7I_EVAL) || defined (USE_STM324x9I_EVAL) 
	
	FLASH_Sector_12;FLASH_Sector_13;FLASH_Sector_14;FLASH_Sector_15;
	FLASH_Sector_16;FLASH_Sector_17;FLASH_Sector_18;FLASH_Sector_19;
	FLASH_Sector_20;FLASH_Sector_21;FLASH_Sector_22;FLASH_Sector_23

	#endif
};

/************************************************************************************
*@fuction	:GetInFlash_SectorNumber
*@brief		:
*@param		:32-bit address
*@return	:The address of the SECTOR Number
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
static uint8_t GetInFlash_SectorNumber(uint32_t Address)
{
	if(Address < ADDR_FLASH_SECTOR_1)					return 0; 	/* Base address of Sector 0, 16 Kbytes   */
	else if(Address < ADDR_FLASH_SECTOR_2)		return 1; 	/* Base address of Sector 1, 16 Kbytes   */
	else if(Address < ADDR_FLASH_SECTOR_3)		return 2; 	/* Base address of Sector 2, 16 Kbytes   */
	else if(Address < ADDR_FLASH_SECTOR_4)		return 3; 	/* Base address of Sector 3, 16 Kbytes   */
	else if(Address < ADDR_FLASH_SECTOR_5)		return 4; 	/* Base address of Sector 4, 64 Kbytes   */
	else if(Address < ADDR_FLASH_SECTOR_6)		return 5; 	/* Base address of Sector 5, 128 Kbytes  */
	else if(Address < ADDR_FLASH_SECTOR_7)		return 6; 	/* Base address of Sector 6, 128 Kbytes  */
	else if(Address < ADDR_FLASH_SECTOR_8)		return 7; 	/* Base address of Sector 7, 128 Kbytes  */
	else if(Address < ADDR_FLASH_SECTOR_9)		return 8; 	/* Base address of Sector 8, 128 Kbytes  */
	else if(Address < ADDR_FLASH_SECTOR_10)		return 9; 	/* Base address of Sector 9, 128 Kbytes  */
	else if(Address < ADDR_FLASH_SECTOR_11)		return 10;	/* Base address of Sector 10, 128 Kbytes */
	else if(Address < FLASH_SECTOR_11_ENDADDR)	return 11;	/* Base address of Sector 11, 128 Kbytes */
	else	return FLASH_EORROR_CODE0;	 					/* address of Sector eorror	*/	

	#if defined (USE_STM324x7I_EVAL) || defined (USE_STM324x9I_EVAL) 
	
	else if(Address < ADDR_FLASH_SECTOR_13) 	return 12; /* Base address of Sector 12 16 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_14)		return 13; /* Base address of Sector 13 16 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_15)		return 14; /* Base address of Sector 14 16 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_16)		return 15; /* Base address of Sector 15 16 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_17)		return 16; /* Base address of Sector 16 64 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_18)		return 17; /* Base address of Sector 17 128 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_19)		return 18; /* Base address of Sector 18 128 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_20)		return 19; /* Base address of Sector 19 128 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_21)		return 20; /* Base address of Sector 20 128 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_22)		return 21; /* Base address of Sector 21 128 Kbytes*/
	else if(Address < ADDR_FLASH_SECTOR_23)		return 22; /* Base address of Sector 22 128 Kbytes*/
	else if(Address < FLASH_SECTOR_23_ENDADDR)	return 23; /* Base address of Sector 23 128 Kbytes*/
	else	return FLASH_EORROR_CODE0;	 				   /* address of Sector eorror	*/

	#endif /* USE_STM324x7I_EVAL or USE_STM324x9I_EVAL */
}

/************************************************************************************
*@fuction	:Flash_EraseFlash
*@brief		:32-bit addressStart,32-bit addressEnd
*@param		:32-bit address
*@return	:
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType Flash_EraseFlash(uint32_t VaddressStart,uint32_t VaddressEnd)
{
	ReturnType ret = E_OK;
	FLASH_Status  status = FLASH_COMPLETE;

	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || ((VaddressStart%4) != 0))/*地址非法*/
	{
		ret = E_NOT_OK;		
	}
	if (ret == E_OK)
	{
		uint8_t StartSector_Index = GetInFlash_SectorNumber(VaddressStart);
		
		FLASH_Unlock();
		FLASH_DataCacheCmd(DISABLE);
		while(StartSector_Index <= GetInFlash_SectorNumber(VaddressEnd))
		{
			if(status != FLASH_EraseSector(InFlash_SectorTable[StartSector_Index],VoltageRange_3))
			{
				break;
			}
			else
			{
				StartSector_Index++;
			}	
		}
		FLASH_Lock();
	}
	if(status != FLASH_COMPLETE)
 	{
		ret = E_NOT_OK;
 	}

  	return ret;
}




/************************************************************************************
*@fuction	:InFlashReadWord
*@brief		:get a word
*@param		:32-bit address
*@return	:word
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
uint32_t InFlashReadWord(const uint32_t VaddressStart)
{
	return *(uint32_t*)VaddressStart;
}

/************************************************************************************
*@fuction	:InFlashReadByte
*@brief		:get a Byte
*@param		:32-bit address
*@return	:Byte
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
uint8_t InFlashReadByte(const uint32_t VaddressStart)
{
	return *(uint8_t*)VaddressStart;
}


/************************************************************************************
*@fuction	:InFlashReadWordData
*@brief		:
*@param		:32-bit address
*@return	:
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashReadWordData(uint32_t VaddressStart,uint32_t *V_Data,uint32_t Datalen)
{
	ReturnType ret = E_OK;

	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || ((VaddressStart%4) != 0))
	{
		/*地址非法*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		u32 i;
		for(i = 0;i < Datalen;i++)
		{
			V_Data[i]=InFlashReadWord(VaddressStart);//读取 4 个字节.
			VaddressStart += 4;//地址偏移 4 个字节.
		}
	}
	else
	{
		return ret;
	}

	return ret;
}


/************************************************************************************
*@fuction	:InFlashWriteByte
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashWriteByte(uint32_t VaddressStart,uint8_t Data)
{
	//使用该函数前先将Flash解锁和擦除
	ReturnType ret = E_OK;
	FLASH_Status  status = FLASH_COMPLETE;
	
	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || (VaddressStart > FLASH_MAIN_MEMADDR_END) || (*(uint32_t *)VaddressStart != 0xFFFFFFFF))
	{
		/*地址非法或者未擦除*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		status = FLASH_ProgramByte(VaddressStart,Data);
		if (status != FLASH_COMPLETE)
		{
			return E_NOT_OK;
		}
		else
		{
			if(*(uint8_t *)VaddressStart != Data)
			{
				return E_NOT_OK;
			}
		}
	}
	return E_OK;
}

/************************************************************************************
*@fuction	:InFlashWriteByte
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashWriteWord(uint32_t VaddressStart,uint32_t Data)
{
	//使用该函数前先将Flash解锁和擦除
	ReturnType ret = E_OK;
	FLASH_Status  status = FLASH_COMPLETE;
	
	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || (VaddressStart > FLASH_MAIN_MEMADDR_END) || (*(uint32_t *)VaddressStart != 0xFFFFFFFF))
	{
		/*地址非法或者未擦除*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		status = FLASH_ProgramWord(VaddressStart,Data);
		if (status != FLASH_COMPLETE)
		{
			return E_NOT_OK;
		}
		else
		{
			if(*(uint32_t *)VaddressStart != Data)
			{
				return E_NOT_OK;
			}
		}
	}
	return E_OK;
}
/************************************************************************************
*@fuction	:InFlashWriteByteData
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashWriteByteData(uint32_t VaddressStart,uint8_t *DataSoruce,uint32_t Datalen)
{
	uint32_t iWrite = 0;
	
	ReturnType ret = E_OK;
	//FLASH_Status  status = FLASH_COMPLETE;

	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || (VaddressStart > FLASH_MAIN_MEMADDR_END))
	{
		/*地址非法*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		FLASH_Unlock();
		for(iWrite = 0;(iWrite < Datalen) && (VaddressStart < FLASH_MAIN_MEMADDR_END);iWrite++)
		{
			if(E_OK == InFlashWriteByte(VaddressStart,*(uint8_t *)(DataSoruce + iWrite)))
			{
				VaddressStart += 1;//写入地址偏移 1个字节.
			}
			else
			{
				ret = E_NOT_OK;	
			}
		}
		FLASH_Lock();
	}

	return ret;
}

/************************************************************************************
*@fuction	:InFlashWriteWordData
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashWriteWordData(uint32_t VaddressStart,uint32_t *DataSoruce,uint32_t Datalen)
{
	uint32_t iWrite = 0;
	//uint32_t WriteAddr = VaddressStart;	
	
	ReturnType ret = E_OK;
	//FLASH_Status  status = FLASH_COMPLETE;

	if((VaddressStart < FLASH_MAIN_MEMADDR_BASE) || (VaddressStart > FLASH_MAIN_MEMADDR_END))
	{
		/*地址非法*/
		ret = E_NOT_OK;	
	}
	if(ret == E_OK)
	{
		FLASH_Unlock();
		for(iWrite = 0;(iWrite < Datalen) && (VaddressStart < FLASH_MAIN_MEMADDR_END);iWrite++)
		{
			if(E_OK == InFlashWriteWord(VaddressStart,*(uint32_t *)(DataSoruce + iWrite)))
			{
				VaddressStart += 4;//写入地址偏移 4个字节.
			}
			else
			{
				ret = E_NOT_OK;	
			}
		}
		FLASH_Lock();
	}

	return ret;
}

/************************************************************************************
*@fuction	:InFlashReadByteData
*@brief		:
*@param		:--
*@return	:void
*@author	:_Awen
*@date		:2022-10-31
************************************************************************************/
ReturnType InFlashReadByteData(uint32_t VaddressStart,uint8_t *Pbuffer,uint32_t Bufflen)
{
	uint32_t iread; 
	ReturnType ret = E_OK;
	
	if(Bufflen == 0)
	{
		ret = E_NOT_OK;
	}
	if(ret != E_NOT_OK)
	{
		for(iread = 0;(iread < Bufflen) && (VaddressStart < FLASH_MAIN_MEMADDR_END);iread++)
		{
			Pbuffer[iread] = InFlashReadByte(VaddressStart);
			VaddressStart++;
		}
	}
	return ret;
}

结束

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值