STM32 Flash

目录

1:Flash简介

2:嵌入式Flash特性

3:Flash 闪存的读取

4:闪存擦除

5:代码实现


1:Flash简介

FLASH存储器是闪速存储器,它的主要特点是在不加电的情况下能长期保持存储的信息。就其本质而言,Flash Memory属于EEPROM(电擦除可编程只读存储器)类型。它既有ROM的特点,又有很高的存取速度,而且易于擦除和重写, 功耗很小。

2:嵌入式Flash特性

  • 对于 STM32F40x 和 STM32F41x,容量高达 1 MB;对于 STM32F42x 和 STM32F43x,容量高达 2 MB
  • 128 位宽数据读取
  • 字节、半字、字和双字数据写入
  • 扇区擦除与全部擦除
  • 低功耗模式

 STM32F40x和STM32F41x Flash 模块构成

可以看到 

  1. 主存储器

该部分用来存放代码和数据常数(如const类型的数据)。分为12个扇区,前4个扇区为16KB大小,然后扇区4是64KB大小,扇区5~11是128K大小,从上图可以看出主存储器的起始地址就是0X0800 0000,B0、B1都接GND的时候,就是从0X0800 0000开始运行代码

   2.系统存储器

这个主要用来存放STM32F4的bootloader代码,此代码是出厂的时候就固化在STM32F4里面了,专门来给主存储器下载代码的。当B0接3.3V,B1接GND的时候,从该存储器启动(即进入串口下载模式)。

  3.OTP区域

即一次性可编程区域,共528字节,被分成两个部分,前面512字节(32字节为1块,分成16块),可以用来存储一些用户数据(一次性的,写完一次,永远不可以擦除!!),后面16字节,用于锁定对应块。

 4.选项字节

用于配置读保护、BOR级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。

3:Flash 闪存的读取

STM23F4的FLASH读取是很简单的。例如,我们要从地址addr,读取一个字(字节为8位,半字为16位,字为32位),可以通过如下的语句读取:

data=*(vu32*)addr;

将addr强制转换为vu32指针,然后取该指针所指向的地址的值,即得到了addr地址的值。类似的,将上面的vu32改为vu16,即可读取指定地址的一个半字。

 在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。

STM32F4的闪存编程由6个32位寄存器控制,他们分别是

  1. FLASH访问控制寄存器(FLASH_ACR)
  2. FLASH秘钥寄存器(FLASH_KEYR)
  3. FLASH选项秘钥寄存器(FLASH_OPTKEYR)
  4. FLASH状态寄存器(FLASH_SR)
  5. FLASH控制寄存器(FLASH_CR)
  6. FLASH选项控制寄存器(FLASH_OPTCR)

其中秘钥寄存器中有两个键值KEY1=0X45670123  KEY2=0XCDEF89AB

STM32F4 Flash标准编程的步骤如下

  • 检查FLASH_SR中的BSY位,确保当前未执行任何FLASH操作。
  • 将FLASH_CR寄存器中的PG位置1,激活FLASH编程。
  • 针对所需存储器地址(主存储器块或OTP区域内)执行数据写入操作:      

         —并行位数为x8时按字节写入(PSIZE=00)      

        —并行位数为x16时按半字写入(PSIZE=01)      

        —并行位数为x32时按字写入(PSIZE=02)      

        —并行位数为x64时按双字写入(PSIZE=03)

  •  等待BSY位清零,完成一次编程。

按以上四步操作,就可以完成一次FLASH编程。不过有几点要注意:1,编程前,要确保要写入地址的FLASH已经擦除。2,要先解锁(否则不能操作FLASH_CR)。3,编程操作对OPT区域也有效,方法一模一样。

4:闪存擦除

FLASH编程的时候,要先判断所写地址是否被擦除了,STM32F4的闪存擦除分为两种

  • 扇区擦除
  • 整片擦除

 

扇区擦除步骤

  1. 检查FLASH_CR的LOCK是否解锁,如果没有则先解锁
  2. 检查FLASH_SR寄存器中的BSY 位,确保当前未执行任何FLASH操作
  3. 在FLASH_CR寄存器中,将SER位置1,并从主存储块的12个扇区中选择要擦除的扇区 (SNB)
  4. 将FLASH_CR寄存器中的STRT位置1,触发擦除操作 等待BSY位清零

 

整片擦除步骤

  1. 检查 FLASH_SR 寄存器中的 BSY 位,以确认当前未执行任何 Flash 操作
  2. FLASH_CR 寄存器中的 MER 位置 1(STM32F405xx/07xx STM32F415xx/17xx 器件)
  3. FLASH_CR 寄存器中的 MER MER1 位置 1STM32F42xxx STM32F43xxx 器件)
  4. FLASH_CR 寄存器中的 STRT 位置 1
  5. 等待 BSY 位清零

5:代码实现

讲几个重要的函数

void FLASH_Unlock(void)
{
  if((FLASH->CR & FLASH_CR_LOCK) != RESET)
  {
    /* Authorize the FLASH Registers access */
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
  }  
}
//解锁用的,先查询CR寄存器的位31,看是否上锁,若上锁,则再给KEYR密钥寄存器写入两个密钥值进行解锁
void FLASH_DataCacheCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if(NewState != DISABLE)
  {
    FLASH->ACR |= FLASH_ACR_DCEN;
  }
  else
  {
    FLASH->ACR &= (~FLASH_ACR_DCEN);
  }
}
//FLASH擦除期间,必须禁止数据缓存,操作ACR访问控制寄存器的位10
uint16_t STMFLASH_GetFlashSector(u32 addr);
//根据要操作的地址,来查询处在哪个扇区

再来看看 FLASH_EraseSector扇区擦除函数中的核心部分

    /* if the previous operation is completed, proceed to erase the sector */
    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= tmp_psize;
    FLASH->CR &= SECTOR_MASK;
    FLASH->CR |= FLASH_CR_SER | FLASH_Sector;
    FLASH->CR |= FLASH_CR_STRT;
    
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();
    
    /* if the erase operation is completed, disable the SER Bit */
    FLASH->CR &= (~FLASH_CR_SER);
    FLASH->CR &= SECTOR_MASK; 
  1. CR控制寄存器位8、9置0
  2. 根据VCC来操作CR寄存器的位8、9
  3. CR寄存器位3~7置0
  4. 操作CR寄存器位3~6来选择要擦除的扇区,并置位1,激活扇区擦除
  5. 操作CR寄存器的位16来触发擦除操作
  6. 等待操作并查询SR寄存器,查询操作的状态
  7. 操作完成后,清除掉一些相应位

写入函数FLASH_ProgramWord

    FLASH->CR &= CR_PSIZE_MASK;
    FLASH->CR |= FLASH_PSIZE_WORD;
    FLASH->CR |= FLASH_CR_PG;
  
    *(__IO uint32_t*)Address = Data;
        
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation();

    /* if the program operation is completed, disable the PG Bit */
    FLASH->CR &= (~FLASH_CR_PG);
  1. CR控制寄存器位8、9置0
  2. 操作CR寄存器位8、9,来确定编程并行位数
  3. 操作CR寄存器的位0,来激活编程
  4. 把写入的数据放进扇区地址中
  5. 等待操作并查询SR寄存器,查询操作的状态
  6. 操作完成后,清除掉CR寄存器位0

至于读函数STMFLASH_ReadWord,那就很简单了

//读取指定地址的半字(16位数据) 
//faddr:读地址 
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu16*)faddr; 
}  

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章