FLASH读写数据

目录

嵌入式 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

FLASH读写数据_第1张图片

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

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

等待周期

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

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

FLASH读写数据_第2张图片FLASH读写数据_第3张图片

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 进行写 
操作时将编程的字节数。

FLASH读写数据_第4张图片

可以从手册知道位宽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 位清零。

遇到的错误

使用FLASH发现,flash读写读写不出来,或者是写的时候反馈是错误的状态;

编译时候发现:*** Scatter Error: no default 'Read/Write' range selected

要勾选上如下

FLASH读写数据_第5张图片

使用MDK5的一些偏僻使用方法和谋个功能的作用_我的老子姓彭的博客-CSDN博客

 

工程程序

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

文件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  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");
						
				 }

	}

}


你可能感兴趣的:(STM32F4的学习,stm32,单片机)