STM32(二十五)读写内部flash

一、内部flash简介

  • STM32 芯片内部有一个 FLASH 存储器,它主要用于存储代码 。
  • 我们在电脑上编写好应用程序后,使用下载器把编译后的代码文件烧录到该内部 FLASH 中 。
  • FLASH 储器的内容在掉电后不会丢失,芯片重新上电复位后,内核可从内部 FLASH 中加载代码并运行。  
  • 访问内部flash的速度比外部的SPI-Flash要快。
  • flash擦除时是按扇区擦除,使用电擦除,设备电压1.8V ~2.1V按字节(8bit)擦除,2.1V ~2.7V擦除半字(16bit),2.7V ~ 3.6V擦除一个字(32bit)

           2.7V to 3.6V +外部电压擦除两个字(64bit),

二、内部flash的构成

  STM32 的内部 FLASH 包含主存储器系统存储器以及选项字节区域,它们的地址分布及大小见下表。

 1、主存储器
  • 一般我们说STM32内部FLASH的时候,都是指这个主存储器区域,它是存储用户应用程序的空间,芯片型号说明中的256K FLASH、512K FLASH都是指这个区域的大小。
  • 主存储器分为256页,每须大小为2KB,共512KB。这个分页的概念,实质就是FLASH存储器的扇区,与其它FLASH - -样,在写入数据前,要先按页(扇区)擦除。

 

2、系统存储区

  系统存储区是用户不能访问的区域,它在芯片出厂时已经固化了启动代码,它负实现串口、 USB 以及 CAN ISP 烧录功能。 

3、选项字节

  选项字节用于配置 FLASH 的读写保护、待机/停机复位、软件/硬件看门狗等功能,这部分共 16 字节。可以通过修改 FLASH 的选项控制寄存器修改。 

三、对内部flash的写入过程

1.解锁

  由于内部FLASH空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给控制寄存器FLASH _CR上锁,这个时候不允许设置FLASH的控制寄存器,从而不能修改FLASH中的内容。所以对FLASH写入数据前,需要先给它解锁。解锁的操作步骤如下:

(1) 往FPEC键寄存器FLASH_ KEYR中写入KEY1 = 0x45670123

(2)再往FPEC键寄存器FLASH_ KEYR中写入KEY2 = 0xCDEF89AB

2.页擦除.

  在写入新的数据前,需要先擦除存储区域,STM32提供了页(扇区)擦除指令和整个FLASH擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。页擦除的过程如下:

  (1) 检查FLASH_ SR寄存器中的“忙碌寄存器位BSY”,以确认当前未执行任何Flash操作;

  (2)在FLASH_ CR寄存器中,将“激活页擦除寄存器位PER”置1。

  (3)用FLASHAR寄存器选择要擦除的页;

  (4) 将FLASH _CR寄存器中的“开始擦除寄存器位STRT"置1,开始擦除;

  (5)等待BSY位被清零时,表示擦除完成。

3.写入数据

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

  (1) 检查FLASH_ SR中的BSY位,以确认当前未执行任何其它的内部Flash操作;

  (2) 将FLASH_ CR寄存器中的“激活编程寄存器位PG”置1;

  (3)向指定的FLASH存储器地址执行数据写入操作,每次只能以16位的方式写入;

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

/**
  * @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;
}

  

思考题1flash擦除完之后,扇区里面所有的数据是什么?

  :所有的数据都是为0xFF,所有bit位都是1。
0

思考题2假如说现在已经擦除完扇区,先写入了1个字,然后在下一个偏移地址再次写入新的字是否在需要擦除扇区?

  答案:不需要的。

思考题3:假如说现在已经擦除完扇区,先写了1个字,然后在同一个地址再次写入新的字是否需要擦除扇区?

  答案:需要进行擦除!
例子,已经写入数据为0x12345678,然后再写入新的数据为0x1111111,最后得到的数据居然是0x101010.
0

总结:

  判断是否允许写入字,只需要判断当前的地址存储的数据是否为0xFFFFFFFF,若为0xFFFFFFFF,可以写入数据,不需要进行扇区擦除。
 

 

 

 

原文地址:https://www.cnblogs.com/yuanqiangfei/p/14468852.html