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

news2025/1/10 16:07:45

目录

概述

1 STM32内部Flash介绍

1.1 MCU简介

1.2 存储空间

1.3 主要特性

1.4 嵌入式闪存 

2 库函数介绍

2.1 编程接口函数

2.2  锁和解锁函数

3 功能实现

3.1 写数据函数:FlashDrv_Write

3.2 读数据函数: FlashDrv_read

3.3 源代码

4 测试

4.1 编写测试函数

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 编程接口函数

函数原型:

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函数

函数原型:

HAL_StatusTypeDef HAL_FLASH_Lock(void);

功能介绍: 锁定FLASH控制寄存器访问

2) HAL_FLASH_Unlock函数

函数原型:

HAL_StatusTypeDef HAL_FLASH_Unlock(void);

功能介绍:解锁FLASH控制寄存器访问

3 功能实现

3.1 写数据函数:FlashDrv_Write

函数原型:

HAL_StatusTypeDef FlashDrv_Write(uint32_t Addr, uint8_t *source, uint32_t length)

参数介绍:

addr: 写数据的首地址

source:    数据指针

length: 数据长度 

3.2 读数据函数: FlashDrv_read

函数原型:

uint32_t FlashDrv_read(uint32_t Addr, uint8_t *source, uint32_t length)

参数介绍:

addr: 读数据的首地址

source:    数据指针

length: 数据长度 

3.3 源代码

1) 创建FlashDrv.c文件,编写如下代码:

/* 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文件,编写如下代码:

/* 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 */

源代码如下:


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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1969305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

carla unreal engine源码:如何自定义开发传感器

文章目录 前言一、目标二、代码内容三、工程搭建1、更改点总览2、工程修改1&#xff09;代码文件拷贝至目标路径2&#xff09;SafeDistanceSensor.cpp 修改3&#xff09;SafeDistanceSerializer.h 修改4&#xff09;SafeDistanceEvent.h 修改5&#xff09;Sensor.h 修改6&#…

大数据技术原理-NoSQL数据库的应用

摘要 本实验报告聚焦于"大数据技术原理"课程中的NoSQL数据库实验。实验环境包括MySQL、Redis、MongoDB、Java以及Hadoop。实验内容涉及Redis和MongoDB的安装、配置和基本操作&#xff0c;包括数据的插入、删除和查询。此外&#xff0c;实验还包括使用Java API对Mong…

【统计全为 1 的正方形子矩阵】python刷题记录

R3-分治篇 class Solution:def countSquares(self, matrix: List[List[int]]) -> int:rowlen(matrix)collen(matrix[0])dp[[0]*(col1) for _ in range(row1)]ret0for i in range(row):for j in range(col):if matrix[i][j]1:dp[i1][j1]min(dp[i][j1],dp[i1][j],dp[i][j])1re…

umi-request全局响应拦截器

文章目录 介绍思路实现方法1.直接修改 umi-request方法2.自定义 request 实例&#xff0c;通过 umi-request 库进行配置 介绍 后端设计统一返回比如BaseResponse对象&#xff0c;前端也需要接收这个对象&#xff0c;从data取出想要的返回值。 前端请求比如之前返回的是numbe…

windows子系统wsl完成本地化设置locale,LC_ALL

在 Windows 的子系统 Linux&#xff08;WSL&#xff09;环境中&#xff0c;解决本地化设置问题可以采取以下步骤&#xff1a; 1. **检查本地化设置**&#xff1a; 打开你的 WSL 终端&#xff08;比如 Ubuntu、Debian 等&#xff09;&#xff0c;运行以下命令来查看当前的本…

大数据技术基础编程、实验和案例----大数据课程综合实验案例

一、实验目的 (1&#xff09;熟悉Linux系统、MySQL、Hadoop、HBase、Hive、Sqoop、R、Eclipse等系统和软件的安装和使用&#xff1b; (2&#xff09;了解大数据处理的基本流程&#xff1b; (3&#xff09;熟悉数据预处理方法&#xff1b; (4&#xff09;熟悉在不同类型数据库之…

湖南(用户洞察)源点咨询 论用户画像于精准营销之意义作用

湖南源点市场调研咨询认为&#xff0c;精准描摹用户画像是实现有效获客的重要方法。 因为只有通过用户画像&#xff0c;我们才能够持续不断了解用户现阶段的需求&#xff0c;痛点以及偏好。 用户画像不是简单的理解为对人群打标签&#xff0c;而是要通过大量的数据采集和分析…

螺旋文字滚动特效源码解析

如图所示&#xff0c;今天看到一个很炫酷的双文字螺旋滚动特效&#xff0c;两行文字呈螺旋状变化&#xff0c;在网站中这样的效果对用户很有吸引力。本文将基于原网站解析如何实现这个炫酷的效果&#xff0c;基于这个动图可以分析出需要实现的要点&#xff1a; 文字呈螺旋状滚…

管理流创建schema流程源码解析

一、简析 schema是pulsar重要的功能之一&#xff0c;现在就一起从源码的视角看下管理流创建schema时客户端和服务端的表现 客户端 客户端主要经历以下四个步骤 创建Schema实例 根据数据类型创建相对应的实例&#xff0c;例如Avro创建AvroSchema、JSON创建JSONSchema等 获取…

1.1、centos stream 9安装Kubernetes v1.30集群 环境说明

最近正在学习kubernetes&#xff0c;买了一套《Kubernetes权威指南 从Docker到Kubernetes实践全接触(第六版)》这本书讲得很好&#xff0c;上下两册&#xff0c;书中k8s的版本是V1.29&#xff0c;目前官网最新版本是v1.30。强烈建议大家买一套看看。 Kubernetes官网地址&#x…

jenkins使用docker api配置自签证书 +发布项目

配置证书 1、创建目录/etc/docker/certs&#xff0c; 在该目录下执行下列命令 openssl genrsa -aes256 -out ca-key.pem 4096 openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pemopenssl genrsa -out server-key.pem 4096 \ openssl req -subj "/…

常见的应急救援设备有哪些_鼎跃安全

在我们的生活中&#xff0c;应急事件的发生常常是突如其来的&#xff0c;它们对人民的生命财产安全构成重大威胁&#xff0c;同时也对社会稳定提出严峻挑战。在这样的紧急情况下&#xff0c;迅速开展有效的救援工作显得尤为重要。而在整个救援过程中&#xff0c;应急设备的使用…

【简历】湘南某二本学院:前端简历指导,秋招面试通过率低

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份25届二本同学的前端简历&#xff0c;但是这个简历&#xff0c;因为学校是个二本的专业&#xff0c;虽然说主体是在小公司&#x…

计算机基础(Windows 10+Office 2016)教程 —— 第6章 电子表格软件Excel 2016(下)

电子表格软件Excel 2016 6.4 Excel 2016的公式与函数6.4.1 公式的概念6.4.2 公式的使用6.4.3 单元格的引用6.4.4 函数的使用6.4.5 快速计算与自动求和 6.5 Excel 2016的数据管理6.5.1 数据排序6.5.2 数据筛选6.5.3 分类汇总6.5.4 分组显示6.5.5 合并计算 6.6 Excel 2016的图表6…

什么品牌的开放式耳机好用?南卡、韶音、漫步者 三款口碑超群机型横评

现如今耳机几乎成为了日常标配&#xff0c;因为选择合适的耳机成为我们不可忽视的需求。开放式耳机凭借其既能沉浸于高品质音乐&#xff0c;又能保持对周围环境的敏锐感知的独特优势&#xff0c;在市场中脱颖而出&#xff0c;尤其受到运动爱好者及追求生活品质的朋友们的喜爱。…

风吸杀虫灯采用新型技术 无公害诱虫捕虫

TH-FD2S】风吸杀虫灯利用害虫的趋光性和对特定波长的光源&#xff08;如紫外光、蓝光&#xff09;的敏感性&#xff0c;通过光波引诱害虫成虫扑灯。同时&#xff0c;内置的风扇产生强烈的气流&#xff0c;形成负压区&#xff0c;将害虫迅速吸入到收集器中。害虫在收集器内被风干…

排序算法:快速排序,golang实现

目录 前言 快速排序 代码示例 1. 算法包 2. 快速排序代码 3. 模拟程序 4. 运行程序 5. 从大到小排序 快速排序的思想 快速排序的实现逻辑 1. 选择基准值 (Pivot) 2. 分区操作 (Partition) 3. 递归排序 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行…

从入门到自动化:一篇文章掌握Python的80%

Python作为一种高级编程语言&#xff0c;以其简洁明了的语法和强大的功能性&#xff0c;在全球编程社区内享有极高的声誉。本文将带领你从Python的基础语法入手&#xff0c;介绍其常用库的应用&#xff0c;以及如何将Python用于数据分析、网络爬虫和简单的自动化任务&#xff0…

模板(c++)part2

目录 1.非类型模板参数 2.特化 2.1函数模板特化 2.2类模板特化 2.2.1全特化 2.2.2偏特化 3.模板分离编译 1.非类型模板参数 注意&#xff0c;假如 #define N 10 template<class T> class A { private:T a[N]; }; 这样的一个类模板&#xff0c;a数组的大小是定死的 …

canvas绘制表格

canvas绘制表格 最近在为公司产品做技术预研&#xff0c;经理让用canvas做一个表格&#xff0c;于是就有了这篇博客。 我们的数据是后端通过MQTT推送过来的 我在代码中也直接使用了 具体MQTT的实现代码&#xff0c;可见博客 在vue使用MQTT 在这里为了方便实用我直接封装成组件…