STM32专题28:内部Flash读写操作详解

内部Flash

除了使用外部的工具(如下载器)读写内部FLASH外,STM32芯片在运行的时候,也能对自身的内部FLASH进行读写,因此,若内部FLASH存储了应用程序后还有剩余的空间,我们可以把它像外部SPI-FLASH那样利用起来,存储一些程序运行时产生的需要掉电保存的数据。

       由于访问内部FLASH的速度要比外部的SPI-FLASH快得多,所以在紧急状态下常常会使用内部FLASH存储关键记录;为了防止应用程序被抄袭,有的应用会禁止读写内部FLASH中的内容,或者在第一次运行时计算加密信息并记录到某些区域,然后删除自身的部分加密代码,这些应用都涉及到内部FLASH的操作。

内部Flash结构(大容量):
TM32 的内部 FLASH 包含主存储器、系统存储器以及选项字节区域,它们的地址分
布及大小见表 (在《STM32 参考手册》 中没有关于其内部 FLASH 的说明,需要了解
这些内容时,要查阅《STM32F10x 闪存编程参考手册》 )

主要功能描述:

  1. 主存储器中保存了我们烧写到Flash中的程序;一般我们说 STM32 内部 FLASH 的时候,都是指这个主存储器区域,它是存储用户应用程序的空间,芯片型号说明中的 256K FLASH、 512K FLASH 都是指这个区域的大小。主存储器分为 256 页,每页大小为 2KB,共 512KB。 这个分页的概念,实质就是FLASH 存储器的扇区,与其它 FLASH 一样,在写入数据前,要先按页(扇区)擦除。
  2. 启动程序代码(系统存储区):是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负责实现串口、USB以及CAN等ISP烧录功能;
  3. 用户选择字节(选项字节):选项字节用于配置FLASH的读写保护、待机/停机复位、软件/硬件看门狗等功能;

 对内部Flash的写入过程:

 1 解锁:

操作的寄存器: 

2 页擦除:

涉及到的寄存器: 

 

 

还有不常使用的全片擦除(防止破解): 

3 写入数据:

擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:

  1.     检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
  2.     将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
  3.     向指定的 FLASH 存储器地址执行数据写入操作,每次只能以 16位的方式写入;
  4.     等待 BSY 位被清零时,表示写入完成;

 闪存编程手册中的描述:

void FLASH_Lock(void)
{
  /* Set the Lock Bit to lock the FPEC and the CR of  Bank1 */
  FLASH->CR |= CR_LOCK_Set;
}

操作内部Flash的库函数 

 解锁

void FLASH_Unlock(void)
{
  /* Authorize the FPEC of Bank1 Access */
  FLASH->KEYR = FLASH_KEY1;
  FLASH->KEYR = FLASH_KEY2;
}

上锁

void FLASH_Lock(void)
{
  /* Set the Lock Bit to lock the FPEC and the CR of  Bank1 */
  FLASH->CR |= CR_LOCK_Set;
}

擦除扇区

/**
* @brief 擦除指定的页
* @param Page_Address: 要擦除的页地址.
* @retval FLASH Status:
可能的返回值: FLASH_BUSY, FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{
	 FLASH_Status status = FLASH_COMPLETE;
	 /* 检查参数 */
	 assert_param(IS_FLASH_ADDRESS(Page_Address));
	 /*...此处省略 XL 超大容量芯片的控制部分*/
	 /* 等待上一次操作完成 */
	 status = FLASH_WaitForLastOperation(EraseTimeout);

	 if (status == FLASH_COMPLETE) {
	 /* 若上次操作完成,则开始页擦除 */
	 FLASH->CR|= CR_PER_Set;
	 FLASH->AR = Page_Address;
	 FLASH->CR|= CR_STRT_Set;

	 /* 等待操作完成 */
	 status = FLASH_WaitForLastOperation(EraseTimeout);

	 /* 复位 PER 位 */
	 FLASH->CR &= CR_PER_Reset;
	 }

	 /* 返回擦除结果 */
	 return status;
}

3.写入数据

/**
  * @brief  Programs a half word at a specified address.
  * @note   This function can be used for all STM32F10x devices.
  * @param  Address: specifies the address to be programmed.
  * @param  Data: specifies the data to be programmed.
  * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. 
  */
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
  FLASH_Status status = FLASH_COMPLETE;
 
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(ProgramTimeout);
  
  if(status == FLASH_COMPLETE)
  {
    /* if the previous operation is completed, proceed to program the new data */
    FLASH->CR |= CR_PG_Set;
  
    /* 把地址参数强制转换为指针,再通过指针操作写入数据 */
    *(__IO uint16_t*)Address = Data;
 
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(ProgramTimeout);
    
    /* Disable the PG Bit */
    FLASH->CR &= CR_PG_Reset;
  } 
  
  /* Return the Program Status */
  return status;
}

实验:读写内部Flash 

bsp_internal_Flash.h

#ifndef __INTERNAL_FLASH_H
#define	__INTERNAL_FLASH_H

#include "stm32f10x.h"

/* STM32大容量产品每页大小2KByte,中、小容量产品每页大小1KByte */
#if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_CL) || defined (STM32F10X_XL)
  #define FLASH_PAGE_SIZE    ((uint16_t)0x800)	//2048
#else
  #define FLASH_PAGE_SIZE    ((uint16_t)0x400)	//1024
#endif

//写入的起始地址与结束地址
#define WRITE_START_ADDR  ((uint32_t)0x08008000)
#define WRITE_END_ADDR    ((uint32_t)0x0800C000)



typedef enum 
{
	FAILED = 0, 
  PASSED = !FAILED
} TestStatus;


int InternalFlash_Test(void);



#endif /* __INTERNAL_FLASH_H */

 bsp_internal_Flash.c

/**
  ******************************************************************************
  * @file    bsp_internalFlash.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   内部FLASH读写测试范例
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 霸道 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
  
#include "./internal_flash/bsp_internal_flash.h"   
#include "./usart/bsp_usart.h"






/**
  * @brief  InternalFlash_Test,对内部FLASH进行读写测试
  * @param  None
  * @retval None
  */
int InternalFlash_Test(void)
{
	uint32_t EraseCounter = 0x00; 	//记录要擦除多少页
	uint32_t Address = 0x00;				//记录写入的地址
	uint32_t Data = 0x3210ABCD;			//记录写入的数据
	uint32_t NbrOfPage = 0x00;			//记录写入多少页
	
	FLASH_Status FLASHStatus = FLASH_COMPLETE; //记录每次擦除的结果	
	TestStatus MemoryProgramStatus = PASSED;//记录整个测试结果
	

  /* 解锁 */
  FLASH_Unlock();

  /* 计算要擦除多少页 */
  NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;

  /* 清空所有标志位 */
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	

  /* 按页擦除*/
  for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
  {
    FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
  
	}
  
  /* 向内部FLASH写入数据 */
  Address = WRITE_START_ADDR;

  while((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
  {
    FLASHStatus = FLASH_ProgramWord(Address, Data);
    Address = Address + 4;
  }

  FLASH_Lock();
  
  /* 检查写入的数据是否正确 */
  Address = WRITE_START_ADDR;

  while((Address < WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
  {
    if((*(__IO uint32_t*) Address) != Data)
    {
      MemoryProgramStatus = FAILED;
    }
    Address += 4;
  }
	return MemoryProgramStatus;
}




main.c

 /**
  ******************************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2013-xx-xx
  * @brief   向STM32的内部FLASH写入数据
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火 F103-霸道 STM32 开发板 
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */ 
#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./internal_flash/bsp_internal_flash.h"   


// 函数原型声明
void Delay(__IO uint32_t nCount);
/*
 * 函数名:main
 * 描述  :主函数
 * 输入  :无
 * 输出  :无
 */
int main(void)
{ 	
	/*初始化USART,配置模式为 115200 8-N-1*/
    USART_Config();
	LED_GPIO_Config();
 
	LED_BLUE;
	printf("\r\n 欢迎使用野火  STM32  开发板。\r\n");	
	printf("正在进行读写内部FLASH实验,请耐心等待\r\n");
	
	if(InternalFlash_Test()== PASSED)
	{
		LED_GREEN;
		printf("读写内部FLASH测试成功\r\n");

	}
	else
	{
		printf("读写内部FLASH测试失败\r\n");
		LED_RED;
	}
	
	
  while(1)
	{	} 
}


void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}
/*********************************************END OF FILE**********************/

作者:旧梦m

物联沃分享整理
物联沃-IOTWORD物联网 » STM32专题28:内部Flash读写操作详解

发表评论