STM32 HAL库之配置数据FLASH存储

news/2024/12/23 2:59:34 标签: stm32, 嵌入式硬件, 单片机

设计需求

        在项目开发中,经常需要保存配置数据至非易失性存储介质中(Flash 或EEPROM中),以便上电重启后获取配置信息。常见的STM32开发中,一般将数据存储在FLASH、备份区域寄存器、外挂EEPROM。由于内部Flash不能像EEPROM一样直接按字节进行读写操作,地址数据只能由1变为0,对固定地址重复写入,必须擦除整页使得地址数据为全FF,才可重新写入数据,通常为了提高内部FLASH的擦除寿命,一般采用内部flash模拟EEPROM方法。

FLASH概述

        本文以STM32F103VET6为例,介绍其内部512KByte的flash存储器。该处理器flash单元主要包括三个部分:存储单元、信息块部分、存储器相关控制寄存器。存储单元以page的形式组织,每页2Kbyte,共256页。信息块部分包括system memory(2Kbyte)和option byte(16Byte),system memory单元主要用于存储ST公司固化的bootloader,实现USART1串口更新用户程序。STM32F103VET6内部flash地址分配如下表所示。

需要注意的几点问题:

(1)、擦除和编程FLASH所需的高压是由STM32内部电路产生,且在此过程中内部晶振HSI需开启;

(2)、页写保护和读保护;

(3)、在写操作过程中,读操作将被挂起,待写操作完成后进行读操作。

2、Flash控制器FPEC —flash programming and erase controller

      默认情况下,内部的flash的FPEC和控制寄存器是处于写保护状态,要实现对FLASH的写操作,则首先unlock 存储器,即向寄存器FLASH_KEYR顺序写入两个key值。

    KEY1 = 0x45670123

    KEY2 = 0xCDEF89AB

FPEC控制器解锁后,通过查询FLASH_SR_BUSY位检查当前工作状态,配合FLASH_CR_PG、FLASH_CR_PER、FLASH_CR_MER分别实现对存储器的编程、页擦除、块擦除。

对于option byte的编程和擦除操作,首先对option byte部分解锁,即向FLASH_OPTKEY写入key值,配合FLASH_CR_OPTPG、FLASH_CR_OPTER实现对option byte进行编程和擦除操作。

3、option byte

选项字节主要用于配置flash的读写保护及看门狗,其分配地址如下:

RDP和WRPx分别用于内部flash的读保护、页写保护设置。系统复位后,the option byte loader—OBL自动加载option byte,并保存option byte 的部分数据至寄存器FLASH_OBR和FLASH_WRPR。RDP默认值为RDPRT key = 0x00A5,即处于非读保护状态。WRPx每位管理着2页的写保护状态。

上图可以看出:WRP0(对应寄存器FLASH_WRPR[7:0])的每位控制2页的写保护状态,共计16页;

WRP1(对应寄存器FLASH_WRPR[15:0])的每位控制2页的写保护状态,共计16页;

WRP2(对应寄存器FLASH_WRPR[23:16])的每位控制2页的写保护状态,共计16页;

WRP3(对应寄存器FLASH_WRPR[30:24])的每位控制2页的写保护状态,共计14页;

WRP3的最高位(对应寄存器FLASH_WRPR[31])控制页62至255页。

默认情况下,寄存器FLASH_WRPR的值均为0,即存储器处于写保护状态。若解除某一页存储器的写保护状态,需要对option byte进行擦除,并进行编程操作,完成后复位系统。

#define OB_BASE               ((uint32_t)0x1FFFF800)    /*!< Flash Option Bytes base address */

typedef struct
{
  __IO uint16_t RDP;
  __IO uint16_t USER;
  __IO uint16_t Data0;
  __IO uint16_t Data1;
  __IO uint16_t WRP0;
  __IO uint16_t WRP1;
  __IO uint16_t WRP2;
  __IO uint16_t WRP3;
} OB_TypeDef;

#define OB                  ((OB_TypeDef *) OB_BASE) 

4、访问存储器时间latency的设置

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }

应用1—操作FLASH

        使用__attribute__后,编译器自动将将所需的配置信息固化Flash地址中。

const uint16_t Version __attribute__((at(0x08010000)))= 0x1234;
const uint32_t Device_SN __attribute__((at(0x08010004))) = 0x55678911;

        重新变更FLASH中的SN序列号。

  /* USER CODE BEGIN 2 */
	FlashWrite(FLASH_TYPEPROGRAM_WORD, 0x08010004, 0x88992266);
  /* USER CODE END 2 */
void FlashWrite(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
	FLASH_EraseInitTypeDef EraseInitstruct =
	{
			.TypeErase = FLASH_TYPEERASE_PAGES,
			.NbPages = 1,
			.PageAddress = Address
	};
	uint32_t PageError = 0;
	HAL_FLASH_Unlock();
	HAL_FLASHEx_Erase(&EraseInitstruct, &PageError);
	HAL_FLASH_Program(TypeProgram, Address, Data);
	HAL_FLASH_Lock();
}

        从上面的结果可以看到,对SN序列号的更改导致了version也变成FF了,这是因为对flash地址数据变更时,必须对整页进行擦除。

应用2 — FLASH模拟EEPROM

        先聊聊本质。从应用1来看,要像读写EEPROM一样对FLASH固定地址的数据进行写操作,必须擦除整页的数据,而flash的擦除寿命是有限的,频繁的擦除势必会对MCU折损。flash模拟EEPROM策略就是对外提供虚拟物理地址,表面上看,可对同一地址进行重复写入,实质是在一页中按地址写入,当一页写满时,拷贝此页有效数据至另一页,并对此页进行整页擦除。以2K/页来说,4096/4 = 1024,即写入1024次后才会擦除一页,这样大大降低了FLASH擦除次数。

        Flash模拟EEPROM接口(官网示例)

uint16_t EE_Init(void);
uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);

        使用时需要重新定义如下几个条目。NumOfVar是写入uint16型的变量数目,VirtAddVarTab数组是定义的虚拟地址。

#define PAGE_SIZE  (uint16_t)0x800  /* Page size = 2KByte */

/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS    ((uint32_t)0x08010000) 

#define NumbOfVar               ((uint8_t)0x03)
/* Virtual address defined by the user: 0xFFFF value is prohibited */
uint16_t VirtAddVarTab[NumbOfVar] = {0x01, 0x02, 0x03};

          由于官方例子不是使用HAL库函数,需要在EEPROM源文件做一下封装兼容。

#define FLASH_COMPLETE  HAL_OK
#define FLASH_Status    HAL_StatusTypeDef

FLASH_Status FLASH_ErasePage(uint32_t PageAddr)
{
    uint32_t PageError = 0;
    FLASH_EraseInitTypeDef EraseInitstruct =
    {
        .TypeErase = FLASH_TYPEERASE_PAGES,
        .NbPages = 1,
        .PageAddress = PAGE0_BASE_ADDRESS
    };

    EraseInitstruct.PageAddress = PageAddr;
    return HAL_FLASHEx_Erase(&EraseInitstruct, &PageError);
}

#define FLASH_ProgramHalfWord(PageAddr, Data) \
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, (PageAddr), (Data))

        读写示例

	HAL_FLASH_Unlock();
	EE_Init();

	EE_WriteVariable(0x01, 0x3344);
	EE_WriteVariable(0x02, 0x5671);
	EE_WriteVariable(0x03, 0x8899);
	HAL_FLASH_Lock();

    

EE_ReadVariable(0x03, &ReadDat);

应用3 —— 程序加密

        待发.....


http://www.niftyadmin.cn/n/5796244.html

相关文章

“魔法糖果盒的秘密:用朴素贝叶斯算法猜糖果颜色”

想象一下&#xff0c;你有一个神奇的糖果盒&#xff0c;这个糖果盒里有两种糖果&#xff1a;红色的和蓝色的。你闭上眼睛&#xff0c;从盒子里拿出一个糖果&#xff0c;然后尝一尝&#xff0c;你想知道这个糖果是红色的还是蓝色的。朴素贝叶斯算法就像是一个魔法规则&#xff0…

Glide 自定义圆角、铺满FitXY

在 Android 开发中&#xff0c;使用 Glide 来加载图片时&#xff0c;有时需要对图片进行特定的处理&#xff0c;比如设置圆角或者使图片完全填充到一个视图中&#xff08;类似于 ImageView 的 scaleType 中的 FitXY&#xff09;。以下是如何使用 Glide 来实现这些自定义需求的处…

Linux —— 搭建Apache服务器

一、基本概念 定义 Apache 服务器&#xff08;全称 Apache HTTP Server&#xff09;是一款开源的、跨平台的 Web 服务器软件。它通过 HTTP 协议提供网页服务&#xff0c;能够将存储在服务器上的网页文件&#xff08;如 HTML 文件、图片、脚本等&#xff09;发送给客户端&#…

OpenAI发布全新AI模型 o3 与 o3-mini:推理与编码能力迎来重大突破. AGI 来临

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

鸿蒙UI开发——组件滤镜效果

1、概 述 ArkUI为组件提供了滤镜效果设置&#xff0c;背景滤镜、前景滤镜、合成滤镜。我们可以通过以下方式为组件设置对应的滤镜效果。 Text(前景滤镜)// ..其他属性.foregroundFilter(filterTest1) // 通过 foregroundFilter 设置模糊效果Text(背景滤镜)// ...其他属性.bac…

Python 写的 《监控视频存储计算器》

代码&#xff1a; import tkinter as tk from tkinter import ttk import math from tkinter.font import Fontclass StorageCalculator:def __init__(self, root):self.root rootself.root.title("监控视频存储计算器")self.root.geometry("600x800")s…

[JavaScript] 我该怎么去写一个canvas游戏

首先你得知道canvas的基础语法&#xff0c;此处不过多赘述. 一、如何更新视图 canvas里面有个clearRect方法&#xff0c;可以遮住画布中一个矩形部分. 但是你想这样做就难免会遮住一些本不该遮住的东西&#xff0c;因为它是一个矩形&#xff0c;并且你还要计算它的位置和尺寸…

【Mysql】函数有哪些

mysql函数有哪些&#xff1f; MySQL 提供了许多内置函数&#xff0c;用于执行各种操作&#xff0c;包括字符串处理、日期时间操作、数学计算、数据转换等。以下是一些常用的 MySQL 函数分类及其示例&#xff1a; 字符串函数 CONCAT(str1, str2, ...)&#xff1a;将多个字符串…