STM32读写内部flash

概念:计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是1个字节,

1个存储单元存放1个字节,每个存储单元对应一个32位(bit)地址,所以重要的话说三遍:对于32bit的ARM CPU

一个32位地址指向1个字节!!!  一个32位地址指向1个字节!!!   一个32位地址指向1个字节!!!

我们常说的flash空间,多少多少K,指的是多少多少K byte 


我使用的是STM32F030C8T6  的芯片 ,查询数据手册可知其flash的大小为64Kbytes,SRAM为8Kbytes

flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同。

RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯片的RAM大小。不同的芯片RAM也不同。

Flash中的内容一般用来存储代码和一些定义为const的数据,断电不丢失, 
RAM可以理解为内存,用来存储代码运行时的数据,变量等等。掉电数据丢失。

STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。 
stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。

一般情况下,程序文件是从 0x0800 0000 地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。 
在使用keil进行编写程序时,其编程地址的设置一般是这样的: 
这里写图片描述 
程序的写入地址从0x08000000(数好零的个数)开始的,其大小为0x80000也就是512K的空间,换句话说就是告诉编译器flash的空间是从0x08000000-0x08080000,RAM的地址从0x20000000开始,大小为0x10000也就是64K的RAM。这与STM32的内存地址映射关系是对应的。

M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执行完之后会跳到我们的main函数,main函数里边一般是一个死循环,进去后就不会再退出,当有中断发生的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进入对应的中断函数,执行完中断函数之后,再次返回main函数中。大致的流程就是这样。

对内部flash的写过程

1. 解锁  
(1) 往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123 
(2) 再往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB 
2. 数据操作位数  
最大操作位数会影响擦除和写入的速度,其中 64 位宽度的操作除了配置寄存器位外,还需要在 Vpp 引脚外加一个 8-9V 的电压源,且其供电间不得超过一小时,否则 FLASH可能损坏,所以 64 位宽度的操作一般是在量产时对 FLASH 写入应用程序时才使用,大部分应用场合都是用 32 位的宽度。 
3. 擦除扇区  
在写入新的数据前,需要先擦除存储区域, STM32 提供了扇区擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。 
扇区擦除的过程如下: 
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何 
Flash 操作; 
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位 SER ”置 1,并设置“扇 
区编号寄存器位 SNB”,选择要擦除的扇区; 
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除; 
(4) 等待 BSY 位被清零时,表示擦除完成。 
4. 写入数据  
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下: 
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作; 
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1; 
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作; 

(4) 等待 BSY 位被清零时,表示写入完成。

5. 上锁

对内部flash的读过程

flash读取的过程比较简单,直接将flash地址中的值赋给自己定义的变量即可,注意地址一定要写正确


主题代码部分

主要实现的功能是:在flash中划分出1kb的空间来保存数据,起始地址为0x0800f800,结束地址为0x0800fc00   也就是说可以存放256个32bit的数据。在本程序中只存放了两个32bit数据 (其实定义了三个元素的数组,第0个数据的读取不正确,就从第1个数据开始保存)

flash.c文件

#include "flash.h"

/* Private define ------------------------------------------------------------*/
#define FLASH_PAGE_SIZE         ((uint32_t)0x00000400)   /* FLASH Page Size(1KB) */
#define FLASH_USER_START_ADDR   ((uint32_t)0x0800F800)   /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR     ((uint32_t)0x0800FC00)   /* End @ of user Flash area */
#define COUNTER_MAX				(sizeof(flashRom.data32)/sizeof(flashRom.data32[0]))			//2

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t Counter = 0x00, Address = 0x00;
//uint32_t Data = 0x3210ABCD;
uint32_t NbrOfPage = 0x00;
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
//__IO TestStatus MemoryProgramStatus = PASSED;

/**************************************************
函数名称     
功能          
参数          
返回值                 
作者           
**************************************************/
uint8_t WriteFlash(void)
{
	/* Unlock the Flash to enable the flash control register access *************/ 
	FLASH_Unlock();		//解锁

	/* Erase the user Flash area
	(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

	/* Clear pending flags (if any) */ //清除flash待处理标志位
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR); 

	/* Define the number of page to be erased */		//要擦出的大小
	NbrOfPage = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;

	/* Erase the FLASH pages */		//开始擦除
	for(Counter = 0; (Counter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); Counter++)
	{
		if (FLASH_ErasePage(FLASH_USER_START_ADDR + (FLASH_PAGE_SIZE * Counter))!= FLASH_COMPLETE)
		{
			/* Error occurred while sector erase. 
			 User can add here some code to deal with this error  */
			FLASH_Lock(); 
			return 1;
		}
		IWDG_ReloadCounter();
	}
	
	  /* Program the user Flash area word by word
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

	Address = FLASH_USER_START_ADDR;
	Counter = 0;
	flashRom.cali.flashWritten = 0xA5;        //表示已经在flash中写入数据
	while (Address < FLASH_USER_END_ADDR && Counter < COUNTER_MAX)			
	{
		if (FLASH_ProgramWord(Address, flashRom.data32[Counter]) == FLASH_COMPLETE)		//¼ì²â  flash²»Ã¦
		{
			Address = Address + 4;
			Counter++;
		}
		else
		{ 
			/* Error occurred while writing data in Flash memory. 
			 User can add here some code to deal with this error */
			FLASH_Lock(); 			//数据写入完成  上锁
			return 1;
		}
		IWDG_ReloadCounter();
	}
	
	/* Lock the Flash to disable the flash control register access (recommended
     to protect the FLASH memory against possible unwanted operation) *********/
	FLASH_Lock(); 
	
	return 0;
}
/**************************************************
函数名称        FlashRead
功能
参数
返回值
作者
**************************************************/
void FlashRead(void)
{
	Address = FLASH_USER_START_ADDR;
//	MemoryProgramStatus = PASSED;
	Counter = 0;

	while (Address < FLASH_USER_END_ADDR && Counter < COUNTER_MAX)
	{
		flashRom.data32[Counter] = *(__IO uint32_t *)Address;
		if(flashRom.cali.flashWritten != 0xA5)
		{
			flashRom.cali.check = 0x00;		//无校准记录
			break;
		}
		Address = Address + 4;
		Counter++;
	}
}

flash.h文件

#ifndef __FLASH_H
#define __FLASH_H

#include "stm32f0xx.h"

typedef enum        //注意:该枚举变量已经在 库函数中定义过的,就将本文件中的删除。加上只是为了观赏性
{
  FLASH_BUSY = 1,
  FLASH_ERROR_WRP,
  FLASH_ERROR_PROGRAM,
  FLASH_COMPLETE,
  FLASH_TIMEOUT
}FLASH_Status;


/* flash存储结构体 */
struct CalibrateStruct
{
	// 32位为一个读写单位
	uint8_t		flashWritten;	// 记录flash曾写入过,读取数据可用 记录值:0xA5
	uint8_t		check;
	uint16_t	__RESERVE0;		// 保留  维持前32位的独立性
	//以上部分保留不允许修改
};
/* flash存储联合体 */
union FlashRom
{
	struct CalibrateStruct cali;
	uint32_t	data32[3];	//
};

#endif

本程序的问题:写入的第一个数据,读取不正确(不知道其中原因,望大神指点迷津)。所以从开始地址的第二个32位数开始保存有效数据


说明:本文章中的文字部分参考  https://blog.csdn.net/qq_33559992/article/details/77676716

其中添加自己的一部分东西。   代码部分为鄙人书写,实测可用



猜你喜欢

转载自blog.csdn.net/David_361/article/details/81056050