你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 FLASH 擦除(防误擦除程序代码)、写入

[复制链接]
植物大战奥特曼 发布时间:2016-6-29 13:43
编译环境:我用的是(Keil)MDK4.7.2   
) d$ k" W4 L' V9 @- u1 _/ Vstm32库版本:我用的是3.5.0, Y4 j7 z2 e  C8 e# @
一、本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料。. P8 h+ N6 X- s5 S1 }
  对STM32 内部FLASH进行编程操作,需要遵循以下流程:  Y5 @7 E/ L3 t" B
  FLASH解锁% c2 s' q  K3 a" S; r1 }2 D, n0 B
  清除相关标志位
" `8 U+ A4 a  A6 T; K4 J: h  擦除FLASH(先擦除后写入的原因是为了工业上制作方便,即物理实现方便)% E, p5 m0 C+ H, L* \7 \
  写入FLASH* o% T0 ~) m2 Z. M, T+ @
  锁定FLASH: A3 F  ~9 k. J7 c* w% |
实例:
$ V  P/ b7 P- Q; u#define FLASH_PAGE_SIZE    ((uint16_t)0x400) //如果一页为1K大小
* J, t; I: M$ h1 Z1 l% c( V#define WRITE_START_ADDR   ((uint32_t)0x08008000)//写入的起始地址
1 R# R) A9 M  Z* O4 S/ h+ n) w#define WRITE_END_ADDR      ((uint32_t)0x0800C000)//结束地址# o" F' g+ |( o/ I2 {' A
uint32_t EraseCounter = 0x00, Address = 0x00;//擦除计数,写入地址
' e% {# p2 s. i" Kuint32_t Data = 0x3210ABCD;//要写入的数据4 \; ~$ @6 f! `" m
uint32_t NbrOfPage = 0x00;//记录要擦除的页数
9 r  {1 u4 ]: ~volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH擦除完成标志*/
4 A3 ]: y& e1 u" x, O% rvoid main()3 Q8 F# z9 N/ e7 l, V" @+ }
{# m; P# J/ N; q7 m/ ?
  /*解锁FLASH*/# l8 X0 S) {! {9 ?+ [$ [* l- m2 K/ e# }: ^
 FLASH_Unlock();* l% M1 s9 P2 b* @
  /*计算需要擦除FLASH页的个数 */  k  ?) S. _  V5 o; x
 NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;0 |8 K) u7 c0 |( D4 R1 O* ?3 f
  /* 清除所有挂起标志位 */
% a/ R- c; J! \, Q0 j  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);        
4 `6 s7 f; l" ]% \; H& `  /* 擦除FLASH 页*/
% S, S( n  U3 E: f: K7 a for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)5 f! U& @  ~8 L9 A/ d( |
    {
1 x# v7 v8 }% T5 ~" s, r      FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));8 E. e& U  \0 t; g$ v! [" O/ I3 Q; O
    }# @2 ]; G2 l' M; q. P  \  O' W
  /* 写入FLASH  */- U! h$ _4 P* F& b2 S
 Address = WRITE_START_ADDR;7 t; S7 x: n. p
 while((Address < WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
1 E7 O3 x1 v1 u; D2 a# u8 x% `    {  E( w6 }4 h  Q' b7 W" b) ]) D
      FLASHStatus = FLASH_ProgramWord(Address, Data);" h6 {  i9 P8 ^( V5 f2 O
      Address = Address + 4;7 D( P$ u# o7 p$ ?' A1 c
    }8 ~2 d# |- j; O9 E" T
/* 锁定FLASH  */7 B) B8 u1 ~2 v' }, Z" |
 FLASH_Lock();  b# U4 u3 Q' y4 l7 u* D
}" t3 p' w5 @0 \, P
二、FLASH 擦除(以及防止误擦除程序代码)
7 W7 z8 Q: g' V% U- y1、擦除函数0 d) s3 F9 k! _+ V5 V
FLASH_Status FLASH_ErasePage(u32 Page_Address)只要()里面的数是flash第xx页中对应的任何一个地址!就是擦除xx页全部内容!
) @  d( w: @/ Q* } 11.png ( T& e9 e/ o: B" O. L3 [
防止误擦除有用程序代码的方法
, S4 c6 A1 K* F& s. H# g( Z. P方法一:首先要计算程序代码有多少,把FLASH存取地址设置在程序代码以外的地方,这样就不会破坏用户程序。原则上从0x0800 0000 + 0x1000 以后的FLASH空间都可以作为存储使用。如果代码量占了 0x3000, 那么存储在 0x0800 0000+ 0x4000 以后的空间就不会破坏程序了。
9 _" E1 ?: l( U! T% p5 |
3 R& U/ x, G1 i& s- ^  J1 o方法二:先在程序中定义一个const 类型的常量数组,并指定其存储位置(方便找到写入、读取位置),这样编译器就会分配你指定的空间将常量数组存入FLASH中。当你做擦除。读写操作时,只要在这个常量数组所在的地址范围就好。
7 c$ L. l* \1 a2 Y) x
, X) F5 }! L, h8 p2 x) v  const uint8_t table[10] __at(0x08010000) = {0x55} ;5 ~" a  ~9 |. Y3 h& ~
  MDK3.03A开始就支持关键字 __at() 。; u# X- ^% p% Z3 j* f, I
  需要加#include <absacc.h>
" o. P, h0 z+ q+ t) c4 H
1 r7 D8 w# \8 a& i# f2 I方法三:在程序中定义一个const 类型的常量数组,无需指定其存储位置。只要定义一个32位的变量存储这个数组的FLASH区地址就行。
! m8 W2 t4 ~3 f9 j- i2 `
$ I9 `, g: |8 ~. `# l2 x4 n1 J  uint32_t address;//STM32的地址是32位的
. s3 ~# x2 a* X5 B  const uint8_t imageBuffer[1024] = {0,1,2,3,4,5,6,7};
: ~8 g8 ~  e. \  address = (uint32_t) imageBuffer;/*用强制类型转换的方式,可以把FLASH中存储的imageBuffer[1024]的地址读到RAM中的变量address 里,方便找到写入、读取位置*/
1 d1 _" }' ^3 \# M: [: L; W8 r) f6 J3 X+ s  `
方法四:利用写保护的方式(没研究明白)9 n0 w3 u) t7 t) C, ~; E

/ H# {* G, m+ V0 |7 j* G6 U! h三、FLASH写入/ Z3 n8 z! z, I* @1 {0 @& |5 x/ l/ _
  FLASH的写入地址必须是偶数(FLASH机制决定的FLASH写入的时候只能是偶数地址写入,必须写入半字或字,也就是2个字节或是4字节的内容)
3 Z5 y! k% b) ]" W 12.png - c& e8 Z  f0 e/ @
13.png / n9 z5 o' P1 {& `7 ?
8 c# @& A; p3 U; @1 Z2 {, Q5 Q  z
四、FLASH 读取方法
! a( E9 j6 p$ M7 n  *(uint32_t *)0x8000000;//读一个字' F* T! ?/ V7 F8 z
  *(uint8_t *)0x8000000;//读一个字节;
. a1 O  ^1 e; g; H  *(uint16_t *)0x8000000;//读半字;  
  a" T5 p. A8 \  举例:
! G- d( x4 p, U$ Z  uint8_t data;
; G: f9 s+ I2 J6 c( k  data = *(uint8_t *)0x8000000;//就是读取FLASH中地址0x8000000处的数据- \1 V  H( u5 W: H* O8 X
五、几个有用的子函数$ G; L. K7 n! v+ R# @+ A
/*
5 Y9 g: H9 j5 J功能:向指定地址写入数据2 V1 ?0 U( K- z; U2 N
参数说明:addr 写入的FLASH页的地址/ _+ a& e$ ]8 @4 o% i6 M7 F) ?% \9 o9 }
          p    被写入变量的地址(数组中的必须是uint8_t类型,元素个数必须是偶数)
1 x1 p+ }# ]# t+ j0 S/ }          Byte_Num 被写入变量的字节数(必须是偶数)
- S( K' j, z7 D+ Z6 l7 G2 ^*/
  \- G% l, }+ b( u- }/ B" G9 p# E  void FLASH_WriteByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num)
1 V: B$ h+ P2 J% C  {
2 _! D3 U# c; g: }! d          uint32_t HalfWord;; _" v$ Q4 N6 |' u3 o1 D
          Byte_Num = Byte_Num/2;
. M$ x& k7 H* N* G4 ~          FLASH_Unlock();7 O7 p6 p- @1 K* W+ S' }
          FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
3 `* F& R$ v* C( v" h+ ^          FLASH_ErasePage(addr);" y$ I: O% t* j, Q; R
          while(Byte_Num --)
1 N) M" @/ y' ~2 x/ i          {
- F. L* ^; T* h7 D                  HalfWord=*(p++);9 I' {5 z" Y  B5 n
                  HalfWord|=*(p++)<<8;: H- D0 r, m# d7 j) l
                  FLASH_ProgramHalfWord(addr, HalfWord);' ?% h0 p8 F8 X# i
                  addr += 2;
3 Z$ A9 K1 {* k! U7 V( [          }
2 v+ B& y/ t. Q4 W: m( G          FLASH_Lock();
' b/ t6 b" Z: W: R  }
4 E7 D. M6 P: v1 h4 Y0 X0 Z  例:, p3 \7 D( B3 L3 ]# e$ ]
  uint8_t data[100];6 S1 Z/ V1 |& i; \7 V
  FLASH_WriteByte(0x8000000 , data , 100);/*数组data的数据被写入FLASH中*/
" _% ~" Q( h0 y* s! ^# h; [/*7 _) V3 S. D% t/ L$ }+ C
功能:从指定地址读取数据
/ f# x+ w- V! R# D. A2 ?. I& s参数说明:addr 从FLASH中读取的地址3 g$ s: O* q0 B8 E
          p    读取后要存入变量的地址(数组中的必须是uint8_t类型)' ]% a) ^# A7 d6 h& y6 _1 \8 |# M* Y
          Byte_Num 要读出的字节数  S0 L0 s: x# ?9 t; P& z- y
*/
0 q/ e7 w. T: Y1 H  void FLASH_ReadByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num)5 |8 ]6 p- C1 p- M' c5 N( S9 [9 {
  {
6 r$ v: L2 Z* n/ z! m5 _+ U    while(Byte_Num--)
. D! C  e0 H1 Q1 h2 d    {
' O( H4 e4 \5 O% _* A) l0 w5 l6 \1 Q     *(p++)=*((uint8_t*)addr++);9 k( I4 J; J# h& e4 @/ ?1 Q
    }, H5 u' ]" z# F/ c3 D+ u5 B+ R7 Z
  }- G: R* [. }: H8 H
  例:2 b. U0 B. ?8 X& \
  uint8_t data[101];
) F  L  q# O/ A4 l' ]( ?1 N  FLASH_ReadByte(0x8000001 , data , 101);/*FLASH中的数据被读入数组data中*/
: z/ F6 k8 q& l4 G2 t
* |* |! X- G) w/ N. N. Q- Q
赞 收藏 1 评论2 发布时间:2016-6-29 13:43

举报

2个回答
stary666 回答时间:2016-6-30 12:54:18
Lumhao 回答时间:2016-7-1 18:08:57
好长啊
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版