目录
[1 STM32内部Flash介绍](#1 STM32内部Flash介绍)
[1.1 MCU简介](#1.1 MCU简介)
[1.2 存储空间](#1.2 存储空间)
[1.3 主要特性](#1.3 主要特性)
[1.4 嵌入式闪存](#1.4 嵌入式闪存)
[2 库函数介绍](#2 库函数介绍)
[2.1 编程接口函数](#2.1 编程接口函数)
[2.2 锁和解锁函数](#2.2 锁和解锁函数)
[3 功能实现](#3 功能实现)
[3.1 写数据函数:FlashDrv_Write](#3.1 写数据函数:FlashDrv_Write)
[3.2 读数据函数: FlashDrv_read](#3.2 读数据函数: FlashDrv_read)
[3.3 源代码](#3.3 源代码)
[4 测试](#4 测试)
[4.1 编写测试函数](#4.1 编写测试函数)
[4.2 功能测试](#4.2 功能测试)
概述
本文主要介绍使用STM32的内部Flash实现数据存储功能,笔者基于STM32F446芯片,使用Hal库中的接口,实现数据的读写功能。
1 STM32内部Flash介绍
1.1 MCU简介
STM32F446使用Arm®32位Cortex®-M4 CPU,自带FPU;适应实时加速器(ART)加速器)允许零等待状态执行从闪存,频率高达180兆赫,MPU, 225 DMIPS/1.25 DMIPS/MHz(Dhrystone 2.1)和DSP指令。
1.2 存储空间
Flash空间大小:512kb的闪存
RAM空间:128kb的SRAM
扩展总线: 灵活的外部存储控制器与up到16位数据总线:SRAM, PSRAM,Sdram / lpsdr Sdram,而不是/ nand闪光的记忆
外部Flash总线:双模QuadSPI接口
1.3 主要特性
1)闪存读取操作
2)闪存程序/擦除操作
3)读写保护
4)I-Code预取
5)在I-Code上有64条128位的缓存线
6)8条128位D-Code高速缓存线
1.4 嵌入式闪存
其主要特性如下:
1)容量最大可达512kbytes
2)128位宽数据读取:字节、半字、字和双字书写
3)扇区和质量擦除
4)内存组织
5)Flash内存的组织方式如下:
-主内存块分为4个16 kb的扇区,1个64 kb的扇区,
6)3个128 kb的扇区
---系统内存引导方式下设备启动时使用的系统内存
7)512 OTP(一次性可编程)字节用于用户数据
OTP区域包含16个额外的字节,用于锁定相应的OTP数据块。
8)---选项字节用于配置读写保护、BOR级别、看门狗
9)软件/硬件和复位时,设备处于待机或停止模式。
10)低功耗模式(详细信息请参见参考文献的电源控制(PWR)部分)手动)
2 库函数介绍
2.1 编程接口函数
函数原型:
cpp
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
功能介绍:
/ * *
功能: 程序字节,半字,字或双字在指定地址
参数:TypeProgram : 表示在指定地址进行编程的方式。该参数可以是FLASH_Type_Program的值
Address: 指定要编程的地址。
Data: 指定要编程的数据
返回值: HAL_StatusTypeDef HAL状态
2.2 锁和解锁函数
1)HAL_FLASH_Lock函数
函数原型:
cpp
HAL_StatusTypeDef HAL_FLASH_Lock(void);
功能介绍: 锁定FLASH控制寄存器访问
2) HAL_FLASH_Unlock函数
函数原型:
cpp
HAL_StatusTypeDef HAL_FLASH_Unlock(void);
功能介绍:解锁FLASH控制寄存器访问
3 功能实现
3.1 写数据函数:FlashDrv_Write
函数原型:
cpp
HAL_StatusTypeDef FlashDrv_Write(uint32_t Addr, uint8_t *source, uint32_t length)
参数介绍:
addr: 写数据的首地址
source: 数据指针
length: 数据长度
3.2 读数据函数: FlashDrv_read
函数原型:
cpp
uint32_t FlashDrv_read(uint32_t Addr, uint8_t *source, uint32_t length)
参数介绍:
addr: 读数据的首地址
source: 数据指针
length: 数据长度
3.3 源代码
1) 创建FlashDrv.c文件,编写如下代码:
cpp
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : FlashDrv.c
* Description : falsh driver base on stm32f446
******************************************************************************
* @attention
*
* COPYRIGHT: Copyright (c) 2024 tangminfei2013@126.com
* DATE: JUL 05th, 2024
******************************************************************************
*/
/* USER CODE END Header */
#include "FlashDrv.h"
#include "stdio.h"
/* Start @ of user Flash area */
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_2
/* End @ of user Flash area : sector start address + sector size -1 */
#define FLASH_USER_END_ADDR ADDR_FLASH_SECTOR_7 + GetSectorSize(ADDR_FLASH_SECTOR_7) -1
#define FLASH_TIMEOUT_VALUE 1000
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;
}
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 if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
{
sector = FLASH_SECTOR_5;
}
else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
{
sector = FLASH_SECTOR_6;
}
else /* (Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_7) */
{
sector = FLASH_SECTOR_7;
}
return sector;
}
HAL_StatusTypeDef FlashDrv_Write(uint32_t Addr, uint8_t *source, uint32_t length)
{
uint32_t FirstSector = 0, NbOfSectors = 0;
HAL_StatusTypeDef FlashStatus = HAL_OK;
uint32_t SECTORError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
int trycnt = 0;
int i;
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
/* Get the bank */
FirstSector = GetSector(Addr);
NbOfSectors = GetSector(FLASH_USER_END_ADDR) - FirstSector + 1;
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FirstSector;
EraseInitStruct.NbSectors = NbOfSectors;
do
{
FlashStatus = HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError);
if( FlashStatus != HAL_OK)
{
/* Infinite loop */
trycnt++;
if( trycnt > 3 )
{
HAL_FLASH_Lock();
return FlashStatus;
}
}
else
break;
FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
}while( trycnt < 3);
__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();
FlashStatus = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE); // Wait for a FLASH operation to complete.
if( FlashStatus == HAL_OK )
{
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
for ( i = 0; i < length; i += 4)
{
trycnt = 0;
do{
FlashStatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Addr + i, *(uint32_t *)(source + i));
}while( trycnt < 3 && FlashStatus != HAL_OK);
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return HAL_OK;
}
uint32_t FlashDrv_read(uint32_t Addr, uint8_t *source, uint32_t length)
{
int i;
for ( i = 0; i < length; i++)
{
source[i] = *(__IO uint8_t *)(Addr + i);
}
return 1;
}
/* End of this file */
2) 创建FlashDrv.h文件,编写如下代码:
cpp
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : FlashDrv.h
* Description : falsh driver base on stm32f446
******************************************************************************
* @attention
*
* COPYRIGHT: Copyright (c) 2024 tangminfei2013@126.com
* DATE: JUL 05th, 2024
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#ifndef __FLASHDRV_H
#define __FLASHDRV_H
/*****************************************************************************/
/* Includes */
/*****************************************************************************/
#include "main.h"
#ifdef _cplusplus
extern "C" {
#endif
#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 */
HAL_StatusTypeDef FlashDrv_Write(uint32_t Addr, uint8_t *source, uint32_t length);
uint32_t FlashDrv_read(uint32_t Addr, uint8_t *source, uint32_t length);
#ifdef _cplusplus
}
#endif
#endif /* __FLASHDRV_H */
4 测试
4.1 编写测试函数
功能介绍:
1)定义两个数据,数组长度为2048
2) 从如下地址开始写数据
ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base address of Sector 6, 128 Kbytes */
源代码如下:
cpp
#define LEN 2048
uint8_t buff[LEN];
uint8_t rbuff[LEN];
void debug_testflash( void )
{
int i;
for ( i = 0; i < LEN; i++)
{
buff[i] = i;
}
FlashDrv_Write(ADDR_FLASH_SECTOR_6, buff , LEN );
FlashDrv_read(ADDR_FLASH_SECTOR_6,rbuff , LEN);
for ( i = 0; i < LEN; i++)
{
if(buff[i] != rbuff[i])
{
printf(" data error \r\n");
return;
}
}
printf(" match data: pass \r\n");
}
4.2 功能测试
编译代码,下载到板卡中运行,仿真结果如下: