STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程

读写FLASH的用途

  • 利用程序存储器的剩余空间来保存掉电不丢失的用户数据     
  • 通过在程序中编程(IAP),实现程序的自我更新
  • 在线编程(In-Circuit Programming – ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序

    在程序中编程(In-Application Programming – IAP)可以使用微控制器支持的任一种通信接口下载程序

    内存映射 

    小容量产品(16K 至 32K)、中容量产品(64k 至 128k)、大容量产品(256K 至 512K)。

     

    闪存存储器接口(外设)不属于闪存 

    FLASH基本结构 

    可以看出 闪存存储器接口(外设)整体结构

     使用指针访问存储器

    1. 使用指针读指定地址下的存储器:     uint16_t Data = *((__IO uint16_t *)(0x08000000));
    2. 使用指针写指定地址下的存储器:     *((__IO uint16_t *)(0x08000000)) = 0x1234; 
    3. #define    __IO    volatile

    易读不易写 可以直接读或者像下面代码一样封装一个函数读

    /**
      * 函    数:FLASH读取一个32位的字
      * 参    数:Address 要读取数据的字地址
      * 返 回 值:指定地址下的数据
      */
    uint32_t MyFLASH_ReadWord(uint32_t Address)
    {
    	return *((__IO uint32_t *)(Address));	//使用指针访问指定地址下的数据并返回
    }
    
    /**
      * 函    数:FLASH读取一个16位的半字
      * 参    数:Address 要读取数据的半字地址
      * 返 回 值:指定地址下的数据
      */
    uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
    {
    	return *((__IO uint16_t *)(Address));	//使用指针访问指定地址下的数据并返回
    }
    
    /**
      * 函    数:FLASH读取一个8位的字节
      * 参    数:Address 要读取数据的字节地址
      * 返 回 值:指定地址下的数据
      */
    uint8_t MyFLASH_ReadByte(uint32_t Address)
    {
    	return *((__IO uint8_t *)(Address));	//使用指针访问指定地址下的数据并返回
    }

     

    程序存储器使用方法 

    FLASH锁 

    擦除控制器(FPEC)共有三个键值:   

  •  RDPRT键 = 0x000000A5
  • KEY1 = 0x45670123   
  •  KEY2 = 0xCDEF89AB
  • 解锁:     复位后,FPEC被保护,不能写入FLASH_CR     在FLASH_KEYR先写入KEY1,再写入KEY2,解锁错误的操作序列会在下次复位前锁死FPEC和FLASH_CR

    加锁:     设置FLASH_CR中的LOCK位锁住 FPEC 和 FLASH_CR 

    该环节库函数两行代码即可完成,实际操作并不复杂,只是这样侧面说明FLASH的复杂及不易出现问题导致丢失。

        FLASH_Unlock();					//解锁
    	
    	FLASH_Lock();					//加锁

    程序存储器全擦除

    流程图 

    /**
      * 函    数:FLASH全擦除
      * 参    数:无
      * 返 回 值:无
      * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
      */
    void MyFLASH_EraseAllPages(void)
    {
    	FLASH_Unlock();					//解锁
    	FLASH_EraseAllPages();			//全擦除
    	FLASH_Lock();					//加锁
    }

     

    程序存储器页擦除 

    流程图 

    /**
      * 函    数:FLASH页擦除
      * 参    数:PageAddress 要擦除页的页地址
      * 返 回 值:无
      */
    void MyFLASH_ErasePage(uint32_t PageAddress)
    {
    	FLASH_Unlock();					//解锁
    	FLASH_ErasePage(PageAddress);	//页擦除
    	FLASH_Lock();					//加锁
    }
    

     

    程序存储器编程 

    流程图 

    /**
      * 函    数:FLASH编程字
      * 参    数:Address 要写入数据的字地址
      * 参    数:Data 要写入的32位数据
      * 返 回 值:无
      */
    void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
    {
    	FLASH_Unlock();							//解锁
    	FLASH_ProgramWord(Address, Data);		//编程字
    	FLASH_Lock();							//加锁
    }
    
    /**
      * 函    数:FLASH编程半字
      * 参    数:Address 要写入数据的半字地址
      * 参    数:Data 要写入的16位数据
      * 返 回 值:无
      */
    void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
    {
    	FLASH_Unlock();							//解锁
    	FLASH_ProgramHalfWord(Address, Data);	//编程半字
    	FLASH_Lock();							//加锁
    }
    

     

     选项字节

  • RDP:写入RDPRT键(0x000000A5)后解除读保护
  • USER:配置硬件看门狗和进入停机/待机模式是否产生复位
  • Data0/1:用户可自定义使用
  • WRP0/1/2/3:配置写保护,每一个位对应保护4个存储页(中容量)
  •  nUSER及前面+ n 是反码

     

    对于产品,选择字节WRPx
    中的每一个比特位用于保护主存储器中
    4
    个存储页
    (1K
    字节
    /


    )

  • 0:实施写保护
  • 1:不实施写保护
  • 中容量四个用户选择字节用于保护总共128K
    字节的主存储器。

  • WRP0:第0~31页的写保护
  • WRP1:第32~63页的写保护
  • WRP2:第64~95页的写保护
  • WRP3:第96~127页的写保护
  • 大容量产品
    四个用户选择字节用于保护总共512K
    字节的主存储器。

  • WRP0:第0~15页的写保护
  • WRP1:第16~31页的写保护
  • WRP2:第32~47页的写保护
  • WRP3:位0~6提供第48~61页的写保护;位7提供第62~255页的写保护
  • 选项字节编程

  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的编程操作
  • 解锁FLASH_CR的OPTWRE位
  • 设置FLASH_CR的OPTPG位为1
  • 写入要编程的半字到指定的地址
  • 等待BSY位变为0
  • 读出写入的地址并验证数据
  • 选项字节擦除 

  • 检查FLASH_SR的BSY位,以确认没有其他正在进行的闪存操作
  • 解锁FLASH_CR的OPTWRE位
  • 设置FLASH_CR的OPTER位为1
  • 设置FLASH_CR的STRT位为1
  • 等待BSY位变为0
  • 读出被擦除的选择字节并做验证
  • 作者:上山的月

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 – FLASH 笔记

    发表回复