目录
描述
复位后,闪存写入/擦除控制器处于锁定状态。要解锁它,请使用 FLASH_Unlock 函数。
在对所需地址进行写入之前,使用闪存擦除扇区功能执行擦除操作。是否有一个疑问,为什么要擦除才能写入,复杂的物理结构不提,简单的说,就是写入操作时可以把0->1,但无法从1->0.而且擦除的最小单元是扇区.通过填充擦除初始化结构来编程擦除过程(从第一个扇区到计算出的扇区数量进行扇区擦除)
然后通过调用 HAL_FLASHEx_Erase 函数逐个擦除所有这些扇区。
注意:如果某个扇区出现问题,擦除操作将停止,并将故障扇区返回给用户(通过变量“SectorError”)。
一旦此操作完成,将使用 HAL_FLASH_Program 函数执行写入操作。随后会检查写入的数据,并将编程操作的结果存储到 MemoryProgramStatus 变量中。
代码
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_2 /* 开始写入的区域 */
#define FLASH_USER_END_ADDR ADDR_FLASH_SECTOR_5 + GetSectorSize(ADDR_FLASH_SECTOR_5) -1 /* 用户闪存区域的结束位置 : sector start address + sector size -1 */
#define DATA_32 ((uint32_t)0x12345678)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t FirstSector = 0, NbOfSectors = 0, Address = 0;
uint32_t SectorError = 0;
__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
/*Variable used for Erase procedure*/
static FLASH_EraseInitTypeDef EraseInitStruct;
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static uint32_t GetSector(uint32_t Address);
static uint32_t GetSectorSize(uint32_t Sector);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
HAL_Init();
/* Configure the system clock to 84 MHz */
SystemClock_Config();
/* 解锁FLASH可以访问控制器寄存器 *************/
HAL_FLASH_Unlock();
/* 取得擦除的第一个扇区 */
FirstSector = GetSector(FLASH_USER_START_ADDR);
/* 从第一个扇区开始擦除的扇区数量*/
NbOfSectors = GetSector(FLASH_USER_END_ADDR) - FirstSector + 1;
/* 填写EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FirstSector;
EraseInitStruct.NbSectors = NbOfSectors;
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
{
/*
在执行扇区擦除操作时发生错误。
用户可以在此处添加一些代码来处理此错误。
“扇区错误”将包含故障扇区的信息,从而能够了解该扇区上的代码错误,
用户可以调用函数“HAL_FLASH_GetError()”来获取相关信息。
*/
/*
FLASH_ErrorTypeDef errorcode = HAL_FLASH_GetError();
*/
Error_Handler();
}
/* 注意:如果闪存中的擦除操作也涉及到数据或指令缓存中的数据,
则必须确保在代码执行期间访问这些数据之前,先对其进行重写。如果无法安全地做到这一点,建议通过在 FLASH_CR 寄存器中设置 DCRST 和 ICRST 位来刷新缓存。*/
__HAL_FLASH_DATA_CACHE_DISABLE();
__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
__HAL_FLASH_DATA_CACHE_RESET();
__HAL_FLASH_INSTRUCTION_CACHE_RESET();
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
__HAL_FLASH_DATA_CACHE_ENABLE();
/* 一个字一个字的写到用户区
(用户定义的 FLASH_USER_START_ADDR 和 FLASH_USER_END_ADDR) ***********/
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, DATA_32) == HAL_OK)
{
Address = Address + 4;
}
else
{
/*
FLASH_ErrorTypeDef errorcode = HAL_FLASH_GetError();
*/
Error_Handler();
}
}
/* 锁定闪存以禁用闪存控制寄存器的访问(此操作推荐用于保护闪存免受可能的不当操作影响) *********/
HAL_FLASH_Lock();
/* 检查所编写的数据是否正确
MemoryProgramStatus = 0:数据编入正确
MemoryProgramStatus != 0:有部分字节编入错误 ******/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = 0x0;
while (Address < FLASH_USER_END_ADDR)
{
data32 = *(__IO uint32_t*)Address;
if (data32 != DATA_32)
{
MemoryProgramStatus++;
}
Address = Address + 4;
}
/* Infinite loop */
while (1)
{
}
}
/**
* @brief Gets the sector of a given address
* @param None
* @retval The sector of a given address
*/
static uint32_t GetSector(uint32_t Address)
{
uint32_t sector = 0;
if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
{
sector = FLASH_SECTOR_0;
}
else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
{
sector = FLASH_SECTOR_1;
}
else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
{
sector = FLASH_SECTOR_2;
}
else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
{
sector = FLASH_SECTOR_3;
}
else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
{
sector = FLASH_SECTOR_4;
}
else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_5))*/
{
sector = FLASH_SECTOR_5;
}
return sector;
}
/**
* @brief Gets sector Size
* @param None
* @retval The size of a given sector
*/
static uint32_t GetSectorSize(uint32_t Sector)
{
uint32_t sectorsize = 0x00;
if((Sector == FLASH_SECTOR_0) || (Sector == FLASH_SECTOR_1) || (Sector == FLASH_SECTOR_2) || (Sector == FLASH_SECTOR_3))
{
sectorsize = 16 * 1024;
}
else if(Sector == FLASH_SECTOR_4)
{
sectorsize = 64 * 1024;
}
else
{
sectorsize = 128 * 1024;
}
return sectorsize;
}
HAL函数及结构体介绍
结构FLASH_EraseInitTypeDef
结构体定义
typedef struct {
uint32_t TypeErase; // 擦除类型:扇区擦除或全片擦除
uint32_t Banks; // 目标存储块(仅适用于双存储块设备)
uint32_t Sector; // 起始扇区编号
uint32_t NbSectors; // 要擦除的扇区数量
uint32_t VoltageRange; // 电压范围,用于设置操作位宽
} FLASH_EraseInitTypeDef;
字段说明
TypeErase 指定擦除类型,可选值: FLASH_TYPEERASE_SECTORS:仅扇区擦除。 FLASH_TYPEERASE_MASSERASE:闪存批量擦除激活。
Banks 指定目标存储块,仅适用于支持双存储块的设备(如 STM32F42x/43x 系列)。对于单存储块设备,此字段可忽略。仅适用于TypeErase为FLASH_TYPEERASE_MASSERASE
Sector 指定起始扇区编号,范围为 FLASH_SECTOR_0 至 FLASH_SECTOR_11(具体范围取决于芯片型号)。仅适用于TypeErase为FLASH_TYPEERASE_SECTORS
NbSectors 指定要擦除的扇区数量。需确保起始扇区和数量的组合在有效范围.
VoltageRange 指定操作电压范围,用于设置擦除和写入的位宽:
FLASH_VOLTAGE_RANGE_1:1.8V 至 2.1V,操作位宽为 8 位。
FLASH_VOLTAGE_RANGE_2:2.1V 至 2.7V,操作位宽为 16 位。
FLASH_VOLTAGE_RANGE_3:2.7V 至 3.6V,操作位宽为 32 位。
FLASH_VOLTAGE_RANGE_4:外部 Vpp,操作位宽为 64位. 最大操作位数会影响擦除和写入的速度,其中64位宽度的操作除了配置寄存器位外,还需要在Vpp引脚外加一个8-9V的电压源,且其供电时间不得超过一小时,否则FLASH可能损坏,所以64位宽度的操作一般是在量产时对FLASH写入应用程序时才使用,大部分应用场合都是用32位的宽度。
擦除函数
函数名称
函数描述
执行闪存批量或特定扇区擦除
参数
pEraseInit:指向一个“FLASH_EraseInitTypeDef”结构的指针,该结构包含了擦除的配置信息。就是上面解释的结构体.
SectorError:指向一个变量的指针,该变量在出现错误时包含故障扇区的配置信息(0xFFFFFFFFU 表示所有扇区均已正确擦除)如果想知道具体错误信息,调用函数HAL_FLASH_GetError()
编程(写入)函数
函数名称
HAL_StatusTypeDef HAL_FLASH_Program (uint32_t TypeProgram, uint32_t Address, uint64_t Data)
描述
在指定地址处读取字节、半字、字或双字的数据。
参数
• TypeProgram:程序设置:指示在指定地址处进行程序设置的方式。此参数可以是“闪存程序设置”这一值。
FLASH_TYPEPROGRAM_BYTE 字节(8位)
FLASH_TYPEPROGRAM_HALFWORD 半字(16位)
FLASH_TYPEPROGRAM_WORD 字(32位)
FLASH_TYPEPROGRAM_DOUBLEWORD 双字(64位)
• Address:指定要进行程序设置的地址。
• Data:指定要进行程序设置的数据。
解锁函数
函数名称
HAL_StatusTypeDef HAL_FLASH_Unlock (void )
描述
解锁 FLASH 控制寄存器访问。
上锁函数
函数名称
HAL_StatusTypeDef HAL_FLASH_Lock (void )
描述
锁 FLASH 控制寄存器访问。
取得FLASH错误标志
函数名称
uint32_t HAL_FLASH_GetError (void )
返回值
闪存错误代码:返回的值可以是以下几种情况的组合:
– HAL_FLASH_ERROR_RD:闪存读保护错误标志(PCROP)
– HAL_FLASH_ERROR_PGS:闪存编程序列错误标志
– HAL_FLASH_ERROR_PGP:闪存编程并行性错误标志
– HAL_FLASH_ERROR_PGA:闪存编程对齐错误标志
– HAL_FLASH_ERROR_WRP:闪存写保护错误标志
– HAL_FLASH_ERROR_OPERATION:闪存操作错误标志
FLASH的空闲区间在哪里?
请看另一篇文章
5187

被折叠的 条评论
为什么被折叠?



