STM32内部Flash存贮数据的应用(STM32F446)

目录

概述

[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 功能测试

编译代码,下载到板卡中运行,仿真结果如下:

相关推荐
yutian06068 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程11 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉15 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名67715 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普16 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣16 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室16 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费16 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623118 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo201718 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范