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

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

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

一、芯片FLASH容量分类:

; S& Z( h7 Z( Q. |  G3 O: |
可以看到我们今天介绍的这款芯片的flash大小是64K的,网上也有人说它可以支持到128K,但是官方给出的解释是前64K是有保证的,后面的无法保证,所以想要使用的小伙伴需要慎重。% N+ k# s' F! g4 X
现在芯片的flash大小我们知道了,下面就可以看看这个flash是怎么划分的了,通过芯片数据手册,我们能看到今天说的STM32F103C8T6是属于中等容量的设备。

既然是中等容量的设备了,那我们就来看看flash划分吧,在STM32的闪存编程手册中有这样一段话:按照不同容量,
$ Z! [( [" [2 r) @* W$ H$ b4 h存储器组织成:5 B* w8 B& z6 \4 ]! d. w/ ^/ w& i
32个1K字节/页(小容量)0 G6 x, i' r8 T! U8 [. L
128个1K字节/页(中容量)2 |' F  |5 |5 j; q8 S
256个2K字节/页(大容量)' j/ }6 g" V  Z. f
这段话怎么理解呢,就是告诉我们小容量的设备(内存是6K和32K)的设备是由1K字节每页组成的,
0 }9 ~1 N2 {$ I! O' K6 L) ]1 N中容量的设备(内存是64K和128K)的设备是由1K字节每页组成的,
' Y3 L5 e/ v9 n0 a/ t大容量的设备(内存是256K、384K和512K)的设备是由2K字节每页组成的,5 t6 F% l. Z/ P* Y2 W5 E0 M' L
举个例子吧:0 |; P0 n/ M% t0 h! I6 ~/ q" [  M
一个芯片的存储容量是64K,这64K是什么呢,就是64*1024个BYTE,一个BYTE是由8位0或1组成的,(比如0000 1111 这8个二进制数组成了一个字节,用十进制来说就是15)
, L+ d, a+ e1 K# w5 d小结一下:64K的flash可以存储64*1024个字节的数据。
6 i( T7 `# ~2 {8 c, \4 w咱们继续说,这64K的数据怎么划分,存储是按照页为单位进行存储的,一页1K的容量,也就说一页可以存储1024个字节
0 ?: {8 Y% Q+ M$ n6 [0 Q* l一共是多少页?% }* m% G7 X$ N" h6 r: T! o6 Q$ B
答案是:64页,我们看一下官方是不是这么说的

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

+ J- v7 e' F! _4 c8 Q; S
二、 读写步骤:
& l9 h' |2 }* Q! T9 ^上面我们知道了芯片是怎么分类的,下面我们就重点来讲解一下芯片是怎么读写的。) k# {8 f& Q: s7 ^
内部flash我们参照HAL库或者标准库,直接调用ST公司给我们封装好的库进行编程就可以了,这里我用的是标准库,有兴趣的小伙伴可以去看看HAL库
9 f. _3 b  @+ R, w9 U% s是不是有小伙伴会疑问什么是标准库,什么是HAL库?
% L3 L3 D3 e. o. d. A在这里给大家解释一下,这两个库都是ST公司,直接把寄存器封装成函数,供大家直接调用某一个函数,就可以完成各种寄存器的配置,不容大家直面芯片的寄存器,方便阅读和使用,因为每个函数的名称功能都是不一样的,在调用前可以参考函数的注释,在F0和F4的标准库里甚至有每个函数的用法,不知道为什么在F1的库里把使用步骤去掉了。5 W% ^3 @3 t! @% b6 g
咱们继续,读写的话库函数分为:

  1. /*------------ Functions used for all STM32F10x devices -----*/& c3 H  [, m5 v) B- P
  2. # J6 ^0 _: d4 u! c
  3. void FLASH_SetLatency(uint32_t FLASH_Latency);, E  {3 W9 z* w2 ~& F& `

  4. 2 T( y0 W3 h  ?* C1 x
  5. void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);
    + B& f3 b4 _( z0 W. z% f
  6. - p! x: H. H7 Y/ t" }3 E
  7. void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);
    ; R, D/ i! H+ p3 z( h& S" a
  8.   D/ ?& t2 Q* q2 b; e9 w* @$ m/ ^
  9. void FLASH_Unlock(void);9 t/ M9 J7 E  z- l6 M3 F8 n3 Y; ~

  10. 0 ^1 ^' Q  h# u3 e
  11. void FLASH_Lock(void);) M9 A9 V, H- \( h, ~: u
  12. 9 d9 M' j3 f/ q1 e  J
  13. FLASH_Status FLASH_ErasePage(uint32_t Page_Address);" E' W9 n' I* }- o7 k/ R( w

  14. ; A0 i3 W$ k3 E" t1 `0 R- y7 f
  15. FLASH_Status FLASH_EraseAllPages(void);. o! s: l+ G6 b* b! A

  16. 9 Z+ k( o. Q) p) f5 {1 V
  17. FLASH_Status FLASH_EraseOptionBytes(void);
    8 h3 X# w6 m; x9 I

  18. . ?9 v4 K/ ]3 K  w$ A1 [% M
  19. FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);
    ' [5 S/ l! q6 V8 p  n
  20.   O; g6 Z9 i8 D, s' Y+ G$ S
  21. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
    & L8 x4 U) e6 ~9 S

  22. $ x( Z0 y, Q6 z
  23. FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);& s, b7 c# Z$ h" b0 e7 e1 v
  24. $ d' @/ p$ B# W4 u- Y" R9 E8 O
  25. FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);
    - a. Y/ X, Y' T2 V) f, `' x8 `9 ]) H: v
  26. $ C% {) m  ^" n( \
  27. FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);- p$ B* N: ~  ^) R

  28. 2 v+ c( u/ c) ?- x2 u$ e6 b+ H! Q, B, V
  29. FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);
    1 t+ V. b; \6 k7 n' ~

  30. * Z' u' ]9 i# g6 E3 F" u- }
  31. uint32_t FLASH_GetUserOptionByte(void);1 V( m; g" }1 B8 n
  32. 1 q; C3 X3 I* E& o+ J, p% d' N) P
  33. uint32_t FLASH_GetWriteProtectionOptionByte(void);/ m2 U" ~, L  x9 C

  34. 9 a1 y* u, ?$ p1 o# P
  35. FlagStatus FLASH_GetReadOutProtectionStatus(void);+ A' a! m1 s* h

  36. $ l' K9 \0 T& T' W" a% w
  37. FlagStatus FLASH_GetPrefetchBufferStatus(void);
    ' v: K$ `1 I" Z  ?# c. @, I" S

  38. , M- a; r( L! }3 [4 F2 i! p1 w
  39. void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);
    9 L2 B: v6 a0 q. C' e

  40. , [4 Z8 a1 b5 D
  41. FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);
    9 X) b' Z9 g  B
  42. , D$ \4 j: N% i) y& C% a6 W
  43. void FLASH_ClearFlag(uint32_t FLASH_FLAG);
    ( P3 W' [- O( |& O9 @6 Z0 O0 S

  44. 8 K9 I( }' V+ Y' y/ H3 p8 \
  45. FLASH_Status FLASH_GetStatus(void);
    8 B5 x4 }' V/ u( b6 W6 J7 o
  46. : _+ h0 D2 f$ L8 t# \
  47. FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
    - c0 F$ j* z5 M
  48. $ I" E2 b4 ?" R) V$ Y

  49. # h2 b0 I1 \5 R& t

  50. / `, H1 ]! z3 I  B$ b2 ?6 j4 }
  51. /*------------ New function used for all STM32F10x devices -----*/
    / t. o- {6 I. ?5 O: e

  52. ) X' o$ t2 Q6 h/ L8 [
  53. void FLASH_UnlockBank1(void);
      p' z9 F1 W+ v  x

  54. 9 F) M* E$ c1 R6 j
  55. void FLASH_LockBank1(void);
    , @5 |1 [4 P7 C4 S5 u: @
  56. - i7 s! \4 m6 h& Z
  57. FLASH_Status FLASH_EraseAllBank1Pages(void);: Z' t& g$ X( ~6 a

  58. 3 m# i9 A7 G# {( a& Q# h
  59. FLASH_Status FLASH_GetBank1Status(void);4 R5 b2 Q6 f8 e9 X  ]' g
  60. - V; z$ f, ?6 y7 d- Z# g0 o
  61. FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout);
复制代码
6 q9 H8 v& [/ R; G( i! R; j9 G% ]
2 J% H1 }, }4 O/ a. S. J( r* W) C. L

在这里就不一个一个的详细说了,我们说一下常用的就行
3 g0 R5 Z; C7 G1 K1. 解锁

void FLASH_Unlock(void);$ P$ C" U* q7 c- T0 {2 S

  H6 P/ m, E7 G, S0 y& V; d0 s
2. 上锁

void FLASH_Lock(void);3 t6 D4 ~5 Y3 j3 Q5 A) I$ \


# E  Y0 c5 g  }& U. @% H3. 页擦除

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


$ ~- u3 p6 o$ K+ c8 o0 j! S好了,其实是一样的。
4 v* X" c) u" Y7 u+ H下面我就和大家来分享一下(百分之九十九参考的正点原子的例程)

  1. //不检查的写入$ @+ O$ }! X# ]0 s# r

  2. 8 n6 Z6 [, I9 c6 [
  3. //WriteAddr:起始地址
    , C6 J! F8 F) t/ H+ r  E( T
  4. 5 U' d% P: U3 T( L# C
  5. //pBuffer:数据指针2 F: T( p5 P& C: C/ F0 W

  6. : ^' ^: G! w, p2 E4 ?. M3 T
  7. //NumToWrite:半字(16位)数   
    2 F: |, [! R% f
  8. 9 [' a5 u0 e/ F# u; O
  9. void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   7 T/ \8 W* j: P+ E
  10. $ @8 L1 U. d$ n$ _9 E
  11. {                                           5 W, i. a% y* z1 v1 s9 q3 }$ r
  12. 4 j1 P0 D. ?4 i9 L+ f0 O- s: Y
  13.         u16 i;
    , m- ]  \% y- x0 c0 J
  14. / C9 h  |6 H$ Q( R
  15.         for(i=0;i<NumToWrite;i++)
    9 o7 z4 R8 ?) j

  16. 5 ]- u1 |4 D2 d, Z  {* x
  17.         {/ C9 b/ D& p3 N; i: i( ]1 A
  18. * V6 D& U  y( w( s5 q9 w! v' T2 X: `4 \: O
  19.                 FLASH_ProgramHalfWord(WriteAddr,pBuffer);
    8 m/ A  X  N! r5 W

  20. 3 E* k# o& q9 D7 W' J
  21.             WriteAddr+=2;//地址增加2.
    ) J, D4 [8 m" A; K

  22. + f& d$ z; M% I5 U8 U. |
  23.         }  
    / p3 @+ d' B4 h
  24. ' U2 ~( @7 ~$ M0 }
  25. }
复制代码
  1. //从指定地址开始写入指定长度的数据
    + ~5 j  `2 b2 j

  2. ' W. V. v& j! Z. [; y2 S! v
  3. //WriteAddr:起始地址(此地址必须为2的倍数!!)* `1 _! p) X0 K* \. a
  4. ! y$ N& A. p: U! N1 W/ }  q  I% |
  5. //pBuffer:数据指针' q2 |- u3 J+ g# h

  6. - p: J. k; S. U4 ]' A1 `$ d* q
  7. //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)( c6 }" m& e6 \

  8. # E" G5 K+ n; d7 a) O

  9. : F% ^7 `% g: f
  10. ! x& M# J+ y3 h1 Z
  11. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
    ' v$ W2 A  i5 `0 G* L0 b% F$ Q: m
  12. ' D5 |. v* o5 H% ~% S) Q+ i
  13. void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)        4 d$ ]  c) y- l* W  Q
  14. 8 I( I! s- I8 n, y4 W0 `3 B4 ]: Q
  15. {
    % k/ a2 [4 V7 J) T; G) Z+ p5 ]# F

  16.   Z0 F- x# I. o4 o3 }& ?- P
  17.         u32 secpos;           //扇区地址
    , W! L5 H8 G( H2 _* B

  18. ) n$ ?, S, c8 I' }& S( S
  19.         u16 secoff;           //扇区内偏移地址(16位字计算)
    8 _, x8 L: q  ?* K; Y
  20.   I+ h: @  N/ w6 y2 L0 a! C: T
  21.         u16 secremain; //扇区内剩余地址(16位字计算)           + o$ y; `1 j  T4 z
  22. * _" ~* S; k1 L: d5 ^& a6 o
  23.          u16 i;    ; n$ }2 F+ K; z" Q

  24. , ~9 H, A% L- R* R
  25.         u32 offaddr;   //去掉0X08000000后的地址
    $ F/ T+ w4 a6 Y+ y% X( W

  26. 0 t" g. A# b' X$ H% |# x7 Y6 y
  27.         if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
    1 r; m8 u( x8 f' _" d4 d4 _
  28.   C* H! J( p# P8 J, G
  29.         FLASH_Unlock();                                                //解锁
    5 L- K: m5 O, ?8 v: H  m8 y
  30. " a$ r& V( \! L' _/ l
  31.         offaddr=WriteAddr-STM32_FLASH_BASE;                //实际偏移地址.
    1 l) L' [* t4 {% D  U' x. r
  32. ; L# s5 d7 _/ j  \
  33.         secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6
    : ^. C" o- g9 Y: {+ c  Q
  34. % k4 t( l- C& `  k  X
  35.         secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单位.)5 ?' Y, l# T$ z1 N+ [7 w0 g- N$ E/ T- y

  36. ! |$ \/ Y3 g1 i$ A: v1 L
  37.         secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小   
    ) M' z6 C, S: {# A, c3 i; O

  38. 2 o, \0 S2 r9 r6 c# u9 A9 S9 h3 |/ V, S
  39.         if(NumToWrite<=secremain)
    5 e6 o# _: C: y! Z( a& X

  40. 7 r" O; s  D4 R% M0 G
  41.         {$ L" O. ?3 w2 h8 x% Z
  42. : W( j4 }1 L9 V: o
  43.           secremain=NumToWrite;//不大于该扇区范围9 n8 I  R" u" |' C

  44. 0 w. ^- N$ ?0 T" `9 X) H
  45.         }4 R, r$ L5 g) c) u- r/ U

  46. , V1 b( z) f$ v8 Z
  47.         while(1)
    7 e' e) d5 S5 m- N9 D  F6 Y9 Z
  48. ; [5 D4 ^( g9 f$ P* E2 k3 F
  49.         {        
    : J' b, M7 s5 ~5 W" y, m8 q

  50. . x( j) I9 d. \0 ^' o1 N
  51.                 STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容1 K9 x# U% Q: J1 t% t3 U/ r) }" D
  52. ( C* g! c* m9 r% O1 j; `
  53.                 for(i=0;i<secremain;i++)//校验数据
    . _' A$ f. `! t6 ~  k, l

  54. ; ?0 S* O* T) W, ~2 [- Y
  55. //                for(i=0;i<(STM_SECTOR_SIZE/2);i++)//校验数据
      c: e5 e/ w# S$ ~/ l( q/ J: E& s
  56. & M3 _+ h$ w. X: `; L7 i4 N- c/ _
  57.                 {
    + v+ c2 \6 }/ H, {' a0 Z1 Y) r4 F
  58. : E9 y5 G: V% ^
  59.                         if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  
    # ], K! y3 b3 Z. G
  60. $ {2 |0 P4 g' o; `: p4 L/ P$ Y
  61. //        if(STMFLASH_BUF!=0XFFFF)break;//需要擦除                        
    6 F: s' m0 i% f+ e$ A( e( @- V

  62. ) ?- Y; Z, G# M! m- e
  63.                 }& {$ p/ B( d6 W% J" a- s2 i5 X
  64. ; U2 _% B! i# V) D2 B" ]8 b& z) Y
  65.                 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);* t5 l: ^/ Y# s6 _! i
  66. 5 s! M+ E4 ?% n: E0 M' ^4 s) e
  67.                 if(i<secremain)//需要擦除
    / ~, N8 c3 h$ d3 s8 j

  68. $ U2 X7 X- k5 [
  69. //                if(i<(STM_SECTOR_SIZE/2))//需要擦除& u  _6 A9 T  T2 F. Y3 B9 s
  70. . ]# ?  C$ V1 J5 d, u
  71.                 {
    ( q/ i% q( m0 t5 v$ Y+ @
  72. , z5 W0 f- I  E; o
  73.                         FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    0 h1 W. x4 h7 s: m

  74. ) Q0 C$ B6 P; d' c; U6 u1 I

  75. 3 `" D) x' W$ [: j' o7 ^

  76. , {; U: ?; X, a* T( }8 v
  77.                         FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
    " Z9 R( b2 i5 o& r8 N- f  T  m

  78. & @9 _! P  n5 ~) S) D* f
  79.                         for(i=0;i<secremain;i++)//复制% W' _3 Y  @* Q

  80. $ R5 x6 s0 x  I3 `; K
  81.                         {
    " D6 {3 [0 N7 [9 G7 t8 S! l

  82. / M1 ]! B0 y: e# a. U  _
  83.                                 STMFLASH_BUF[i+secoff]=pBuffer;         
    7 a/ @: `0 @# L; Q: o6 Y1 g
  84. $ L5 x& M6 L. c- B+ K4 U
  85.                         }$ v7 E( T1 q! L

  86. 3 K- x, _7 R$ F8 f
  87.                         STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  8 w/ Y; m; {1 p, e. I6 h% w. _
  88. ( R1 i3 q& r& C. J6 k# v% f3 I
  89.                 }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                    % j; \: X1 x/ C/ K9 O2 m
  90.   R& c2 I, x' ?- ^3 v; _; [
  91.                 if(NumToWrite==secremain)break;//写入结束了
    1 e+ f' k* k8 r, G( a" e

  92. 9 D" D( ~+ v2 Q& _. _# y/ q
  93.                 else//写入未结束: U: V1 M  _/ f7 u! P9 g

  94. ) L" u9 l( e. D( B, U% L
  95.                 {
    1 o0 A$ `( L+ g5 c, q

  96. ; W# U; G# T* q
  97.                                 secpos++;                                //扇区地址增1
    & P  l/ D2 [* b+ K

  98. 8 y, ~" ~( j( ~0 N/ |
  99.                                 secoff=0;                                //偏移位置为0         
    8 ]" k; R2 w* J

  100. 0 r, U# \, m, R5 ?5 X
  101.                                   pBuffer+=secremain;          //指针偏移' |& G, {3 m! S  D& L; z
  102. & L3 U) \$ O/ n. m, b. T
  103.                                 WriteAddr+=(secremain*2);        //写地址偏移           # ^( c: P0 O. n6 U' c
  104. . O' J& f' ?+ l9 |
  105.                                  NumToWrite-=secremain;        //字节(16位)数递减
    $ L1 j5 S; j, `: R- ^5 w
  106. 6 P2 J6 ]5 D8 O% c9 p0 d( n  M
  107.                                 if(NumToWrite>(STM_SECTOR_SIZE/2))
    ! I$ e2 q; N. b# J

  108. 9 `) n9 m; C' d) r
  109.                                 {' J2 B3 R- ]8 A, t- g% W6 f
  110. ; z: t" O; r% w- U
  111.                                   secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完- ]: u6 z' r1 [+ o/ ^& `5 @2 u  ^; i
  112. 7 H( e, A1 K8 _- |1 r; e' \
  113.                                 }
    . o  Q) l$ W2 z5 t/ n9 t
  114. # j* t, _( A0 Z8 X% k( a0 M, o
  115.                                 else
      a( k" F1 @/ A$ x5 Z

  116. 3 q$ G$ h+ V! d3 [8 {* ]' k
  117.                                 {
    $ _2 C* v/ J3 V
  118. , `" o1 z; [8 u8 W+ W+ \5 l$ d
  119.                                   secremain=NumToWrite;//下一个扇区可以写完了, y( j" u7 }9 b# Z/ o

  120. , X! p7 Z9 g  z3 t) `! N
  121.                                 }
    * K2 i: F4 z! _. M/ |- @  ]

  122. 9 _' \) R% t5 K# d$ B
  123.                 }         . M; [5 t$ J$ N- F1 |
  124. 8 ?3 Q- c- F# c- N* Z
  125.         }        
    - C" j* m5 t1 g; @6 P1 z. I

  126. 4 Z7 Y" ^, l/ G
  127.         FLASH_Lock();//上锁
    , D2 R' A' e: D9 @; l# G! T
  128. 5 l( C: _- _& G; {/ l# j
  129. }
    " s( a3 d+ R1 N0 G: G: y
复制代码

$ n6 j4 F3 `. m1 C* {+ k


$ L6 x& Y+ f, R1 T& `3 ]  u最终我们调用STMFLASH_Write()函数进行数据的写入,是不是有没看懂的小伙伴,我给大家解释一下写入的过程吧
2 s3 K9 b4 c3 v( h7 j! B4 D5 {/ G) p: g1 R9 `
这个STMFLASH_Write()函数,是说给定一个写入的地址、数据和写入的个数,然后按照给定的地址开始写数据,注意红色字体。; M% U0 }1 e+ a" |
写数据是怎么做的呢; U) k, c' j/ `2 @
首先是整理一下写入的页地址和需要写入多少页,每一页写入的话起始地址是什么! T  j2 O* c! R! {
然后开始一页一页的写,当遇到跨页写入的时候,把第二页的地址写进去,写的个数继续写入就行
# `( |+ w2 l1 a+ k! L% @如果还有不明白的可以在下面留言,我给大家解答
& q' i' ~& H: i  V  C还有一个地方很重要,就是我修改了库函数

# K9 h) Y% M+ U5 h2 b+ ?


    8 M; d8 w& X3 ^: W" z6 S
    1. /**
      1 k; H4 [4 Q' e5 x' a
    2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Programs a half word at a specified address.
      + b. v* ?8 W% @) I* K6 A
    3.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]   This function can be used for all STM32F10x devices.8 ?) b1 j5 n" F+ Q. Z2 n! a9 ^
    4.   * @param  Address: specifies the address to be programmed.! s7 R) s! c1 J2 i+ K
    5.   * @param  Data: specifies the data to be programmed.0 V4 d/ Y( H: o2 j" `) ?
    6.   * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
      % m; k6 h1 s5 r4 o
    7.   *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
      * C7 t/ J$ s4 k3 u, E
    8.   */
      7 v$ k; j' _- [4 E  q% Q

    9. 8 f8 p. [# M5 _1 p* d
    10. FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
      # B# t# G* e" W8 s
    11. 2 v7 N+ C# Z* H
    12. {' b/ {+ J9 a0 V0 v  {
    13. % E3 X) v9 `1 _) O
    14.         FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
      / t% x9 ~) N9 o+ o
    15. " s4 s$ A4 ?) N' C! M
    16.   FLASH_Status status = FLASH_COMPLETE;
      # C2 b8 `& ]1 F1 K8 U
    17. 4 v2 ?. @) c( h8 p! J8 V/ I5 }) B
    18.   /* Check the parameters */4 R3 D4 ~( a! a$ U: ~+ [8 [

    19. " A0 f: ]0 T5 ]3 W/ f. v
    20.   assert_param(IS_FLASH_ADDRESS(Address));" r+ ^& ~2 ]! ]

    21.   b4 |1 Y9 k" W+ g" o( F

    22. - r% ~5 {1 n% f- |$ `* t
    23. % ]1 P. b0 @: c3 @
    24. #ifdef STM32F10X_XL' p# I) x, G- m. s6 J: o# _) a

    25. ) Q4 p# W7 A7 P/ {; e5 B. y
    26.   /* Wait for last operation to be completed */
      8 ^0 x9 U; N7 \) Z. t' _; e  G
    27. 7 g9 a1 @: _- u" Z1 x) p
    28.   status = FLASH_WaitForLastOperation(ProgramTimeout);  L& C& |4 B5 z: m, |' Z
    29. - b% D) l9 Y; U4 B4 r/ z

    30. + w$ |9 f1 Z$ H: X  Q; ?% j: P( N
    31. 8 l% x# f1 K) p6 `( N1 h
    32.   if(Address < FLASH_BANK1_END_ADDRESS)
      $ [) @7 Z- c- r: Z5 t

    33. , ]3 C; q% j9 {/ K! e
    34.   {+ H2 K& K+ U8 K1 y

    35. * ]/ i& U/ u; V3 P; C2 P* f
    36.     if(status == FLASH_COMPLETE)4 O: Z" c- y5 P, E
    37. $ @: W/ W) O* d5 `# J5 K
    38.     {
      & Y9 A2 @" L: h$ J
    39. ! L: X' s$ Y2 A7 o; i
    40.       /* if the previous operation is completed, proceed to program the new data */
      . f9 t8 [) S4 `1 S, t

    41. 9 ?) P! Y5 D# D: H% G, ~
    42.       FLASH->CR |= CR_PG_Set;) A# z1 ]1 @; b+ \

    43. , p- I# A- }: G8 J4 h  ~: K

    44. ' V: q4 M( o* a: p1 x& J
    45. ; c( A$ S9 ]* R! O- m: Z4 \
    46.       *(__IO uint16_t*)Address = Data;5 M6 Z5 P0 C: ?9 M

    47. # ?7 E! S, M% }: @$ V" F
    48.       /* Wait for last operation to be completed */+ ~: ?6 {3 b3 q1 U$ B, Y; Y

    49.   ~+ F. \' H6 Y! }8 _. w# \( q, r
    50.       status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
      / a- W4 W# o: g

    51. ! N! z9 h/ q. I! v% C6 \

    52. , l! q, Z% k* S& Z# B

    53. . T1 Z8 V3 H+ q, {  J5 ?& ?6 k) _
    54.       /* Disable the PG Bit */7 f& R' \0 A8 e* Y: d
    55. ( s- [/ S3 ~& T
    56.       FLASH->CR &= CR_PG_Reset;
      & u0 a7 i8 O' f8 \' x% R
    57. ; X" ?) |6 _6 `* j1 u$ {$ {
    58.     }
      / I; m6 x! X* e' P& V8 H3 p- R

    59. $ t# Z2 E* _2 ~; H+ Z
    60.   }
      2 v. a$ S+ X9 X, ~' c

    61. 7 ^1 K2 \) \! I7 S* r
    62.   else
      " H0 L/ K- O& X$ q$ V0 p% G
    63. % E; p7 o2 [7 ~6 F
    64.   {8 `# j! j. I: _: C- K* N+ t1 i

    65. 8 z1 R4 |) }* v0 F- m$ v$ a- H
    66.     if(status == FLASH_COMPLETE)
      $ g: x) a# }' w% U3 P8 w( W- C
    67. + r) [4 H* e" q$ m! `0 Z' Y& a
    68.     {$ p  N7 W) s6 x3 H: t/ |* `
    69. 4 S9 H6 |6 {) }/ K- j
    70.       /* if the previous operation is completed, proceed to program the new data */
        O1 \1 x  Z& l
    71. ) T/ l% f8 `* K4 @. |8 c1 w4 l
    72.       FLASH->CR2 |= CR_PG_Set;
        T7 q3 y; I1 j7 D6 v' ?0 S

    73. * h0 _# w- i' u6 z$ g
    74. + I3 ?) q2 \2 E
    75. , ~+ d( M2 q- @: n
    76.       *(__IO uint16_t*)Address = Data;
      $ c3 H/ I' ]5 c- Q+ e( m

    77. 0 P+ i- ~: X1 {5 ]& V2 a3 I
    78.       /* Wait for last operation to be completed */
      : }4 O+ O" |2 w" W7 L0 P

    79. - m) a5 E* X" K% o. M
    80.       status = FLASH_WaitForLastBank2Operation(ProgramTimeout);! i! @0 W, i  p
    81. ) a$ z+ R* _) W6 M, J! b

    82. 3 r: r, d2 D. U) Q/ N

    83. 2 J1 [3 P0 E# |. j: K: A5 |# W
    84.       /* Disable the PG Bit */' S9 T  ~3 S: Z! @9 G2 O

    85. ' w: s' K1 D0 j3 z: h0 m* `# }( W
    86.       FLASH->CR2 &= CR_PG_Reset;9 \* }  n3 B9 i  S, w( v/ R% w
    87. * E  R7 i/ A, `0 `6 n. n) [
    88.     }
      # _' S. \, _4 H7 ]
    89.   s, Q0 E$ y- r9 z! T  F8 k
    90.   }7 v+ I7 {3 B5 g, T
    91. ' J0 ?5 N3 O# p
    92. #else
      ; d* b; h8 @4 h! L
    93. 4 Y5 Y# U2 u+ J- P) }% g" {
    94.   /* Wait for last operation to be completed */9 n* m5 M& X. m. _1 C

    95. 2 C6 Y0 G' J9 E- N
    96.   status = FLASH_WaitForLastOperation(ProgramTimeout);$ i! K9 I' F& }1 n$ @+ z7 e9 Y
    97. / [& f- d- B( D
    98. - G5 b4 q& e8 n9 g$ j
    99. & l& l* u; \) q" C7 r. ?
    100.   if(status == FLASH_COMPLETE)/ h+ x' f  k) t, y) F+ J/ G

    101.   {  X  ?. n% a  s7 o% [9 N6 X
    102.   {/ n1 @; E6 B5 q* f4 d; g( F0 N

    103. & K& M4 Q' S7 ^, l7 r
    104.     /* if the previous operation is completed, proceed to program the new data */
      2 s4 G" M0 r  F) H1 j+ E

    105. ) y* J5 q8 F6 r
    106.     FLASH->CR |= CR_PG_Set;0 e" c1 c! m8 h! M' W2 s* X

    107. 3 h3 L6 s! H8 y  V4 l- @! ?" b
    108. 6 G3 j* b) [; N& x8 s; w

    109. 9 b& q7 e( F6 m7 T
    110.     *(__IO uint16_t*)Address = Data;1 }1 U% s/ v! s+ I7 @. l/ N- Q. m
    111. 7 n" ^. ~2 D5 t2 h* `) y2 p
    112.     /* Wait for last operation to be completed */
      . i$ w2 J( J' d0 |  R2 M
    113. 2 Z% o+ K1 |, K0 x
    114.     status = FLASH_WaitForLastOperation(ProgramTimeout);
      4 b  G9 J7 X5 V

    115. * q% z' {5 }. Y  @4 J7 P' [2 z* ?

    116. # G1 d# G3 G; L1 h
    117. 9 T, }3 }* A7 ^6 j; \
    118.     /* Disable the PG Bit */. i" |' ~8 U0 E& j4 ]
    119. ' U; W2 P$ k  ?1 t( K1 H' x0 O
    120.     FLASH->CR &= CR_PG_Reset;
      2 a+ `8 O& x, b7 m

    121. : o$ O; j) `7 b' v' x  T  _
    122.   }
      $ d- ~8 Y+ `& Q1 W$ |9 e! [

    123. 1 S8 v5 t7 U0 C
    124. #endif  /* STM32F10X_XL */
      1 B: |! f5 b6 X& w8 t# w0 M; y
    125. # D8 O. {( f7 }) m( w# o$ |
    126. ) O3 B/ Q- A. `. r
    127. 2 V, F& A  {- `- M0 E
    128.   /* Return the Program Status */* H5 x" V; `: x' U
    129. : }: ?* J' ~6 {, S
    130.   return status;$ I8 x; U4 l& i7 {4 M6 V% ^

    131. " c- a# N5 x4 e& U4 f3 {% A
    132. }
    复制代码

: G( b7 p, q! ~$ \$ n& M  M% r


' e3 o4 T, q- o! o, F大家能看出来吗?就是红色字体部分,增加了一个每次写入前清除所有异常状态。
; d1 O1 ?, e5 Y& Q; k为什么添加这个呢?5 n# G9 x  O' \4 Z
因为,如果你写入的数据的地址没有擦除,你就写入的话会导致异常状态的发生,而这个异常状态时要手动清除的,如果你没有清除这个异常状态,而继续写入数据的话,那么你后面写入任何数据都会报错,均写不进去,所以我在这里增加了一个异常状态清除,如果前面写入的数据报错了,不会影响我接下来的数据写入。1 a) d2 u# p1 d# G, |4 T
这里大家就清除为什么了吧。
; j4 @0 w: T* p$ d1 J) M写数据会了,那么再说一下读数据,其实这里读数据要比外部flash读取容易的多,我们直接读取地址,返回的就是地址存放的数据,是不是很简单# R: c  g& D. V5 n& C5 N/ N0 d0 e
看下面的函数

6 T4 T3 d, m7 s# h0 R7 e3 W, ~0 P

  1. ' [0 W% ]9 M$ U8 r
  2. //读取指定地址的半字(16位数据)$ M" L0 L) K9 D6 i( i
  3. : ~# p. ^9 y: L" e" ~
  4. //faddr:读地址(此地址必须为2的倍数!!): y2 I9 M- E; ^, f
  5. % v# z* n9 j9 p( p5 ?! V. X  l
  6. //返回值:对应数据.
    8 [4 X# U+ e" q  C- n7 K6 b1 _
  7. " F6 D" r1 C5 Q6 E
  8. u16 STMFLASH_ReadHalfWord(u32 faddr): W5 k0 {- e! s
  9. $ W; R2 q2 ^" S* c& k/ _8 T
  10. {
    2 |, i. c* q& [
  11. , p# y6 Q# V, Y2 U8 F. k
  12.         return *(vu16*)faddr;
    & V; |0 v& _* E

  13. 7 L' B$ ?$ D* g, r/ a
  14. }; X) M: `/ b8 }" A& |  P% Q; E
  15. " F+ j0 P7 @* u: [
  16. : B4 H1 `4 ]! S1 Z* W! g. e3 B' _: b
  17. , |" a9 H% j, [" L2 T! w0 g
  18. //从指定地址开始读出指定长度的数据
    : M% [6 W8 A: H' k# W8 W
  19. - f% I6 G$ U2 Q
  20. //ReadAddr:起始地址" P: J/ m# S/ C: w

  21. : |, M4 T& n$ t, E
  22. //pBuffer:数据指针
    ( @1 _3 m, H  l* T- Z$ \7 z" Q% ~
  23. . y( h% `3 i+ g. o
  24. //NumToWrite:半字(16位)数2 A' u5 @$ G1 z' ^

  25. ! t! X3 t# g' L+ \

  26. ) c1 P: s2 ~: g- c+ N8 B

  27. ! g# t* s0 x6 @9 e
  28. void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)           
    . N3 z7 w! n0 A: c8 f
  29. . o: l3 V' ?5 @; T
  30. {3 l9 O/ _1 ^+ ?; _) f# r
  31. 8 T3 j# c$ G- A; B
  32.         u16 i;
    2 f6 h2 j, N9 q9 R- d

  33. . f. z4 d! O  b
  34.         for(i=0;i<NumToRead;i++)
      G5 F. z  X2 d1 ]4 d

  35. ' g1 O( }4 o8 S2 [! u1 N- K% g+ P7 b
  36.         {
    , r6 h. E$ p  f& X

  37. 8 V0 N8 z4 J; g$ m' G
  38.                 pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
    ! c1 N2 d& p3 ^- n' X
  39. / v3 @, g; ^% z2 b5 x
  40.                 ReadAddr+=2;//偏移2个字节.        1 z# b! c0 T6 |

  41. 9 _" d2 F( |; }) S
  42.         }  d! L: J6 p# w/ x. W" u7 v

  43. : Q3 [! j2 i  p/ x
  44. }+ S- O8 d6 i1 S" A  p$ b+ {
复制代码

* N, @% i' F2 Y% R
有没有很开心,读写数据就是这么简单就完成了。
7 O, L0 }, Q4 Z9 Q
& f9 q. ]6 ]% L8 x---------------------6 f5 H6 [( H& w8 z4 A
作者:binoo7


& j  `" N& ~* X$ t  O" p, M2 C
收藏 评论0 发布时间:2022-12-9 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版