嵌入式_基于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;
}
结束