首页 > 其他分享 >stm32 FLASH闪存(读写内部FLASH&读取芯片ID)

stm32 FLASH闪存(读写内部FLASH&读取芯片ID)

时间:2024-09-22 09:50:18浏览次数:3  
标签:闪存 void FLASH stm32 MyFLASH Data uint32 Store

理论

1.FLASH简介

STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)(FLASH管理员)可以对程序存储器和选项字节进行擦除和编程

读写FLASH的用途:

    利用程序存储器的剩余空间来保存掉电不丢失的用户数据   

    通过在程序中编程(IAP),实现程序的自我更新

在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG(stm32特有协议)、SWD协议(通用协议)或系统加载程序(Bootloader)下载程序

在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序

2.闪存模块组织

主存储器与信息块:真正的闪存

闪存存储器接口存储器:进行擦除和编程的地方

3.FLASH基本结构

系统存储区不可以进行任何的写入操作

选项字节可以对程序存储器进行配置读写保护 

 4.FLASH解锁

FPEC共有三个键值:

  RDPRT键 = 0x000000A5(解除读保护)

  KEY1 = 0x45670123

  KEY2 = 0xCDEF89AB

解锁:

    复位后,FPEC被保护,不能写入FLASH_CR   

    在FLASH_KEYR先写入KEY1,再写入KEY2,解锁   

    错误的操作序列会在下次复位前锁死FPEC和FLASH_CR

加锁:

    设置FLASH_CR中的LOCK位锁住FPEC和FLASH_CR

 5.使用指针访问存储器

使用指针读指定地址下的存储器:

uint16_t Data = *((__IO uint16_t *)(0x08000000));

_IO是指在此位置不要进行优化操作

传入0x8000000强转为 uint16_t的指针类型

 使用指针写指定地址下的存储器:

*((__IO uint16_t *)(0x08000000)) = 0x1234;

 _IO是指在此位置不要进行优化操作

 __IO :

#define    __IO    volatile

指的是对代码进行优化 

6.程序存储器

(1)程序存储器编程

补充:

字       32位

半字   16位

字节   8  位

先进行解锁,然后向系统发送我们即将要写入数据,在指定的位置写入半字,然后进行等待操作

(2)程序存储器页擦除 

进行解锁操作,FLASH_CR的STRT=1芯片开始干活,FALSH_CR PER=1进行页擦除,FALSH_AR选择擦除的页(指定页),等待擦除完成

(3)程序存储器全擦除

进行解锁操作,FLASH_CR的STRT=1芯片开始工作,FALSH_CR的MER=1进行全擦除,等待擦除完成

7.选项字节

RDP:写入RDPRT键(0x000000A5)后解除读保护

USER:配置硬件看门狗和进入停机/待机模式是否产生复位

Data0/1:用户可自定义使用

WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量) 

(1)选项字节编程

检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作

解锁FLASH_CR的OPTWRE位

设置FLASH_CR的OPTPG位为1

写入要编程的半字到指定的地址

等待BSY位变为0

读出写入的地址并验证数据

(2)选项字节擦除

检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作

解锁FLASH_CR的OPTWRE位

设置FLASH_CR的OPTER位为1

设置FLASH_CR的STRT位为1

等待BSY位变为0

读出被擦除的选择字节并做验证

8.器件电子签名

电子签名存放在闪存存储器模块的系统存储区域,包含的芯片识别信息在出厂时编写,不可更改,使用指针读指定地址下的存储器可获取电子签名

闪存容量寄存器:

    基地址:0x1FFF F7E0

    大小:16位

产品唯一身份标识寄存器:

    基地址: 0x1FFF F7E8  

    大小:96位

API学习

1.FLASH_Unlock

void FLASH_Unlock(void);

进行解锁FLASH操作

2.FLASH_ErasePage

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

进行页的擦除

3.FLASH_EraseAllPages

FLASH_Status FLASH_EraseAllPages(void);

进行FLASH的全擦除 

4.FLASH_ProgramWord

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);

进行字(32位)的写入

5.FLASH_ProgramHalfWord

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

进行半字(16位)的写入

代码

读写内部FLASH

MyFLASH.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个16位的半字
  * 参    数:Address 要读取数据的半字地址
  * 返 回 值:指定地址下的数据
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
	return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个8位的字节
  * 参    数:Address 要读取数据的字节地址
  * 返 回 值:指定地址下的数据
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
	return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH全擦除
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
  */
void MyFLASH_EraseAllPages(void)
{
	FLASH_Unlock();					//解锁
	FLASH_EraseAllPages();			//全擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH页擦除
  * 参    数:PageAddress 要擦除页的页地址
  * 返 回 值:无
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
	FLASH_Unlock();					//解锁
	FLASH_ErasePage(PageAddress);	//页擦除
	FLASH_Lock();					//加锁
}

/**
  * 函    数:FLASH编程字
  * 参    数:Address 要写入数据的字地址
  * 参    数:Data 要写入的32位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramWord(Address, Data);		//编程字
	FLASH_Lock();							//加锁
}

/**
  * 函    数:FLASH编程半字
  * 参    数:Address 要写入数据的半字地址
  * 参    数:Data 要写入的16位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
	FLASH_Unlock();							//解锁
	FLASH_ProgramHalfWord(Address, Data);	//编程半字
	FLASH_Lock();							//加锁
}

MyFLASH.h

#ifndef __MYFLASH_H
#define __MYFLASH_H

uint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);

void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);

void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

#endif

Store.h

#ifndef __STORE_H
#define __STORE_H

extern uint16_t Store_Data[];

void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);

#endif

Store.c

#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"

#define STORE_START_ADDRESS		0x0800FC00		//存储的起始地址
#define STORE_COUNT				512				//存储数据的个数

uint16_t Store_Data[STORE_COUNT];				//定义SRAM数组

/**
  * 函    数:参数存储模块初始化
  * 参    数:无
  * 返 回 值:无
  */
void Store_Init(void)
{
	/*判断是不是第一次使用*/
	if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//读取第一个半字的标志位,if成立,则执行第一次使用的初始化
	{
		MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定页
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
		for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循环STORE_COUNT次,除了第一个标志位
		{
			MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了标志位的有效数据全部清0
		}
	}
	
	/*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/
	for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循环STORE_COUNT次,包括第一个标志位
	{
		Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//将闪存的数据加载回SRAM数组
	}
}

/**
  * 函    数:参数存储模块保存数据到闪存
  * 参    数:无
  * 返 回 值:无
  */
void Store_Save(void)
{
	MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定页
	for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,包括第一个标志位
	{
		MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//将SRAM数组的数据备份保存到闪存
	} 
}

/**
  * 函    数:参数存储模块将所有有效数据清0
  * 参    数:无
  * 返 回 值:无
  */
void Store_Clear(void)
{
	for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循环STORE_COUNT次,除了第一个标志位
	{
		Store_Data[i] = 0x0000;							//SRAM数组有效数据清0
	}
	Store_Save();										//保存数据到闪存
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"

uint8_t KeyNum;					//定义用于接收按键键码的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();				//OLED初始化
	Key_Init();					//按键初始化
	Store_Init();				//参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Flag:");
	OLED_ShowString(2, 1, "Data:");
	
	while (1)
	{
		KeyNum = Key_GetNum();		//获取按键键码
		
		if (KeyNum == 1)			//按键1按下
		{
			Store_Data[1] ++;		//变换测试数据
			Store_Data[2] += 2;
			Store_Data[3] += 3;
			Store_Data[4] += 4;
			Store_Save();			//将Store_Data的数据备份保存到闪存,实现掉电不丢失
		}
		
		if (KeyNum == 2)			//按键2按下
		{
			Store_Clear();			//将Store_Data的数据全部清0
		}
		
		OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//显示Store_Data的第一位标志位
		OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//显示Store_Data的有效存储数据
		OLED_ShowHexNum(3, 6, Store_Data[2], 4);
		OLED_ShowHexNum(4, 1, Store_Data[3], 4);
		OLED_ShowHexNum(4, 6, Store_Data[4], 4);
	}
}

读取芯片ID

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

int main(void)
{
	OLED_Init();						//OLED初始化
	
	OLED_ShowString(1, 1, "F_SIZE:");	//显示静态字符串
	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);		//使用指针读取指定地址下的闪存容量寄存器
	
	OLED_ShowString(2, 1, "U_ID:");		//显示静态字符串
	OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);		//使用指针读取指定地址下的产品唯一身份标识寄存器
	OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);
	OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);
	OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
	
	while (1)
	{
		
	}
}

接线图

标签:闪存,void,FLASH,stm32,MyFLASH,Data,uint32,Store
From: https://blog.csdn.net/2302_79504723/article/details/142424061

相关文章

  • 学习STM32的震动开关
    学习STM32的震动开关在本文中,我将详细介绍如何使用STM32微控制器来实现一个震动开关。震动开关是一种能够检测物体是否发生震动的传感器,通常用于安防系统、智能家居等领域。我们将使用STM32的GPIO模块和外部中断功能来实现震动开关的功能。前期准备在开始之前,我们需要准备以......
  • STM32实现简单的智能办公系统
    为了实现一个简单的智能办公系统,我们可以利用STM32微控制器和一些外设来实现各种功能。在本文中,我将介绍如何通过STM32来控制温度和湿度传感器、人体红外传感器,以及通过无线通信来实现报警和监控功能。首先,我们需要准备一些硬件设备,包括:STM32微控制器开发板:本例中使用的是S......
  • 学习STM32的OLED显示屏控制
    引言:OLED(OrganicLightEmittingDiode)屏幕是一种新型的显示技术,它使用有机材料作为发光器件,具有高对比度、快速响应、广视角和低功耗等特点。STM32是一家全球领先的微控制器制造商,其产品家族中包括了多种型号的ARMCortex-M系列的微控制器。在本文中,我们将介绍如何使用STM32......
  • 学习STM32的火焰传感器
    火焰传感器是一种用于检测火焰存在的电子设备。它可以广泛应用于火灾检测、火焰监控和安全预警等领域。本文将详细介绍如何使用STM32开发板和火焰传感器来实现火焰检测功能,并给出相应的代码案例。一、硬件准备首先,需要准备以下硬件设备:STM32开发板(如STM32F103C8T6)火焰传感器......
  • 单片机毕业论文 怎么写 STM32单片机毕业论文 单片机毕设设计论文怎么写 单片机编程 单
    单片机毕业论文怎么写引言单片机毕业论文怎么写?这个问题看似复杂,但只要掌握一些关键技巧,就能轻松应对。论文的本质无非是用一种结构化的方式展示你对单片机的理解、设计、实现和思考。接下来,我们用通俗幽默的方式,逐步解析如何撰写一篇优秀的单片机毕业论文。1.开题报告......
  • stm32 PWR电源控制(修改主频&睡眠模式&停机模式&待机模式)
    理论1.PWR简介PWR(PowerControl)电源控制PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能可编程电压监测器(PVD)可以监控VDD电源电压,当VDD下降到PVD阀值以下或上升到PVD阀值之上时,PVD会触发中断,用于执行紧急关闭任务低功耗模式包括睡眠模......
  • stm32 WDG看门狗(独立看门狗&窗口看门狗)
    理论WDGWDG(Watchdog)看门狗看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计......
  • STM32F407单片机编程入门(九)低功耗模式实战含源码
    文章目录一.概要二.STM32单片机低功耗基本介绍三.STM32F407单片机待机模式介绍四.CubeMX配置一个待机低功耗例程五.CubeMX工程源代码下载六.小结一.概要在生活中通过关掉电器组件可以实现省电节能的目的,同样的道理单片机也可以通过这种方法实现降低功耗。单片机是由......
  • 三星USB 3.2闪存盘上手:性能超400MB/s
    三星作为存储行业的翘楚,不论是品牌影响力还是闪存技术积累,都位于整个行业的头部,为了更好地满足当下快节奏、数字化时代的全面到来,三星存储也推出了新款的USB闪存盘,拥有小巧的身材、强大的性能和海量的存储空间,满足各类用户存储需求。这次我们拿到的两款USB闪存盘分别为三星BARPl......
  • 米尔STM32MP2核心板首发新品上市!高性能+多接口+边缘算力
    米尔发布基于STM32MP257设计的嵌入式处理器模块MYC-LD25X核心板及开发板。核心板基于STM32MP2系列是意法半导体推出最新一代工业级64位微处理器,采用LGA252PIN设计,存储配置1GB/2GBLPDDR4、8GBeMMC,具有丰富的通讯接口,适用于高端工业HMI、边缘计算网关、新能源充电桩、储能EMS系......