FLASH读写数据

news2025/1/23 7:25:18

目录

嵌入式 Flash大概了解

数据手册2.3.2章节

结构图f407

等待周期

 Flash 控制寄存器解锁

编程/擦除并行位数

 擦除

 编程(写入)

工程程序


嵌入式 Flash大概了解

可以从flash区域启动程序;大概是程序区可以在flash,所以是可以直接读取数据的

数据手册2.3.2章节

Flash 接口可管理 CPU 通过 AHB I-Code 和 D-Code 对 Flash 进行的访问。该接口可针对 
Flash 执行擦除和编程操作,并实施读写保护机制。Flash 接口通过指令预取和缓存机制加速 
代码执行。
Flash 结构如下:
● 主存储器块分为多个扇区。
● 系统存储器,器件在系统存储器自举模式下从该存储器启动
● 512 OTP(一次性可编程)字节,用于存储用户数据。
● 选项字节,用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或停止 
模式下的复位。

可以知道flash是存储程序用的,可以用来做主存储

结构图f407

主存储器大概有12个扇区:主要的数据程序都在这里;

当使用时要注意程序的大小,在程序大小之外使用。不然会影响,擦除原来存储的程序;造成死机;

等待周期

为了准确读取 Flash 数据,必须根据 CPU 时钟 (HCLK) 频率和器件电源电压在 Flash 存取控 
制寄存器 (FLASH_ACR) 中正确地编程等待周期数 (LATENCY)

所以一句话:读取数据需要时间,并且根据HCLK和电压范围得到的CPU周期;

168M 的HCLK 和 3.3V的电压 可以知道等待周期大概6个CPU时间;

 Flash 控制寄存器解锁

 复位后,Flash 控制寄存器 (FLASH_CR) 不允许执行写操作,以防因电气干扰等原因出现对 
Flash 的意外操作。此寄存器的解锁顺序如下:
1. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY1 = 0x45670123
2. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY2 = 0xCDEF89AB
如果顺序出现错误,将返回总线错误并锁定 FLASH_CR 寄存器,直到下一次复位。

所以操作配置的时候必须要先解锁;

编程/擦除并行位数


通过 FLASH_CR 寄存器中的 PSIZE 字段配置并行位数。并行位数表示每次对 Flash 进行写 
操作时将编程的字节数。

可以从手册知道位宽128,即32字节;所以配置应该32字节即可;

 擦除

Flash 擦除操作可针对扇区或整个 Flash(批量擦除)执行。执行批量擦除时,不会影响 
OTP 扇区或配置扇区。

扇区擦除
扇区擦除的具体步骤如下:
1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作
2. 在 FLASH_CR 寄存器中,将 SER 位置 1,并从主存储块的 12 个 (STM32F405xx/07xx 
和 STM32F415xx/17xx) 或 24 个 (STM32F42xxx 和 STM32F43xxx) 扇区中选择要擦除
的扇区 (SNB)
3. 将 FLASH_CR 寄存器中的 STRT 位置 1
4. 等待 BSY 位清零

 编程(写入)


标准编程
Flash 编程顺序如下:
1. 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何主要 Flash 操作。
2. 将 FLASH_CR 寄存器中的 PG 位置 1。
3. 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作:
— 并行位数为 x8 时按字节写入
— 并行位数为 x16 时按半字写入
— 并行位数为 x32 时按字写入
— 并行位数为 x64 时按双字写入
4. 等待 BSY 位清零。

工程程序

不懂地址谨慎使用,会破坏原来的程序;

文件C

#include"flash_eeprom.h"

/***** 读取字 *******/

uint32_t flash_read_word(  uint32_t *addr   )
{
  return *addr;
}

uint32_t flash_read( uint32_t addr,uint32_t *buff ,uint32_t cnt  )
{

   uint32_t i;
	 for(i=0 ;i<cnt ;i++)
	 {
		  *buff++=flash_read_word(  (uint32_t *)addr  );
		  addr+=4;
	 }

}
/*
   用地址来确定是flash的哪一个扇区
   addr flash的地址


*/

uint16_t 	flash_get_sector_x(  uint32_t addr     ) 
{
    if(addr<FLASH_SECTOR1_ADDR   ) return  FLASH_Sector_0;
	  else if( addr<FLASH_SECTOR2_ADDR ) return  FLASH_Sector_1;
	  else if( addr<FLASH_SECTOR3_ADDR ) return  FLASH_Sector_2;
	  else if( addr<FLASH_SECTOR4_ADDR ) return  FLASH_Sector_3;
	  else if( addr<FLASH_SECTOR5_ADDR ) return  FLASH_Sector_4;
	  else if( addr<FLASH_SECTOR6_ADDR ) return  FLASH_Sector_5;
	  else if( addr<FLASH_SECTOR7_ADDR ) return  FLASH_Sector_6;
	  else if( addr<FLASH_SECTOR8_ADDR ) return  FLASH_Sector_7;
	  else if( addr<FLASH_SECTOR9_ADDR ) return  FLASH_Sector_8;
	  else if( addr<FLASH_SECTOR10_ADDR ) return  FLASH_Sector_9;
	  else if( addr<FLASH_SECTOR11_ADDR ) return  FLASH_Sector_10;
	  else  return  FLASH_Sector_11;

}


void flash_write( uint32_t addr ,uint32_t *buff ,uint32_t cnt    )
{
   FLASH_Status state=FLASH_COMPLETE; 
	 uint32_t start_addr=addr;
	 uint32_t end_addr=start_addr+cnt*4;
	  FLASH_Unlock();//解锁
	  FLASH_DataCacheCmd(DISABLE);//禁止数据缓存
   if(  (addr < FLASH_START_ADDR  && addr >  FLASH_END_ADDR ) || addr%4 !=0  ) return; //确保地址在主储存区域
	 while( start_addr < end_addr)
	 {
	      if( flash_read_word(  (uint32_t * )start_addr   ) != 0xffffffff) 
				{
				    state=FLASH_EraseSector(  flash_get_sector_x(start_addr), VoltageRange_3 );//擦除需要电压相关,得到周期时间
					  if( state != FLASH_COMPLETE )
						{
						     break;   
						}
				
				}
	      start_addr+=4;
	 }
	 start_addr=addr;
   if(state== FLASH_COMPLETE)
	 {
	      while(start_addr< end_addr)//写数据进flash
				{
		         if(FLASH_ProgramWord( start_addr , *buff++) !=FLASH_COMPLETE )
						 {break;} 
             start_addr+=4;						 
				}
	 
	 }
   
	 FLASH_DataCacheCmd(ENABLE);//使能数据缓存
	 FLASH_Lock();//锁上
}




文件H

#ifndef FLASH_EEPROM_H
#define FLASH_EEPROM_H

#include "main.h"

#define FLASH_START_ADDR 0x08000000

#define FLASH_SECTOR0_ADDR  0X08000000    //16k
#define FLASH_SECTOR1_ADDR  0X08004000    //16k
#define FLASH_SECTOR2_ADDR  0X08008000   //16k
#define FLASH_SECTOR3_ADDR  0X0800C000   //16k

#define FLASH_SECTOR4_ADDR  0X08010000  //64k

#define FLASH_SECTOR5_ADDR  0X08020000  //128k
#define FLASH_SECTOR6_ADDR  0X08040000  //128k
#define FLASH_SECTOR7_ADDR  0X08060000  //128k
#define FLASH_SECTOR8_ADDR  0X08080000  //128k
#define FLASH_SECTOR9_ADDR  0X080A0000  //128k
#define FLASH_SECTOR10_ADDR  0X080C0000  //128k
#define FLASH_SECTOR11_ADDR  0X080E0000  //128k

#define FLASH_END_ADDR 0x080EFFFF
#define FLASH_USER_ADDR 0X080E0000  //

uint32_t flash_read( uint32_t addr,uint32_t *buff ,uint32_t cnt  );
void flash_write( uint32_t addr ,uint32_t *buff ,uint32_t cnt    );

#endif


#include "main.h"
#define tmep_len 30
uint8_t temp_buf[tmep_len]={0};
	
void test();
uint8_t *mian_temp;
double time_us;
int main(void)
{ 
 
  u8 key,flag ,i,n=5;           //保存键值
  static bool cnt;
//	delay_init(168);  //初始化延时函数
	software_times_base_init( 168 );
	uart_init(115200);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	LED_Init();				//初始化LED端口 
	BEEP_Init();      //初始化蜂鸣器端口
	KEY_Init();       //初始化与按键连接的硬件接口
  LED1=!LED1;
	LED0=!LED0;

	while(1)
	{
				 key=KEY_Scan(0);
				 if(key==1)
				 {
						mian_temp=temp_buf;
						memset( mian_temp, 0 ,tmep_len );
						flash_read( FLASH_USER_ADDR,(uint32_t *)mian_temp ,tmep_len  );//读取 tmep_len 长的数据 ,并且要地址在程序区之外
						for(i=0;i< tmep_len;i++)
						{
								printf( "%d " ,mian_temp[i]);
						}
						printf( "\r\n");
				 }
				 if(key==2)
				 {
						mian_temp=temp_buf;
						memset( mian_temp, n++ ,tmep_len );
						flash_write( FLASH_USER_ADDR ,(uint32_t *)mian_temp ,tmep_len  );//写入 tmep_len 长的数据 ,并且要地址在程序区之外
					 
						mian_temp=temp_buf;
						memset( mian_temp, 0 ,tmep_len );
						flash_read( FLASH_USER_ADDR,(uint32_t *)mian_temp ,tmep_len  );
						for(i=0;i< tmep_len;i++)
						{
								printf( "%d " ,mian_temp[i]);
						}
						printf( "\r\n");
						
				 }

	}

}


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

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

相关文章

python调用git出错:ImportError: Failed to initialize: Bad git executable.

报错信息 #报错信息 Traceback (most recent call last): File “”, line 1, in File “C:\Python27\lib\site-packages\git_init_.py”, line 85, in raise ImportError(‘Failed to initialize: {0}’.format(exc)) ImportError: Failed to initialize: Bad git executab…

春秋云镜 CVE-2018-16283

春秋云镜 CVE-2018-16283 WordPress Plugin Wechat Broadcast LFI 靶标介绍 WordPress Plugin Wechat Broadcast LFI 启动场景 漏洞利用 exp # Exploit Title: WordPress Plugin Wechat Broadcast 1.2.0 - Local File Inclusion # Author: Manuel Garcia Cardenas # Date:…

图论-01-图的基本表示-邻接矩阵和邻接表-Java

文章目录 邻接矩阵邻接表邻接表的问题和改进总结 邻接矩阵 import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Scanner;public class AdjMatrix {private int V;private int E;private int[][] adj;// 构造函数&#xff0c;从文…

利用网络流通过拆点判断图的路径存在性问题:abc318_g

https://atcoder.jp/contests/abc318/tasks/abc318_g 对于图上一类路径是否存在问题&#xff0c;可以考虑网络流。 Trick1 路径存在转网络流 题目转化为&#xff1a; 找出两条不交路径 B->A, B->C 对于已经找到的路径&#xff0c;我们不能再走。对于当前我们找到的某条…

Matlab图像处理-幂次变换

幂次变换 如下图所示的幂次变换函数曲线图&#xff1a; 当γ <1时&#xff0c;效果和对数变换相似&#xff0c;放大暗处细节&#xff0c;压缩亮处细节&#xff0c;随着数值减少&#xff0c;效果越强。 当γ >1时&#xff0c;放大亮处细节&#xff0c;压缩暗处细节&…

云备份——配置信息及获取配置信息类模块

一&#xff0c;配置信息 使用文件配置加载一些程序的运行关键信息&#xff0c;如ip&#xff0c;端口等&#xff0c;可以让程序的运行更加灵活 我们需要的配置信息如下 IP地址端口号热点判断时间&#xff0c;也就是非热点文件的时间要求文件下载的URL前缀路径&#xff0c;用于表…

Matlab图像处理-

对数变换 对数变换的一项主要应用是压缩动态范围。一些特别的图像在实际显示中&#xff0c;高灰度值部分较占优势&#xff0c;而低灰度值的可见细节部分丢失。通过计算对数&#xff0c;如10的动态范围会降至14左右[即 ln1013.8]&#xff0c;这样就更易于处理。 对数变换就是压…

Pygame中Trivia游戏解析6-4

3.3.3 显示题目选项 在显示题目选项时&#xff0c;有三种情况&#xff1a;分别是用户还未选择答案时&#xff1b;用户的答案是正确时&#xff1b;用户的答案是错误时。 &#xff08;1&#xff09;用户还未选择答案时 此时&#xff0c;用白色显示四个备选答案&#xff0c;如图…

数据工厂-生成接口通用用例

章节目录&#xff1a; 一、背景介绍二、前置准备三、设计思路四、代码具体实现五、执行效果六、其他说明七、结束语 一、背景介绍 有哪些用例是可以通用且固定的&#xff1f; 针对之前提到的接口用例设计思路&#xff0c;拆分为三个切入点&#xff1a; 举个例子&#xff1a; {…

【原创】H3C三层交换机VLAN路由

网络拓扑图 VLAN 配置 VLAN 100 VLAN 200 [H3C]int vlan 100 ip address 1.1.1.1 255.255.255.0[H3C-Vlan-interface100]int vlan 200 ip address 2.2.2.1 255.255.255.0[H3C]int GigabitEthernet 1/0/1port access vlan 100[H3C]int GigabitEthernet 1/0/2port access vlan 2…

R语言中缺失值的处理

目录 一.寻找缺失值 1.complete.cases() 2.manyNAs 二.缺失值的处理 1.直接删除 2.填补缺失值 一.寻找缺失值 1.complete.cases() #会展现缺失值 algae[!complete.cases(algae),] 2.manyNAs > manyNAs(algae) [1] 62 199 #表示第62条和第199条都有很多缺失值>m…

文本标注技术方案(NLP标注工具)

Doccano doccano 是一个面向人类的开源文本注释工具。它为文本分类、序列标记和序列到序列任务提供注释功能。您可以创建用于情感分析、命名实体识别、文本摘要等的标记数据。只需创建一个项目&#xff0c;上传数据&#xff0c;然后开始注释。您可以在数小时内构建数据集。 支持…

基于springboot跟redis实现的排行榜功能(实战)

概述 前段时间&#xff0c;做了一个世界杯竞猜积分排行榜。对世界杯64场球赛胜负平进行猜测&#xff0c;猜对1分&#xff0c;错误0分&#xff0c;一人一场只能猜一次。 1.展示前一百名列表。 2.展示个人排名(如&#xff1a;张三&#xff0c;您当前的排名106579)。 一.redis so…

wireshark抓包体验

目录 1、使用基础 1.1 数据包筛选 1.2 MAC地址筛选 1.3 端口筛选 1.4 协议筛选 1.5 包长度筛选 1.6 http请求筛选 2.数据包搜索 3.数据包还原 2、例题复现 1、使用基础 1.1 数据包筛选 ip.src 源ip地址 同理可以得到筛选目标地址&#xff1a; ip.dst 目的ip地址 1.2 …

Unity中Shader的渲染排序Tags{“Queue“ = “Transparent“}

文章目录 前言一、在Unity中渲染排序一般是固定的几个层级&#xff0c;透明 和 半透明是以 2500 为 分界点&#xff0c;渲染层级 从 低 到 高二、渲染队列 可以 在 SubShader 或 Pass 中写 前言 Unity中Shader的渲染排序 一、在Unity中渲染排序一般是固定的几个层级&#xff0…

【vue2第十章】data数据与组件间通信

组件化化开发时data写法。 组件化开发中data是一个函数&#xff0c;一个组件的data选项必须是一个函数。需要保证每个组件的实列维护自己的独立的数据。 写法就是&#xff1a; 函数名(){return{属性名:值,属性名:值,属性名:值} }这里不管实列化多少份这个组件&#xff0c;每个…

软件架构Architecture篇卷首语

2023年9月2日&#xff0c;周六晚上 我为什么要开始学习软件架构&#xff1f;我为什么要专门开始这个专栏&#xff1f; 原因如下&#xff1a; Well-structured software is delivered in half the time, at half the cost, with 8x less bugs ——US Air Force study 这句话是我…

2022年06月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:小白鼠再排队2 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从小到大的顺序输出它们头上帽子的颜色。帽子的颜色用 “red”,“blue”等字符串来表示。不同的小白鼠可…

C++面试题(期)-数据库(二)

目录 1.3 事务 1.3.1 说一说你对数据库事务的了解 1.3.2 事务有哪几种类型&#xff0c;它们之间有什么区别&#xff1f; 1.3.3 MySQL的ACID特性分别是怎么实现的&#xff1f; 1.3.4 谈谈MySQL的事务隔离级别 1.3.5 MySQL的事务隔离级别是怎么实现的&#xff1f; 1.3.6 事…

TiDB同城双中心监控组件高可用方案

作者&#xff1a; Prest13 原文来源&#xff1a; https://tidb.net/blog/44b9b8b1 背景 在双中心部署tidb dr-auto sync集群&#xff0c;出于监控的高可用考虑&#xff0c;在物理分离的两个数据中心分别部署独立的prometheusalertmanagergrafana&#xff0c;实现任一监控均…