FLASH的简单应用
FLASH的简单应用(后续)
1、简介
- Flash存储器(Flash Memory)是一种非易失性内存器件,断电后可长期保存数据。其主要分为NOR和NAND两类技术:NOR Flash由Intel于1988年推出,支持直接执行代码,读取速度快,适用于嵌入式系统等小容量代码存储场景;NAND Flash由东芝于1989年提出,存储密度高、成本低,擦写速度快,适用于固态硬盘(SSD)、U盘等大容量数据存储领域。
两类闪存均基于浮栅晶体管结构,通过隧道效应实现数据擦写。NOR采用并行结构和热电子注入方式,支持字节级随机访问,但单元尺寸较大;NAND采用串行结构,以页/块为单位操作,单元尺寸更小且集成度高,但需配合ECC纠错和坏块管理机制。NOR适用于对代码可靠性要求高的场景,NAND则在消费电子和移动存储领域占据主导地位,其技术演进涵盖从2D到3D堆叠架构,显著提升了存储密度与性能。
2、操作方法(HAL库)
(1)初始化
- 使能串口
![img]()
- 在
Inc中新建myflash.h并定义以下函数
void MyFLASHProgramInit(uint64_t data);
uint32_t MyFLASH_Read(uint32_t Address);
- 在主函数外部声明该函数
//用于写入初始化的函数,参数为要写入的字符
void MyFLASHProgramInit(uint64_t data){
HAL_FLASH_Unlock();//解锁FLASH
// 擦除 Sector 5,这里得具体看芯片哪块扇区允许操作
/*----------初始化用于删除的结构体---------------*/
FLASH_EraseInitTypeDef erase = {0};
uint32_t SectorError;//定义报错类型
erase.TypeErase = FLASH_TYPEERASE_SECTORS;//选择"删除种类为'扇区删除'"
erase.Sector = FLASH_SECTOR_5;//选择删除的为"第五扇区"
erase.NbSectors = 1;//选择删除的扇区数量
erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;//选择删除的电压级别
erase.Banks = FLASH_BANK_1;//选择存储区为Bank_1
//如果擦除成功,就进行写入操作
if (HAL_FLASHEx_Erase(&erase, &SectorError) == HAL_OK) {
// 写入数据(8 位)
HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, ADDR_FLASH_SECTOR_5, data);
}
HAL_FLASH_Lock();//锁住FLASH
}
//用于读取该位置是否存在数据的函数,会返回该地址的数值
uint32_t MyFLASH_Read(uint32_t Address){
return *((__IO uint32_t *)(Address));
}
/* USER CODE END 0 */
为了安全起见,操作FLASH时应当按照以下步骤:
解锁FLASH→操作→锁上FLASH
(2)写入代码
- 在主函数内部声明该字符串:
/* USER CODE BEGIN 1 */
char message[] = "Notempty";
/* USER CODE END 1 */
- 在主循环外部写入以下内容:
//判断指定区域是否为空
if(MyFLASH_Read(ADDR_FLASH_SECTOR_4) != 0){
//如果不为空,则输出"Notempty"
HAL_UART_Transmit(&huart2, message, strlen(message), HAL_MAX_DELAY);
}
//写入字符'a'
MyFLASHEraseInit('a');
char chr = MyFLASH_Read(ADDR_FLASH_SECTOR_4);//读取该FLASH地址的值
- 在主循环写入以下内容
while (1)
{
//同过串口询问已写入地址处的值
HAL_UART_Transmit(&huart2, &chr, 1, HAL_MAX_DELAY);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
(3)烧录效果
(i)烧录程序后,会先查询指定扇区是否为空,若为空则输出Notempty
(ii) 之后会在指定扇区写入字符
(iii)完成写入操作后每隔一秒会由串口传输指定地址的数据

3、代码清单
/*-----------------用于FLASH删除初始化的结构体-------------------*/
typedef struct
{
uint32_t TypeErase; /*选择"大量删除"(mass erase),还是"块删除"(sector erase)*/
uint32_t Banks; /*选择要删除的存储区*/
uint32_t Sector; /*当"大量删除"被禁用后,用于初始化指定删除的扇区*/
uint32_t NbSectors; /*指定要删除的扇区数量*/
uint32_t VoltageRange;/*指定要选择的删除电压*/
} FLASH_EraseInitTypeDef;
#define FLASH_TYPEERASE_SECTORS 0x00000000U /*仅删除扇区*/
#define FLASH_TYPEERASE_MASSERASE 0x00000001U /*把整个芯片的FLASH都删除了*/
#define FLASH_VOLTAGE_RANGE_1 0x00000000U /*操作电压等级: 1.8V 到 2.1V */
#define FLASH_VOLTAGE_RANGE_2 0x00000001U /*操作电压等级: 2.1V 到 2.7V */
#define FLASH_VOLTAGE_RANGE_3 0x00000002U /*操作电压等级: 2.7V 到 3.6V */
#define FLASH_VOLTAGE_RANGE_4 0x00000003U /*操作电压等级” 2.7V 到 3.6V + 外部电源 */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) //指定的扇区
//解锁FLASH寄存器的函数
HAL_StatusTypeDef HAL_FLASH_Unlock(void)
{
HAL_StatusTypeDef status = HAL_OK;
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
/* Authorize the FLASH Registers access */
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
/* Verify Flash is unlocked */
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
status = HAL_ERROR;
}
}
return status;
}
//锁定FLASH寄存器的函数
HAL_StatusTypeDef HAL_FLASH_Lock(void)
{
/* Set the LOCK Bit to lock the FLASH Registers access */
FLASH->CR |= FLASH_CR_LOCK;
return HAL_OK;
}
//写入FLASH的函数,需要写入类型"TyprProgram",指定地址"Address",指定数据"Data"
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
HAL_StatusTypeDef status;
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
if (status == HAL_OK)
{
if (TypeProgram == FLASH_TYPEPROGRAM_BYTE)
{
/*Program byte (8-bit) at a specified address.*/
FLASH_Program_Byte(Address, (uint8_t) Data);
}
else if (TypeProgram == FLASH_TYPEPROGRAM_HALFWORD)
{
/*Program halfword (16-bit) at a specified address.*/
FLASH_Program_HalfWord(Address, (uint16_t) Data);
}
else if (TypeProgram == FLASH_TYPEPROGRAM_WORD)
{
/*Program word (32-bit) at a specified address.*/
FLASH_Program_Word(Address, (uint32_t) Data);
}
else
{
/*Program double word (64-bit) at a specified address.*/
FLASH_Program_DoubleWord(Address, Data);
}
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
/* If the program operation is completed, disable the PG Bit */
FLASH->CR &= (~FLASH_CR_PG);
}
}
注意:烧录该程序后再次从CubeIDE中烧录其他程序会导致报错,需要用KEIL烧录程序后才行。疑似因为CubeIDE烧录时并未全部擦除FLASH数据,等我研究一下再发后续
后续来了,把同样程序用Keil编译完执行到HAL_UART_Transmit(&huart2, ADDR_FLASH_SECTOR_5, 1, HAL_MAX_DELAY);后,单片机就卡死了
我后面看来一下,传输的地址要求为const uint8_t *,FLASH的地址是uint32_t,不符合要求
疑似是GCC编译器在编译代码时优化了这个问题,而KEIL的ARMCC编译器没有优化,导致执行到该区域后单片机卡死
所以需要中间变量char c来读取FLASH处数据,然后再使用串口传输的函数传输该中间变量的值


浙公网安备 33010602011771号