STM32标准库内部FLASH读写操作详解

1.内部FLASH的构成

STM32F407的内部FLASH包含主存储器、系统存储器、OTP区域以及选项字节区域。

一般我们说STM32内部FLASH的时候,都是指这个主存储器区域,它是存储用户应用程序的空间。STM32F407ZGT6型号芯片, 它的主存储区域大小为1MB。其中包含4个16KB扇区、1个64KB扇区和7个128KB的扇区。

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

  • OTP区域
  • OTP(One Time Program),指的是只能写入一次的存储区域,容量为512字节,写入后数据就无法再更改,OTP常用于存储应用程序的加密密钥。

  • 选项字节
  • 选项字节用于配置FLASH的读写保护、电源管理中的BOR级别、软件/硬件看门狗等功能,这部分共32字节。可以通过修改FLASH的选项控制寄存器修改。

    2.对内部FLASH的写入过程

    2.1解锁

    由于内部FLASH空间主要存储的是应用程序,是非常关键的数据,为了防止误操作修改了这些内容,芯片复位后默认会给FLASH上锁, 这个时候不允许设置FLASH的控制寄存器,并且不能对修改FLASH中的内容。

    所以对FLASH写入数据前,需要先给它解锁。解锁的操作步骤如下:

    (1) 往Flash 密钥寄存器 FLASH_KEYR中写入 KEY1 = 0x45670123

    (2) 再往Flash 密钥寄存器 FLASH_KEYR中写入 KEY2 = 0xCDEF89AB

    2.2数据操作位数

    在内部FLASH进行擦除及写入操作时,电源电压会影响数据的最大操作位数,该电源电压可通过配置FLASH_CR 寄存器中的 PSIZE位改变,见表 数据操作位数 。

    数据操作位数

    最大操作位数会影响擦除和写入的速度,其中64位宽度的操作除了配置寄存器位外,还需要在Vpp引脚外加一个8-9V的电压源, 且其供电时间不得超过一小时,否则FLASH可能损坏,所以64位宽度的操作一般是在量产时对FLASH写入应用程序时才使用,大部分应用场合都是用32位的宽度。

    2.3擦除扇区

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

    扇区擦除的过程如下:

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

    (2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位SER ”置 1,并设置“扇区编号寄存器位SNB”,选择要擦除的扇区;

    (3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;

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

    2.4写入数据

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

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

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

    (3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;

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

    3.查看工程的空间分布

    在上面map文件的描述中,我们了解到加载及执行空间的基地址(Base)都是0x08000000,它正好是STM32内部FLASH的首地址, 即STM32的程序存储空间就直接是执行空间;它们的大小(Size)分别为0x00001ae4及0x00001ab4, 执行空间的ROM比较小的原因就是因为部分RW-data类型的变量被拷贝到RAM空间了;它们的最大空间(Max)均为0x00100000,即1M字节,它指的是内部FLASH的最大空间。计算程序占用的空间时,需要使用加载区域的大小进行计算,本例子中应用程序使用的内部FLASH是从0x08000000至(0x08000000+0x00001ae4)地址的空间区域。所以,一个扇区的大小就够了。

    4.FLASH读写实验

    #ifndef __BSP_INTER_FLASH_H
    #define __BSP_INTER_FLASH_H
    
    #ifdef __cplusplus
    extern "C"{
    
    #endif
    
    #include "stm32f4xx.h"
    
    
    #define TEST_FLASH_SECTION            FLASH_Sector_1 //这里用或操作直接两块section好像不太行
    #define TEST_FLASH_BASE_ADDRESS       0x08004000
    #define TEST_FLASH_SIZE               16*1024
    #define TEST_FLASH_DATA               0x5a5aa5a5 
    
    
    void inter_flash_test(void);
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    
    
    
    #include "bsp_inter_flash.h"
    #include "stdio.h"
    
    void inter_flash_test()
    {
    	//1.解锁  2.擦除  3.写入  4.上锁  5.读取
    	FLASH_Status status = FLASH_COMPLETE;
    	
    	FLASH_Unlock();
    
    	status=FLASH_EraseSector(TEST_FLASH_SECTION,VoltageRange_3);
    	if(FLASH_COMPLETE==status)
    	{
    		printf("FLASH_EraseSector OK\r\n");
    	}
    	
    	for(int i=0;i<TEST_FLASH_SIZE;i+=4)
    	{
    		status=FLASH_ProgramWord(TEST_FLASH_BASE_ADDRESS+i,TEST_FLASH_DATA);
    		if(FLASH_COMPLETE==status)
    	    {
    		     printf("FLASH_ProgramWord OK\r\n");
    	    }
    	}
    	
    	FLASH_Lock();
    	
    	__IO uint32_t* addr=(__IO uint32_t*)TEST_FLASH_BASE_ADDRESS;
    	for(int i=0;i<TEST_FLASH_SIZE;i+=4)
    	{
    		if(TEST_FLASH_DATA!=*(addr++))
    		{
    			printf("TEST_FLASH_DATA ERROR\r\n");
    		}
    	}
    }
    
    
    

    作者:heater404

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32标准库内部FLASH读写操作详解

    发表回复