赞
踩
在STM32芯片内有一个Flash存储器断电后数据不会丢失,所以Flash中经常存储一些关键数据,例如:运行的程序、属性文件、密钥、累计运行时间、故障日志等,所以Falsh读写操作非常重要。
<1>、硬件平台:STM32F407
<2>、软件平台:本例程是基于使用标准STM32F4xx_DSP_StdPeriph_Lib_V1.4.0固件库编写,
不同型号的 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 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。
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; }
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.解锁原理: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; } }
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)
参数为所要擦除的扇区编号和设备匹配电压,在本文最后给出的完成代码中,我们也从新包装了擦除函数,即给出随意合法地址,然后自动算出该地址所在扇区并进行解锁擦除该扇区
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; }
结束
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。