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

【经验之谈】基于STM32F103神操作--如何快速读写内部flash?的经验分享

[复制链接]
STMCU小助手 发布时间:2022-12-9 18:00

一、芯片FLASH容量分类:

" g- T7 Z" o: D+ o  T* O1 H
可以看到我们今天介绍的这款芯片的flash大小是64K的,网上也有人说它可以支持到128K,但是官方给出的解释是前64K是有保证的,后面的无法保证,所以想要使用的小伙伴需要慎重。
* a4 R& v5 Q, P+ X现在芯片的flash大小我们知道了,下面就可以看看这个flash是怎么划分的了,通过芯片数据手册,我们能看到今天说的STM32F103C8T6是属于中等容量的设备。

既然是中等容量的设备了,那我们就来看看flash划分吧,在STM32的闪存编程手册中有这样一段话:按照不同容量,
" d& i, v% a/ w3 `, x" F6 x存储器组织成:
3 {% S2 ~( J) m1 q' s32个1K字节/页(小容量)
' x  l; N& v, Q% l  T  O+ |4 T128个1K字节/页(中容量)
+ p, H7 k+ x2 }$ c. O  _- T256个2K字节/页(大容量)
: b  O7 t  f: A- E这段话怎么理解呢,就是告诉我们小容量的设备(内存是6K和32K)的设备是由1K字节每页组成的,; Q0 _; E4 t  `" S9 ^. f: g
中容量的设备(内存是64K和128K)的设备是由1K字节每页组成的,
! |+ t: r3 e5 D9 o- \. n大容量的设备(内存是256K、384K和512K)的设备是由2K字节每页组成的,: Y5 b5 Q2 n9 Y8 O
举个例子吧:
2 F3 z! `. S# {: f* j; o, T6 b一个芯片的存储容量是64K,这64K是什么呢,就是64*1024个BYTE,一个BYTE是由8位0或1组成的,(比如0000 1111 这8个二进制数组成了一个字节,用十进制来说就是15)4 S2 I) \/ _+ L: T+ K9 Q/ Q  z
小结一下:64K的flash可以存储64*1024个字节的数据。# R! _$ z% x, e/ D) ^: U
咱们继续说,这64K的数据怎么划分,存储是按照页为单位进行存储的,一页1K的容量,也就说一页可以存储1024个字节* D3 R" K: W/ T9 ?$ F
一共是多少页?
+ n, @) x9 m& U! ~答案是:64页,我们看一下官方是不是这么说的

在闪存编程手册里确实是这么说的,所以我们刚才说是64页是正确的

( {9 M! U. R% o! f% H
二、 读写步骤:# ~9 @+ ~( ?9 m; p1 o1 f" p) Y3 H
上面我们知道了芯片是怎么分类的,下面我们就重点来讲解一下芯片是怎么读写的。
" t! ?% s1 n7 t& e3 p/ j/ E, m内部flash我们参照HAL库或者标准库,直接调用ST公司给我们封装好的库进行编程就可以了,这里我用的是标准库,有兴趣的小伙伴可以去看看HAL库, E4 w* }$ p& t
是不是有小伙伴会疑问什么是标准库,什么是HAL库?: l2 l$ k+ Q  m$ |* P/ q5 Z. l1 o
在这里给大家解释一下,这两个库都是ST公司,直接把寄存器封装成函数,供大家直接调用某一个函数,就可以完成各种寄存器的配置,不容大家直面芯片的寄存器,方便阅读和使用,因为每个函数的名称功能都是不一样的,在调用前可以参考函数的注释,在F0和F4的标准库里甚至有每个函数的用法,不知道为什么在F1的库里把使用步骤去掉了。
7 D& B! G( `% N0 i, X. r+ G. M咱们继续,读写的话库函数分为:

  1. /*------------ Functions used for all STM32F10x devices -----*/8 s+ \/ Y  l6 _$ H& D( q) f
  2. - z) V  R6 n5 j& j& r2 a! {
  3. void FLASH_SetLatency(uint32_t FLASH_Latency);" }% Q+ Z; l8 g1 h
  4.   @5 [6 n3 ]1 z7 x$ Q  C1 E
  5. void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);8 I# P6 y+ Z1 @2 q- ?

  6. * G( i- l  B( O6 d3 t* M
  7. void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);2 F& o3 v' X% c( t8 _( y3 k

  8. 1 q/ ]. _+ n6 ~3 S9 I$ F  M
  9. void FLASH_Unlock(void);
    . x& O3 v5 K; z# o
  10. 8 q% z, b7 a/ I( e
  11. void FLASH_Lock(void);
    4 x$ t) |) {. r- a6 N  v' U

  12. 5 A) v( r2 e' d! {% y- c& U
  13. FLASH_Status FLASH_ErasePage(uint32_t Page_Address);# l7 T2 {  {0 E6 d* ], q! m

  14. : k9 i5 y- F" N( z
  15. FLASH_Status FLASH_EraseAllPages(void);. B7 I8 F3 t5 q( {' v* [

  16. 5 v% Q8 v8 Y7 p0 e: r# |
  17. FLASH_Status FLASH_EraseOptionBytes(void);/ A& J; X3 n, f' Y# e9 x
  18. 1 {6 s: X; m- d0 u* ^( C
  19. FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
    # L1 O# w. x. \! A0 G2 M

  20. 6 j; Q( {7 [7 C* U0 r; a
  21. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
    1 E% }7 Q% G/ c0 T* j. s0 D- k

  22. - C; F& }% P$ w7 k
  23. FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);. ]& u" E) Z/ _" X

  24. : a3 _  Q0 `- m+ ~# G; s% ^5 z
  25. FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);5 d3 T, {/ \! ^

  26. 4 F( _9 [9 K0 X/ Y* S4 n9 |& `* G
  27. FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);+ L& D+ g( u" {  G$ ?

  28. + X! x) [9 F7 r* l
  29. FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);9 G, C5 a- P0 p( r7 v* W

  30. 5 Q- f: |& h& v; w9 ]5 T9 M
  31. uint32_t FLASH_GetUserOptionByte(void);) T0 [: n( t; X9 H: h( m
  32. : i. l+ n2 T& T+ q8 y4 q4 l
  33. uint32_t FLASH_GetWriteProtectionOptionByte(void);* ^8 E% F( j. ]

  34. & V4 I$ }9 ~3 v) n6 r6 @
  35. FlagStatus FLASH_GetReadOutProtectionStatus(void);( o4 N. k5 x5 ~

  36. - T& }- n8 j7 l) o& ]4 I
  37. FlagStatus FLASH_GetPrefetchBufferStatus(void);. L. Q- E1 G" D, m2 x( x' Y8 V& a

  38. 9 B0 g- r& q1 l$ e( w. E/ w0 h
  39. void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);
    : z* v9 T! p' J( q7 r6 \3 v
  40. ' i% [, o1 M3 R5 p4 t
  41. FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);: D! h, w, ], [4 i4 x; U

  42. ; u+ w* b, @( {& A' x
  43. void FLASH_ClearFlag(uint32_t FLASH_FLAG);
    1 ?0 ?! Y. V5 S; I% V! `
  44.   f( q  ]) r( `3 n9 F; g1 k
  45. FLASH_Status FLASH_GetStatus(void);
    ' T/ B5 g0 J8 ^) f1 G0 N! q$ A
  46. ( l1 ]6 R9 G/ \
  47. FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
    ( Y* @$ t( A7 p1 L

  48. 9 ]; t4 E% w) T+ S
  49. $ m2 P8 X6 ^+ g. M5 \, H) w
  50. 5 t' `$ D$ [5 S* o2 x
  51. /*------------ New function used for all STM32F10x devices -----*/
    0 R4 Y/ g/ N, |/ J# x" U* m; q
  52. 9 W" _. L( U8 }7 n0 j& \2 b
  53. void FLASH_UnlockBank1(void);
    ( |; s2 u! \3 I6 m
  54.   {! E8 ~! a+ M# y
  55. void FLASH_LockBank1(void);* n5 }' G3 T' d1 u2 S/ K, l
  56. 3 m' o$ u/ T& {3 U2 C/ A- A3 \
  57. FLASH_Status FLASH_EraseAllBank1Pages(void);
    & {8 J2 A: \! a$ R- p8 X

  58. 5 Q7 J! h$ ]  B
  59. FLASH_Status FLASH_GetBank1Status(void);* F/ x. S7 w% O. _$ \" X  X

  60. 4 W6 W' w2 ?+ s* `+ C3 K
  61. FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout);
复制代码
3 V+ S3 Z6 y, Y6 B

& ^. x9 T( n5 ^+ n+ W

在这里就不一个一个的详细说了,我们说一下常用的就行
0 C$ G2 V1 A# z3 s2 T! W  S# G1. 解锁

void FLASH_Unlock(void);; |' C, s3 O3 }' Z


" ~4 l: ~, Z) n" n+ I2. 上锁

void FLASH_Lock(void);
7 [6 b# l3 \. o. M2 R

* _. P! {8 X. y& R. }% y( ^
3. 页擦除

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);4. 半字写入9 t+ d( ^/ Q! d* `
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);上面这4个函数就是我们最常用的。下面说一下数据写入的步骤,第一步:解锁第二步:判断写入的数据是否被擦除过,也就是判断写入的地址内存放的是不是0xFFFF 这里要重点说一下,为什么要判断是不是0xFFFF而不是判断是不是0xFF呢?因为我们每次写入数据都要写入半字,也就是两个字节的数据才行,而且写入的地址只能是2的整数倍,不能是奇数。这里大家注意一下。第三步:写入数据 STM32F103C8T6只能按照半字的方式进行数据写入,写入前的数据必须是0XFFFF,因为FLASH数据写入,只能写0,不能写1,这也就是为什么我们要先确保写入前的数据是被擦除了的原因。第四步:上锁第五步:验证写入是否正确其实第五步可以省略。我们看看官方给的写入过
1 q6 G1 u. x2 g9 e


* C  [. D, B# W: k* o1 q好了,其实是一样的。& O/ Q( s9 j" L- w7 t; B7 S
下面我就和大家来分享一下(百分之九十九参考的正点原子的例程)

  1. //不检查的写入1 G( s3 O2 y0 q+ W6 q% H' b( c9 c. ?
  2. " W+ z# B8 _8 P  j7 F& K  ]. K
  3. //WriteAddr:起始地址9 v' u' ]' ^2 E( ~
  4. $ i  g" ?; m7 [: _
  5. //pBuffer:数据指针
      U8 ]& s+ p) A" _& P5 X' W) l( l

  6. ( m2 q3 W1 a1 ]& x
  7. //NumToWrite:半字(16位)数   
    , {1 e, [3 N/ c; C- d
  8. ' o" W2 p9 j& ^  \6 H5 i
  9. void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   / l7 Q. {- c4 O  F/ x. s; |

  10. 7 T. X  v) ]+ h5 u+ s/ i
  11. {                                          
    ! D) Q% J0 s/ U3 V% X
  12. 4 ~8 B& A2 l, @! S
  13.         u16 i;! Q5 P/ `9 q8 ^- v# x

  14. ; }6 f- \. w/ X% q& c1 _, T' u
  15.         for(i=0;i<NumToWrite;i++)
    ) N' B/ H% y8 l
  16. ( I; Y' Q$ {4 X% Q: u, e9 Y
  17.         {1 C" c9 j4 R8 ?! O7 ?

  18. ' R5 }+ }# @5 v( F* L
  19.                 FLASH_ProgramHalfWord(WriteAddr,pBuffer);; j8 C* H$ y  v$ n

  20. / U3 ^- Q1 z& v: j, K, W
  21.             WriteAddr+=2;//地址增加2.& [+ z( r0 {+ o- Q, g1 T
  22. 0 L- A) X* L  `- K7 R) E" q
  23.         }  ' {/ G, K: }# i& e
  24.   w5 w- v" ~* o  y6 e7 N+ i
  25. }
复制代码
  1. //从指定地址开始写入指定长度的数据
    3 j& G$ M( M" H" e5 q; P
  2. : k2 ]- y4 Y3 p- y1 U, C2 Z
  3. //WriteAddr:起始地址(此地址必须为2的倍数!!)
      o* h% o7 H3 T' N0 ]
  4. * c$ S8 c; b# y4 A% g
  5. //pBuffer:数据指针
    ' j/ n& Q( I' P* N1 o5 f6 ?* T
  6. 0 A7 J. z4 O# }1 V+ E: D: k
  7. //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
    6 m$ y  b8 B1 G  f6 W
  8. ) f  p3 E& L$ p9 W5 L2 A- |

  9. ( ~" a# s, C5 C/ Q* S, I" G; F

  10. 0 e; Z8 t2 q  \
  11. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节: ?4 T2 `/ c6 h
  12. # h& d1 f- q' r" w. O
  13. void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)        
    1 C% Y$ k7 l$ K' [

  14. 3 \- M" ]2 t- Z, ^- z
  15. {
    + B/ `$ ~/ a# S4 m
  16. 2 v  k1 m6 K+ H# ^' u. P9 U
  17.         u32 secpos;           //扇区地址1 T8 f; p9 r. V$ V7 G$ {
  18. / z% x' c( Y% f. H. r; `) w& i
  19.         u16 secoff;           //扇区内偏移地址(16位字计算)8 o- X6 q+ o* V9 ?

  20. 5 j& j; _2 r* p; k: M6 r: s* ]) c% f
  21.         u16 secremain; //扇区内剩余地址(16位字计算)           
    ! v; R0 F, t3 ~* P
  22.   X  E; R/ C5 C- g
  23.          u16 i;   
    ! g/ X4 R! y% D; X

  24. 7 i/ o- H! S9 ~- l. s( v' E
  25.         u32 offaddr;   //去掉0X08000000后的地址$ }* R$ p/ u, l: {! k% u+ R
  26. & S$ Y) a2 R2 q% A
  27.         if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
    , x5 M$ Y6 [8 L( T0 k0 s
  28. ! }( X8 p; o) [7 W' R! E& J- S
  29.         FLASH_Unlock();                                                //解锁4 M% |8 N4 f" j& v" o/ T

  30. & f1 F4 E/ q, u7 @3 U2 w
  31.         offaddr=WriteAddr-STM32_FLASH_BASE;                //实际偏移地址.3 i1 q; n5 N, d2 b

  32. % e' j, n( E: P: l
  33.         secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6
    8 A' J0 f7 ]0 x9 L( {
  34. 8 \7 o2 q7 s/ ~' g
  35.         secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单位.)( y/ \+ B3 s9 M( V6 h; q, R* y" A
  36. 2 j9 V2 k6 R5 ~+ X
  37.         secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小   
      t8 }# r8 F- q$ J

  38. - b) F6 }, d+ ^1 Q% Z: k: N. L
  39.         if(NumToWrite<=secremain)
    7 p& S6 u6 ?  Z& \" c6 H
  40. 7 v; Y) i1 u: @* u
  41.         {
    ; I. L' D. t' {8 E4 v& G, X/ T

  42. " s4 c2 a! O/ m4 _
  43.           secremain=NumToWrite;//不大于该扇区范围
    ' x4 g- @% m5 K5 R6 s  k( b& s

  44. # M/ ]! p3 f) J& D- M
  45.         }
    6 G6 A$ {  J2 K% I  A! q, }) b
  46. ' N& x1 D' W( o; c
  47.         while(1) ' Z$ G5 [% E& }9 ]0 V; c9 G

  48. / w! j: B) R/ N* O; J
  49.         {        " Q. w, U) {5 I% J
  50. 1 c5 j' B, F" c& q8 C! y1 D: M4 V" M
  51.                 STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
    8 w( g5 M9 t% V. M

  52. * ]0 Z" \; [) i+ T- ]8 o0 S* Y
  53.                 for(i=0;i<secremain;i++)//校验数据
    , p5 H5 z. W- z" q* v
  54. 5 z# H3 \7 G+ [9 ^0 \2 N2 A
  55. //                for(i=0;i<(STM_SECTOR_SIZE/2);i++)//校验数据
    # F" Z8 I" g8 {% j& ]% B
  56.   ?4 W) r1 ?( [  [+ |* ^
  57.                 {
    5 u% D% @% y7 \8 Z9 n# I, Z

  58. ' O0 [% \. W4 ]
  59.                         if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  
    / o2 s+ W  I/ A" d
  60. 6 ^2 `1 c& q1 X' J: R; ]
  61. //        if(STMFLASH_BUF!=0XFFFF)break;//需要擦除                        
    ; i1 K5 }# N# K6 v
  62. : z3 Y( {; h# m% @  ?* R- M
  63.                 }
    $ H, b+ B' G/ `9 s# @0 g
  64. ( s4 B# W6 }: }" }5 @1 D9 y7 K/ G
  65.                 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    9 ]0 S# o& J$ M0 e! L! v

  66. . r$ m+ b# h$ O. @) U+ |) e
  67.                 if(i<secremain)//需要擦除
    ! k: H4 Z2 @+ |# `6 E. s* v; h% B% F! G
  68. / E1 B; l4 n' U1 f" L
  69. //                if(i<(STM_SECTOR_SIZE/2))//需要擦除2 @; r9 C, X: g- a

  70. & H- e' \# l% C6 Z" V
  71.                 {" ^2 O5 F- S4 }/ F4 f4 n2 `4 o

  72. : U0 q) `/ ?+ C2 c& w+ u' M2 {
  73.                         FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
      U' I  m* a8 a
  74. 4 s' Q& v; _# b) x- ?
  75. - Z4 C# f9 L6 p

  76. % u0 j0 r* k$ t# z
  77.                         FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区; w0 q! X* f) ~; A2 G3 @

  78. * R, Z  d! n5 @
  79.                         for(i=0;i<secremain;i++)//复制
    " x4 u8 V" v9 g' k: z

  80. / p9 K7 k7 V0 ?! s8 q+ \6 z8 A
  81.                         {! k: G! X' p( W( `- y5 y. R

  82. 2 g9 |) B' D% ^
  83.                                 STMFLASH_BUF[i+secoff]=pBuffer;          ; ]1 V& Y. U9 B( p' e4 U; w9 k
  84. & k  Z2 }1 W4 Q
  85.                         }1 @- u0 w" F$ @* \. I

  86. $ M, c( s" s3 j# h3 K. V
  87.                         STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
    & R7 `! J6 Y* o! b' p2 G1 X0 t# k
  88. - g. K) N0 L2 x: |7 \. B1 T
  89.                 }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                    
    / U1 n; a: o9 {8 n

  90. - P% H- L+ Y7 W
  91.                 if(NumToWrite==secremain)break;//写入结束了% ^- W' N5 I! p+ a8 s( c8 y

  92. ; q2 A8 ?: O: k- D  t8 l
  93.                 else//写入未结束
    - L  q6 K: [0 ^& u8 W

  94. + j/ L8 ~# u$ l8 x" R) b7 C$ y2 l
  95.                 {
    3 f7 ~8 N- i9 d1 z) j4 _7 }

  96. # ~; `. l  H8 `
  97.                                 secpos++;                                //扇区地址增1
    3 |% @2 w" d0 w9 w

  98. 2 L, R. e+ k6 f0 D, i8 F
  99.                                 secoff=0;                                //偏移位置为0          / J9 p; g0 G$ S" {# Q. f
  100. ( u3 m9 _, O3 g/ S4 E2 @$ F
  101.                                   pBuffer+=secremain;          //指针偏移
    . F5 W- j, C7 T1 X+ ]& l$ N9 u
  102. ( |  Y: V. G% ~# d- [  g$ b- X
  103.                                 WriteAddr+=(secremain*2);        //写地址偏移           
      J& C" L6 ~; v: o% m; _

  104. ) P/ R; y& f( b) s3 j
  105.                                  NumToWrite-=secremain;        //字节(16位)数递减
    2 P: n6 w/ ^! z( k1 _
  106. , X8 k" S& t5 a% k- {
  107.                                 if(NumToWrite>(STM_SECTOR_SIZE/2))" f; D7 B; R* ?( C! D

  108. ! B7 P7 a0 i' H
  109.                                 {7 \+ @; O. o, r) G7 [8 h) p

  110. 4 `7 ?6 z8 Q3 M7 y; g
  111.                                   secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
    2 Z8 x% P" ?# k6 _; y/ ]' O2 Y5 O/ A

  112. , }* |( J& d& m! R
  113.                                 }8 [- z  E6 v9 q$ Z# k$ h
  114. 1 K4 `, K1 |1 L8 A
  115.                                 else 2 d& y$ ~" A/ }) w6 ~0 L

  116. " ~7 S. x( G0 h) {( u5 V
  117.                                 { 5 ~/ u# {9 S2 F, _) d& _

  118. 4 |! x! w" m9 E1 u3 [
  119.                                   secremain=NumToWrite;//下一个扇区可以写完了
    " y: n8 o9 e  T- x: i! r

  120. 9 n: _0 V" U3 K
  121.                                 }
    9 j' r5 ?  ~  n7 H9 V5 T5 P

  122. 2 `* m2 ]0 l9 Y2 u7 }
  123.                 }         ! R, y4 e8 o2 {# X0 ?" p

  124. + |( K2 E( K/ e4 E8 N2 Q9 H
  125.         }        4 Y) V/ s  Q* f8 O

  126. ; ?7 j; j5 H5 a3 j
  127.         FLASH_Lock();//上锁5 \. F5 G: B3 B5 `7 C- R. Q& i

  128. # G- Y% V9 u( d
  129. }% M& U7 p( I) {1 K+ q
复制代码
  L  E. v2 R# K: `


5 ^& W/ @0 U9 w) h& F4 w最终我们调用STMFLASH_Write()函数进行数据的写入,是不是有没看懂的小伙伴,我给大家解释一下写入的过程吧
% i1 a; R( }) i4 c, e& m- _4 y; _* P! B) W7 b/ `/ j8 U0 p
这个STMFLASH_Write()函数,是说给定一个写入的地址、数据和写入的个数,然后按照给定的地址开始写数据,注意红色字体。1 a' y3 H9 }' ?$ }0 b7 G
写数据是怎么做的呢
7 {( M2 d4 A5 ^' M/ c9 F首先是整理一下写入的页地址和需要写入多少页,每一页写入的话起始地址是什么3 P* ^: z. z# l& m$ n
然后开始一页一页的写,当遇到跨页写入的时候,把第二页的地址写进去,写的个数继续写入就行- i: T2 t# t5 ^" g, y' n/ S0 N+ Y' H
如果还有不明白的可以在下面留言,我给大家解答( y' S1 E  p# E: y  c
还有一个地方很重要,就是我修改了库函数

7 m) Y7 N1 ], f( f; _& o9 E+ o


    0 h" A: E& B+ o
    1. /**
      % A. }! u% y  {9 W' |9 ^
    2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Programs a half word at a specified address.8 w9 _0 i" F5 b, N
    3.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]   This function can be used for all STM32F10x devices.6 b3 ^* a  V6 K
    4.   * @param  Address: specifies the address to be programmed.$ p& b' g7 _* X# y* Y
    5.   * @param  Data: specifies the data to be programmed.
      . x: v* Z/ ^5 Q( [1 G# L
    6.   * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,, ~: `4 q& f( X$ d- `
    7.   *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. , M4 M2 b" W5 L: q
    8.   */  j, C) N/ Q- [' W) ^- \" ^

    9. ; W4 D3 Q# N8 l8 {: [
    10. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)1 f7 `0 J' O# Y' D3 e% X

    11. % s: W' X1 D( A  m9 g, b
    12. {6 g% b8 u* T. J- h- o/ D3 B
    13. + |) H: I4 h9 J0 `9 m7 H2 M$ J
    14.         FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
      ' k) q& b8 O, i, w( G+ P
    15. 4 z+ j  b9 Q% h! E
    16.   FLASH_Status status = FLASH_COMPLETE;  p( v5 k- q  Q" k' w1 K
    17. 9 ]  C$ M5 u3 C2 G+ I% H
    18.   /* Check the parameters */- M' S! g& u! p4 g/ s

    19. 2 V) M' s2 |6 x
    20.   assert_param(IS_FLASH_ADDRESS(Address));3 @- n' o; D5 V% x5 H/ @. R( D
    21. 4 d- T0 F- c; R' a9 V, j8 i: J
    22. $ f$ \5 {# S# r0 M- ~

    23. # o/ n, F; q' n# A
    24. #ifdef STM32F10X_XL7 K- P- S& n, x9 Q* X4 `

    25.   M& r/ z1 }& ]/ n
    26.   /* Wait for last operation to be completed */
      5 {# K5 c9 V) W! l  T

    27. $ m. d* M( C6 z# _2 J
    28.   status = FLASH_WaitForLastOperation(ProgramTimeout);& @) }9 j; K2 Y9 q

    29. ! a( J# _; X& l

    30. 2 r1 r0 w. Q3 b# o6 v* U* I

    31. % @9 B4 r* Y  N; S" }& q' E% t
    32.   if(Address < FLASH_BANK1_END_ADDRESS). m' X# x! U! z. A3 v

    33. 2 ]2 s! x# \+ `6 g
    34.   {
        z* L* k. {  G/ O3 ?& D

    35. 7 J5 S, V1 u# d. K7 q
    36.     if(status == FLASH_COMPLETE)7 g$ _6 |; s( Y+ }

    37. + x; f7 `+ }& m# U+ c. Q
    38.     {
      ' B% O! H' A, `7 q( K

    39. ) B7 |5 K$ H' {
    40.       /* if the previous operation is completed, proceed to program the new data */
      7 [+ `0 ]2 N6 _, A$ }" [' W% n

    41. & ~' q6 [) C# f6 @
    42.       FLASH->CR |= CR_PG_Set;) ?+ L" c2 m% v0 ^4 ?

    43. 6 j% q" j8 ?6 R. h2 Z! r
    44. 1 u" {5 s5 Y( T  Z# `9 F

    45. 9 |4 `& Z5 _5 S
    46.       *(__IO uint16_t*)Address = Data;
      2 n. b! H/ T9 b# T, B0 W
    47. 2 ?4 b" G& j$ J: Y% W% H
    48.       /* Wait for last operation to be completed */
      + G  i. K' F0 w( l
    49. % J1 ^$ ^7 {  j+ q: ]7 i
    50.       status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
      ( E$ _6 F- M$ w, \* s, F3 O% {3 N

    51. ' d' l# |8 |6 m1 [) P

    52. + F4 w! i# X- Y( o: F

    53. ; B1 i0 _# [% h0 _! t2 h4 m! ?
    54.       /* Disable the PG Bit *// S& i, P( \5 |/ X' j; M7 s8 w

    55. 6 \3 v( _( F6 T
    56.       FLASH->CR &= CR_PG_Reset;
      6 M7 ^% D/ t* i5 O) L2 s3 \
    57. + g5 ^" L- v+ J9 {# p5 D: @
    58.     }
      ) c* |0 H1 H- z  _7 T! |7 _
    59. ' A2 P4 g4 O7 B3 Z0 V* _
    60.   }8 _3 V1 _% }# X; A+ ~. o

    61. 5 m- s) r5 s7 R: n/ T6 _0 z
    62.   else! x9 ?: `8 `( m+ n
    63. , [' l9 a" ~3 y7 ^! _  p
    64.   {: P% l4 g2 ~$ V; v0 H
    65. 7 _1 B% \1 d. b, F' V
    66.     if(status == FLASH_COMPLETE)$ w0 Q. H3 W1 T  o7 s! k- X$ c

    67. / K* Z' ]! G7 _& b8 K# |! z! z
    68.     {
      # i. ~, n5 x3 E4 V; C  u) T6 d

    69. 1 X+ P. h7 q& y0 B
    70.       /* if the previous operation is completed, proceed to program the new data */
      5 \0 C2 a7 b; h; ?4 A& `

    71. - f! x: z7 E& ^+ H8 J: G4 }4 A; [
    72.       FLASH->CR2 |= CR_PG_Set;0 V/ {$ x' a  b! f; ?& J

    73. 6 v( N' R( e$ O3 w' K  p' h1 y2 w
    74. 1 k/ ~' V9 c% u6 f# y9 Y6 A# \0 h

    75. 5 E/ H" H! {* m& ^+ o
    76.       *(__IO uint16_t*)Address = Data;$ [8 _7 f# S9 S% J/ b3 V; y* \  w: {

    77. 7 G7 |  P" v! s- r- U
    78.       /* Wait for last operation to be completed *// {# H. J" P' P$ u: `8 e. Q1 O
    79. $ _3 y/ s- {% c: r
    80.       status = FLASH_WaitForLastBank2Operation(ProgramTimeout);  W1 O: h* D4 ^4 ^& d5 p
    81. 0 V0 ^5 M+ K1 S* s* o' A

    82. ) q( ?" x5 g( V! J' \
    83. 3 k; _% Y8 v) i2 o9 f2 W) N
    84.       /* Disable the PG Bit */
      ; S9 L/ o3 A, }2 B

    85.   r2 S8 y3 O. T
    86.       FLASH->CR2 &= CR_PG_Reset;4 g2 l' H9 Z9 L$ i/ O4 U

    87. 3 P$ f4 Q& d& Z+ m
    88.     }. l# W6 G  s% X6 @* T
    89. 1 {- \6 m6 w8 ]* U5 z2 B+ t
    90.   }& l2 Z7 t( w& Q: ^& d: F
    91. " }0 P- b0 _/ D2 S! F2 S
    92. #else* L" P: {2 `: d3 Y+ O* U- E
    93. * P5 M- A; Q, v
    94.   /* Wait for last operation to be completed */- N9 {4 F, ?, J8 k% z
    95. : S# y$ {$ m5 T/ b4 V
    96.   status = FLASH_WaitForLastOperation(ProgramTimeout);
      ; T& q. d7 L# H7 {
    97.   V( b2 e. |5 }. m* ~

    98. 3 H* }5 U$ M. ?) }$ P

    99. % a/ [7 [7 t( F/ g
    100.   if(status == FLASH_COMPLETE)3 L3 f5 i7 Z9 T' S* E4 a
    101. / m% y4 P1 s* A
    102.   {
      , `: H" d0 m$ g. {- W4 ^

    103. 6 c7 q" L, K: b) o. x$ ^
    104.     /* if the previous operation is completed, proceed to program the new data */
      ! X, F2 ~$ _& @

    105. 8 q8 c/ p7 o+ b* z; P" c% q. ^
    106.     FLASH->CR |= CR_PG_Set;9 o8 T6 @! q* |: m, {: ^- u

    107. 2 s+ F' ]& O: E
    108. + k7 B9 m7 J( K6 Q

    109. + G3 V- g# R0 N7 z" i
    110.     *(__IO uint16_t*)Address = Data;
        B0 D. M1 C& ^4 r; v
    111. " ^1 e  q( i$ m" A/ i8 @* I* E& n6 Y
    112.     /* Wait for last operation to be completed */
      + l: A1 }) ^! i: ^% z

    113. + C, @: M5 V( U% f, S
    114.     status = FLASH_WaitForLastOperation(ProgramTimeout);' W! M! |7 x. B* o# `/ ^

    115. ( \$ P7 q$ S7 n  N6 w7 x

    116. 0 ?' A2 _% q2 W$ A

    117.   s; ?& r4 g9 G
    118.     /* Disable the PG Bit */; z. Y" \& ~3 V2 c9 }# ]3 \

    119. 5 l9 S: |2 y. O7 E
    120.     FLASH->CR &= CR_PG_Reset;
      9 Y3 w  U' P5 r4 g$ y

    121.   T) i( S, |% }% g" v# f
    122.   }
      # Q/ D" p( {; N/ A$ a; A5 L2 V
    123. " T9 \! V! ^" f2 a; _& k. y" t1 V9 r
    124. #endif  /* STM32F10X_XL */
      / l' C7 a. S! c, o$ o1 y
    125. # P9 U/ @" w7 P% B  l) N$ Q

    126.   a& f7 R9 X  `% y: k
    127. , {- Z1 E5 d9 k! }+ B/ A
    128.   /* Return the Program Status */
      + q0 P" c4 y1 h5 |9 b
    129. $ c( t+ u& q' T: F
    130.   return status;
      ' z) T7 Y# o7 ~7 q* z

    131. 3 U' U) a, z0 i, q; s' l$ P
    132. }
    复制代码

+ t& @4 t) t* W+ E4 j

  ?5 o4 T, C2 V  H$ P) u& w2 d( F
大家能看出来吗?就是红色字体部分,增加了一个每次写入前清除所有异常状态。
" Q, x! w1 L1 H; y5 Z! d为什么添加这个呢?
5 C6 C3 V, r. N6 }% b3 U因为,如果你写入的数据的地址没有擦除,你就写入的话会导致异常状态的发生,而这个异常状态时要手动清除的,如果你没有清除这个异常状态,而继续写入数据的话,那么你后面写入任何数据都会报错,均写不进去,所以我在这里增加了一个异常状态清除,如果前面写入的数据报错了,不会影响我接下来的数据写入。
' y9 o5 Y# C8 V这里大家就清除为什么了吧。. O8 f8 o8 [  `$ c5 I
写数据会了,那么再说一下读数据,其实这里读数据要比外部flash读取容易的多,我们直接读取地址,返回的就是地址存放的数据,是不是很简单
( P5 i; z- u. ~' v, `9 B, W看下面的函数


4 z  W" X# ~/ N. X/ e' G
  1. , G0 Z2 j1 p( d3 W" X5 n
  2. //读取指定地址的半字(16位数据)
    + S5 W- |7 r4 u; z# H# D0 s, ?1 X
  3. - M. O, q7 W( b; b1 y1 D- y
  4. //faddr:读地址(此地址必须为2的倍数!!): a6 O" `% q$ y/ O! E/ z

  5. / n4 s8 t* h; d( m+ Q9 l- O
  6. //返回值:对应数据.
    - R& T1 A) p/ H& w

  7. 9 _) _/ u0 z4 _6 J
  8. u16 STMFLASH_ReadHalfWord(u32 faddr)
    ! m6 |' d% y5 B
  9. % V/ n& c/ T. Z( ~  y# M( m# k2 g1 g
  10. {" \. D" ?+ _& T! m. n2 e# p& G
  11. ) _5 ~4 r; X) m
  12.         return *(vu16*)faddr;
    + y2 ~* N" P  I9 M8 E; |! ~
  13. % C" V1 @% @; \0 s' P
  14. }
    : _% w2 O( X5 M' z

  15. ' D  }- _; G8 u3 i3 b" f6 V

  16. + N; v7 q0 c: D; u! p% o

  17. ' a% m6 }% r2 b, d0 ?7 f$ r  ?
  18. //从指定地址开始读出指定长度的数据, l( U+ O1 F7 D' {

  19. , a! `4 S/ o0 _2 y. j2 I
  20. //ReadAddr:起始地址
    : L& o0 t0 Y* D+ I

  21. . h8 P6 ?0 T# p% ]5 i8 W
  22. //pBuffer:数据指针5 J9 Z7 ?7 h8 D

  23. 0 m% ?" n% P8 I" r: X
  24. //NumToWrite:半字(16位)数
      v( I7 Q8 N8 a) i. @2 Y7 A

  25. 5 W! Q! i" G  K2 A& |- C

  26. * l4 F, ]9 @6 V+ G" e

  27.   H, @! K6 H! k. v0 ^" ?
  28. void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)           ) _! K0 W+ I$ x$ n1 ]' B& B
  29. . c  V8 t8 P9 t  h1 S
  30. {. e' f. q; r/ Q* E% r
  31. / P/ i2 o5 B- O- ]. P, B8 A9 a1 ]
  32.         u16 i;. p: [7 O8 k/ f- i' N( j
  33.   r3 }/ U, v# y( D
  34.         for(i=0;i<NumToRead;i++)4 q4 r- [' E& `' B( z' `
  35. ( m: ^0 t" Y/ S, y' m
  36.         {
      p. R2 C9 F1 p  a7 u2 B
  37. 2 z* m% ^; P! s1 s0 r. I
  38.                 pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.8 A  G& \) T/ }

  39. ' {% A5 M" A& f: l- M
  40.                 ReadAddr+=2;//偏移2个字节.        
    ( _& d8 k4 s* ^2 Y

  41. " Q( i* k3 o1 A; z4 ^' d: [) i
  42.         }9 U" s6 z# S( R+ G8 c4 ^

  43. 9 ?3 O$ |2 @( N. C6 i0 C, w+ T
  44. }
    * H3 z9 Z; H; m( C
复制代码


0 w7 A$ a/ V. ~* Z6 o- [3 R+ X有没有很开心,读写数据就是这么简单就完成了。
* {+ {1 _% T' \- ~( @3 O  c+ }& A
# _: [& @7 i/ G7 E" D! b---------------------
: f+ {* i( D) @1 m2 w作者:binoo7

$ |  S3 p1 ]+ n7 e0 v# v9 @" @0 b
赞 收藏 评论0 发布时间:2022-12-9 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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