[应用相关] STM32教程系列之FLASH

[复制链接]
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:37 | 显示全部楼层 |阅读模式
一、实现的功能
1.实现对STM32Fxxx的片内FLASH的擦除和烧写,并读出后进行检验。
2.用串口打印出检验FLASH内容是否正确的变量值。
二、实验操作及现象
1.双击FLASH.eww打开工程文件,然后进行编译。
2.用Flash Loader将程序下载到ARM内,或者利用JLINK等仿真器进行仿真。
3.在程序运行前,用串口线将开发板的串口1和PC机的串口1连接,并打开“串
口调试助手”,设置波特率为115200,将会看到每0.5秒显示一次“Flash Status=1”,
则说明FLASH操作成功,否则说明FLASH操作失败。
三、片内FLASH学习
大家可能会疑惑,既然我们可以利用工具将代码下载芯片内部,为什么还要讲解Flash编程呢?目的是让大家掌握后可以编写自己的BootLoader,例如用CAN总线接口来更新产品中的升级代码,不需要将产品拆卸即可完成。另外一个很重要的问题就是我们要保护好自己编写的代码,否则被破_解后,就成别人的产品了。
1.解除Flash锁   
复位后,闪存擦写控制器模块是被保护的,不能写入FLASH_CR寄存器,
通过写入两个关键字(KEY1,KEY2)到FLASH_KEYR寄存器打开闪存擦写控
制器,才可以进行其他闪存操作。其中KEY1为0x45670123,KEY2为0xCDEF89AB。
编程如下:
FLASH->KEYR = FLASH_KEY1;
  FLASH->KEYR = FLASH_KEY2;
2.页擦除
在FLASH操作中,每次擦除只能擦除一页,不能一个字节一个字节的擦除,其实所谓的擦出就是将指定的页全部填写成0XFF,下面是页擦除的过程:
   -检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
   -用FLASH_AR寄存器选择要擦除的页;
   -设置FLASH_CR寄存器的PER位为1;
   -设置FLASH_CR寄存器的STRT位为1;
   -等待BSY位变为0;
   -读出被擦除的页并做验证。
编程如下:
//等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  1. status = FLASH_WaitForLastOperation(EraseTimeout);
  2.   
  3.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进行页擦除操作
  4.   {
  5.    
  6.     FLASH->CR|= CR_PER_Set;//设置FLASH_CR寄存器的PER位为1
  7.     FLASH->AR = Page_Address;//用FLASH_AR寄存器选择要擦除的页
  8.     FLASH->CR|= CR_STRT_Set;//设置FLASH_CR寄存器的STRT位为1
  9.    
  10.     //等待擦除操作完毕(等待BSY位变为0)
  11.     status = FLASH_WaitForLastOperation(EraseTimeout);

  12.     if(status != FLASH_BUSY)//如果SR的BSY为0
  13.     {
  14.       //如果擦除操作完成,禁止CR的PER位
  15.       FLASH->CR &= CR_PER_Reset;
  16.     }
  17.   }


 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:37 | 显示全部楼层
全部擦除
全部擦除就是将全部FLASH都填写成0xFF,其过程如下:
   -检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
   -设置FLASH_CR寄存器的MER位为1;
   -设置FLASH_CR寄存器的STRT位为1;
   -等待BSY位变为0;
   -读出所有页并做验证。
编程如下:
//等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  1. status = FLASH_WaitForLastOperation(EraseTimeout);
  2.   
  3.   if(status == FLASH_COMPLETE)//如果FLASH出于可以操作状态,开始进行全部页擦除操作
  4.   {
  5.      FLASH->CR |= CR_MER_Set;//设置FLASH_CR寄存器的MER位为1
  6.      FLASH->CR |= CR_STRT_Set;//设置FLASH_CR寄存器的STRT位为1
  7.    
  8.     //等待全部页擦除操作完毕(等待BSY位变为0)
  9.     status = FLASH_WaitForLastOperation(EraseTimeout);

  10.     if(status != FLASH_BUSY)//如果SR的BSY为0
  11.     {
  12.       //如果擦除操作完成,禁止CR的PER位
  13.       FLASH->CR &= CR_MER_Reset;
  14.     }
  15.   }   
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:37 | 显示全部楼层
4. 编程
   编程就是将数据写入指定的FLASH地址,STM32的FLASH每次编程都是16位(在32位系统中,我们叫做半字),过程如下:
-检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作;
   -设置FLASH_CR寄存器的PG位为1;
   -写入要编程的半字到指定的地址;
   -等待BSY位变为0;
   -读出写入的地址并验证数据。
编程如下:
  1. //检查参数是否正确
  2.   assert_param(IS_FLASH_ADDRESS(Address));

  3.   //等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  4.   status = FLASH_WaitForLastOperation(ProgramTimeout);
  5.   
  6.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进行编程操作
  7.   {
  8.    
  9.     FLASH->CR |= CR_PG_Set;//设置FLASH_CR寄存器的PG位为1
  10.   
  11.     *(vu16*)Address = Data;//写入要编程的半字到指定的地址
  12.     //等待半字编程操作完毕(等待BSY位变为0)
  13.     status = FLASH_WaitForLastOperation(ProgramTimeout);

  14.     if(status != FLASH_BUSY)
  15.     {
  16.       //如果半字编程完毕,禁止PG位
  17.       FLASH->CR &= CR_PG_Reset;
  18.     }
  19.   }
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:38 | 显示全部楼层
5. 信息块擦除
   信息块的擦除主要是指对选择字节的擦除,选择字节组织如下:
RDP:读出保护选择字节
读出保护功能帮助用户保护存在闪存中的软件。该功能由设置信息块中的一个选择字节启用。写入正确的数值(RDPRT键=0x00A5)到这个选择字节后,闪存被开放允许读出访问。
USER:用户选择字节
这个字节用于配置下列功能:
− 选择看门狗事件:硬件或软件
− 进入停机(STOP)模式时的复位事件
− 进入待机模式时的复位事件
Data:用户数据,可由用户自己分配
WRPx:闪存写保护选择字节
用户选择字节WRPx中的每个位用于保护主存储器中4页的内容,每页为1K字节。总共有4个用户选择字节用于保护所有128K主闪存。
其擦除的过程如下:
-检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的闪存操作;
   -解除FLASH_CR寄存器的OPTWRE位;
   -设置FLASH_CR寄存器的OPTER位为1;
   -设置FLASH_CR寄存器的STRT位为1;
   -等待BSY位变为0;
   -读出小信息块并做验证。
编程过程如下:
  1. //等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  2.   status = FLASH_WaitForLastOperation(EraseTimeout);

  3.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进选择字节擦除操作
  4.   {
  5.     //解锁 CR寄存器中的OPTWRE位
  6.     FLASH->OPTKEYR = FLASH_KEY1;//输入选择字节键1
  7.     FLASH->OPTKEYR = FLASH_KEY2;//输入选择字节键2
  8.    
  9.     FLASH->CR |= CR_OPTER_Set;//设置FLASH_CR寄存器的OPTER位为1
  10.     FLASH->CR |= CR_STRT_Set;//设置FLASH_CR寄存器的STRT位为1

  11.     //等待选择字节擦除操作完毕(等待BSY位变为0)
  12.     status = FLASH_WaitForLastOperation(EraseTimeout);
  13.    
  14.     if(status == FLASH_COMPLETE)//如果选择字节擦除操作完毕
  15.     {
  16.       //如果擦除操作完毕,禁止OPTER位
  17.       FLASH->CR &= CR_OPTER_Reset;
  18.       
  19.       //使能选择字节编程操作
  20.       FLASH->CR |= CR_OPTPG_Set;

  21.       //使能读出访问
  22.       OB->RDP= RDP_Key; //选择字节擦除同时需要开放代码读出

  23.       //等待前次操作完毕
  24.       status = FLASH_WaitForLastOperation(ProgramTimeout);

  25.       if(status != FLASH_BUSY)//如果前次操作结束
  26.       {
  27.         //如果编程操作完毕,禁止OPTPG位
  28.         FLASH->CR &= CR_OPTPG_Reset;
  29.       }
  30.     }
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:38 | 显示全部楼层
6. 选择字节编程
   选择字节的编程就是向上面讲到的选择字节里面写入指定的数据,其过程如下:
-检查FLASH_SR寄存器的BSY位,以确认没有其他正在进行的编程操作;
   -解除FLASH_CR寄存器的OPTWRE位;
   -设置FLASH_CR寄存器的OPTPG位为1;
   -写入要编程的半字到指定的地址;
   -等待BSY位变为0;
   -读出写入的地址并验证数据。
编程过程如下:
  1. //等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  2.   status = FLASH_WaitForLastOperation(ProgramTimeout);

  3.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进行编程操作
  4.   {
  5.     //解锁 CR寄存器中的OPTWRE位
  6.     FLASH->OPTKEYR = FLASH_KEY1;
  7.     FLASH->OPTKEYR = FLASH_KEY2;
  8.    
  9.     FLASH->CR |= CR_OPTPG_Set;//设置FLASH_CR寄存器的OPTPG位为1
  10.     *(vu16*)Address = Data;//写入要编程的半字到指定的地址
  11.    
  12.     //等待半字编程操作完毕(等待BSY位变为0)
  13.     status = FLASH_WaitForLastOperation(ProgramTimeout);

  14.     if(status != FLASH_BUSY)
  15.     {
  16.       //如果半字编程完毕,禁止OPTPG位
  17.       FLASH->CR &= CR_OPTPG_Reset;
  18.     }
  19.   }
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:39 | 显示全部楼层
7.STM32的代码保护
通过选择字节的设置,可以实现代码的读保护和写保护,在上面6中讲到的,RDP和WRP分别是读保护和写保护,将RDP设置指定的数值,可以实现代码的读 保护,也就是不允许任何设备读取FLASH里面的应用代码,将WRP里设置指定的数值,可以实现代码的写保护,不允许任何设备改写FLASH里面的应用代 码。其中设置读保护的代码如下:
  1. //等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  2.   status = FLASH_WaitForLastOperation(EraseTimeout);

  3.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进行指定操作
  4.   {
  5.     //解锁 CR寄存器中的OPTWRE位
  6.     FLASH->OPTKEYR = FLASH_KEY1;
  7.     FLASH->OPTKEYR = FLASH_KEY2;
  8.     //擦除整个选择字节区域
  9.     FLASH->CR |= CR_OPTER_Set;
  10.     FLASH->CR |= CR_STRT_Set;

  11.     //等待擦除操作完毕
  12.     status = FLASH_WaitForLastOperation(EraseTimeout);

  13.     if(status == FLASH_COMPLETE)//如果擦除操作完毕
  14.     {
  15.       //禁止OPTER位
  16.       FLASH->CR &= CR_OPTER_Reset;

  17.       //使能选择字节编程操作
  18.       FLASH->CR |= CR_OPTPG_Set;

  19.       if(NewState != DISABLE)//禁止读出操作
  20.       {
  21.         OB->RDP = 0x00;
  22.       }
  23.       else//使能读出操作
  24.       {
  25.         OB->RDP = RDP_Key;  
  26.       }

  27.       //等待写入完毕
  28.       status = FLASH_WaitForLastOperation(EraseTimeout);
  29.    
  30.       if(status != FLASH_BUSY)
  31.       {
  32.         //写入操作完毕,禁止OPTPG位
  33.         FLASH->CR &= CR_OPTPG_Reset;
  34.       }
  35. }
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:39 | 显示全部楼层
写保护代码如下:
  1. //等待前次操作完毕(检查FLASH_SR寄存器的BSY位)
  2.   status = FLASH_WaitForLastOperation(ProgramTimeout);
  3.   
  4.   if(status == FLASH_COMPLETE)//如果FLASH处于可以操作状态,开始进行编程操作
  5.   {
  6.     //解锁 CR寄存器中的OPTWRE位
  7.     FLASH->OPTKEYR = FLASH_KEY1;
  8.     FLASH->OPTKEYR = FLASH_KEY2;
  9.     //设置FLASH_CR寄存器的OPTPG位为1
  10.     FLASH->CR |= CR_OPTPG_Set;

  11.     if(WRP0_Data != 0xFF)//如果不是全部不写保护
  12.     {
  13.       OB->WRP0 = WRP0_Data;//写入WRP0
  14.       
  15.       //等待写入操作完毕
  16.       status = FLASH_WaitForLastOperation(ProgramTimeout);
  17.     }
  18.     if((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF))
  19.     {
  20.       OB->WRP1 = WRP1_Data;
  21.       
  22.       //等待写入操作完毕
  23.       status = FLASH_WaitForLastOperation(ProgramTimeout);
  24.     }

  25.     if((status == FLASH_COMPLETE) && (WRP2_Data != 0xFF))
  26.     {
  27.       OB->WRP2 = WRP2_Data;
  28.       
  29.       //等待写入操作完毕
  30.       status = FLASH_WaitForLastOperation(ProgramTimeout);
  31.     }
  32.    
  33.     if((status == FLASH_COMPLETE)&& (WRP3_Data != 0xFF))
  34.     {
  35.       OB->WRP3 = WRP3_Data;
  36.      
  37.       //等待写入操作完毕
  38.       status = FLASH_WaitForLastOperation(ProgramTimeout);
  39.     }
  40.          
  41.     if(status != FLASH_BUSY)
  42.     {
  43.       //如果编程操作完毕,禁止OPTPG位
  44.       FLASH->CR &= CR_OPTPG_Reset;
  45.     }
  46.   }   
 楼主| 小狗爱吃骨头 发表于 2015-9-29 22:39 | 显示全部楼层
8.STM32有3种启动模式:
第1种:上电前BOOT0脚为0,BOOT1脚是0或者1,上电后直接进入FLASH执行应用程序。
第2种:上电前BOOT0脚为1,BOOT1脚为0,上电后进入芯片的自举程序(LOADER代码,厂家写好固化到芯片里的专门用于串口下载代码的程序),一般我们烧写程序的时候进入此模式。
第3种:上电前BOOT0脚为1,BOOT1脚为1,上电后进入芯片的SRAM,一般我们很少使用这个模式

paderboy 发表于 2015-9-29 23:46 | 显示全部楼层
多谢分享,学习了。。。
yiyigirl2014 发表于 2015-9-30 07:56 来自手机 | 显示全部楼层
Data:用户数据,可由用户自己分配 WRPx:闪存写保护选择字节
豆腐块 发表于 2015-9-30 20:53 | 显示全部楼层
提醒下,Flash擦写的时候必须保持N个周期,否则将导致复位。通常会关闭总中断,在完成后再开启。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

286

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

28

主题

286

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部