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

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


文章目录

  • 嵌入式_基于STM32F4标准库的Flash读写操作
  • 前言
  • 一、STM32F4的 Flash 简介
  • 二、闪存的读写操作
    • 1.闪存的读取
    • 2.闪存的解锁、擦除和写入
      • 1.闪存解锁
      • 2.闪存擦除
      • 3.闪存写入
  • 三、完整代码


前言

在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;
}

结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/227537.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

整数二分的建模

当题目能够使用整数二分法建模时&#xff0c;主要有整数二分法思想进行判定&#xff0c;它的基本形式如下&#xff1a; while(left < right) {int ans;//记录答案 int mid left (right - left) / 2;//二分if(check(mid)){//检查条件&#xff0c;如果成立 ans mid;//记录…

学习spring、springmvc、mybatis、ssm所有可能用到的依赖总结,父工程pom文件依赖,<packaging>pom</packaging>

1、父工程pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/PO…

Java:UDP 通信方法(发送 + 接收)并 实现简单的聊天 详细代码

文章目录 UDP 通信编程发送 数据接收 数据实现简易的通信聊天 UDP 通信编程 发送 数据 创建 DatagramSocket 对象&#xff08;创办 快递公司&#xff09; 不传参&#xff0c;随机一个可用端口&#xff0c;传参&#xff0c;可指定端口。&#xff08;发送端口&#xff09;创建 …

Leetcode算法题笔记(1)

目录 哈希1. 两数之和1.1 解法11.1 解法2 2. 字母异位词分组2.1 解法12.2 解法2 3. 最长连续序列3.1 解法 小结 双指针4. 移动零4.1 解法14.2 解法2 5. 盛最多水的容器5.1 解法一5.2 解法二 6. 三数之和6.1 解法16.2 解法2 7. 接雨水7.1 解法1 小结 滑动窗口8. 无重复字符的最长…

随机Numpy数组的创建方法(第2讲)

随机Numpy数组的创建方法 &#xff08;第2讲&#xff09;         &#x1f379;博主 侯小啾 感谢您的支持与信赖。☀️ &#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&#x1f339;꧔ꦿ&…

代码随想录算法训练营 ---第五十八天

今天开启单调栈的征程。 第一题&#xff1a; 简介&#xff1a; 本题有两种解法&#xff0c;第一种&#xff1a;暴力破解 两层for循环 时间复杂度为O(n^2) 超时了 第二种&#xff1a;单调栈解法也是今天的主角。 单调栈是什么&#xff1f; 单调递增栈&#xff1a;单调递增栈…

在vue中深度选择器的使用

一、为什么要使用深度选择器 在vue中&#xff0c;当我们使用了第三方库中的组件时&#xff0c;想要更改一些样式&#xff0c;达到我们想要的效果&#xff0c;由于scoped的影响直接编写同名样式时&#xff0c;是覆盖不了组件内的样式的。 为了达到我们想要的效果&#xff0c;…

关于最长上升子序列的动态规划问题的优化算法(二分搜索)

最长递增子序列 暴力解法&#xff1a; 思路&#xff1a;使用动态规划的思想&#xff0c;判断当前元素之前的所有元素&#xff0c;如果比当前元素小&#xff0c;则修改当前元素的最长递增子序列&#xff08;需判断是否需要修改&#xff09;。 时间复杂度&#xff1a;O(n^2) im…

智能优化算法应用:基于天鹰算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于天鹰算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于天鹰算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天鹰算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

记一次Java内存溢出导致程序宕机的问题及排查

Hi, I’m Shendi 记一次Java内存溢出导致程序宕机的问题及排查 问题场景 今天在使用工具中的 word 转 pdf 出了问题&#xff0c;报502错误&#xff0c;打开服务器发现服务被关闭了&#xff0c;起初以为是误关&#xff0c;打开后重新转换又出现了这个问题&#xff0c;在项目文件…

Redis保证高可用的三种方式

Redis保证高可用主要有三种方式&#xff1a;主从、哨兵、集群。 主从复制了解吗&#xff1f; Redis主从复制简图 主从复制&#xff0c;是指将一台 Redis 服务器的数据&#xff0c;复制到其他的 Redis 服务器。前者称为 主节点(master)&#xff0c;后者称为 从节点(slave)。且…

【EXCEL】offset函数

语法&#xff1a; offset(reference,row,column,[height],[width]) 例子&#xff1a;

Java网络编程 *TCP与UDP协议*

网络编程 什么是计算机网络? 把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统 简单来说就是把不同地区的计算机通过设备连接起来,实现不同地区之前的数据传输 网络编程是干什么的? 网络…

UDS诊断 10服务

文章目录 简介诊断会话切换请求和响应1、请求2、子功能3、肯定响应4、否定响应5、特殊的NRC 为什么划分不同会话报文示例UDS中常用 NRC参考 简介 10服务&#xff0c;即 Diagnostic Session Control&#xff08;诊断会话控制&#xff09;服务用于启用服务器中的不同诊断会话&am…

【软件测试】系统测试

一、系统测试概念 系统测试&#xff08;System Testing&#xff09;是将已经集成好的软件系统&#xff0c;作为整个基于计算机系统的一个元素&#xff0c;与计算机硬件、外设、某些支持软件、数据和人员等其他元素结合在一起&#xff0c;在实际运行环境下&#xff0c;对计算机…

定兴县第三实验小学开展“宪法宣传周”系列活动

2023年12月4日是我国第十个国家宪法日&#xff0c;我校集中深入学习宣传宪法&#xff0c;弘扬宪法精神&#xff0c;维护宪法权威&#xff0c;开展“宪法宣传周”系列活动。 宪法主题升旗仪式 五&#xff08;6&#xff09;班薛谨熙同学以《学法懂法 与我同行》为主题做国旗下讲…

K-means算法通俗原理及Python与R语言的分别实现

K均值聚类方法是一种划分聚类方法&#xff0c;它是将数据分成互不相交的K类。K均值法先指定聚类数&#xff0c;目标是使每个数据到数据点所属聚类中心的总距离变异平方和最小&#xff0c;规定聚类中心时则是以该类数据点的平均值作为聚类中心。 01K均值法原理与步骤 对于有N个…

共创共赢|美创科技获江苏移动2023DICT生态合作“产品共创奖”

12月6日&#xff0c;以“5G江山蓝 算网融百业 数智创未来”为主题的中国移动江苏公司2023DICT合作伙伴大会在南京成功举办。来自行业领军企业、科研院所等DICT产业核心力量的百余家单位代表参加本次大会&#xff0c;共话数实融合新趋势&#xff0c;共拓合作发展新空间。 作为生…

9.关于Java的程序设计-基于Springboot的家政平台管理系统设计与实现

摘要 随着社会的进步和生活水平的提高&#xff0c;家政服务作为一种重要的生活服务方式逐渐受到人们的关注。本研究基于Spring Boot框架&#xff0c;设计并实现了一种家政平台管理系统&#xff0c;旨在提供一个便捷高效的家政服务管理解决方案。系统涵盖了用户注册登录、家政服…

Java se的语言特征之封装

目录 封装的概念常见的一些包静态成员变量代码块 封装的概念 可以理解为套壳屏蔽细节,将数据和操作数据的方法进行有机的结合,隐藏对象的属性和实现细节,仅对外公开接口和对象进行交互 从语法的层面来理解就是,被private修饰的成员变或者成员方法,只能在当前类中使用,但是可以…