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

【经验分享】STM32F1系列HAL库读写内部FLASH

[复制链接]
STMCU小助手 发布时间:2022-4-11 10:16
测试环境:" ]- @6 a3 x8 u8 d
STM32F103RB
2 f' r* A, I/ s9 Y* z9 L20KBytes RAM
/ R; U8 g/ ?! d( f128KBytes FLASH
9 c) {7 D3 w+ X. u( D注:本章节代码只适合STM32F1系列!) u7 G& ^) E* Q- |9 O' @* L" N) n9 C- Q! q

, d  t/ y( q; b( J! N 20201024152250174.png
+ \! A; ]- I9 ~0 H2 L: V6 A4 s6 G3 @7 N5 |3 o- o
头文件
. m8 w& z/ v  g7 _5 a6 V+ R/ g8 w+ E  }- n$ {# E* v( W/ ~
  1. /*** ^0 B8 ?; ~: r. O
  2. * @brief Create by AnKun on 2019/10/10$ L4 k6 b' {/ [9 `: X3 X* e
  3. *// ]6 F8 H9 c+ G. y

  4. " F% f. z9 u: [% E# I8 Y' T0 K$ o  V% N
  5. #ifndef __FLASH_H
    6 k9 z% T; w+ O2 g+ ^& D6 U2 x
  6. #define __FLASH_H
    5 p7 e) w2 m  N/ J. [. B

  7. ; l/ R1 T' Z8 C) n! E
  8. #include "main.h"" \+ Q1 K5 n+ V& G, R

  9. 8 G9 X( C# \# H7 p3 ^, ^0 A
  10. 移植修改区 ///- I( {) K# R  B) h* G
  11. 8 t: c$ \2 X. |$ |" }
  12. /* FLASH大小:128K */
    * X) ]' H$ o3 P1 Y1 T, F
  13. #define STM32FLASH_SIZE  0x00020000UL- h( E/ g1 y9 o, G, d0 p! J

  14. 9 n+ E3 Y9 W4 o8 ^) ^
  15. /* FLASH起始地址 */. C- o+ I) @7 g9 b* a6 U
  16. #define STM32FLASH_BASE  FLASH_BASE5 b! X& {7 T2 G) i

  17. ) V! ~1 w$ p0 _" j! Z
  18. /* FLASH结束地址 */
    & q! e, g/ y/ V. r, i9 }; g' ^+ `4 m
  19. #define STM32FLASH_END   (STM32FLASH_BASE | STM32FLASH_SIZE)
    7 \: k0 A) b! I* Z. m$ n( {1 f+ f
  20. 6 o3 @4 B# k6 \7 m+ [( P
  21. /* FLASH页大小:1K */
    " Q+ s8 r/ x6 Y: W
  22. #define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE8 A5 s3 ?% p* Y- ?/ H& o& _

  23. 5 d# o) K" n8 o1 J* Z9 \, @9 E" o
  24. /* FLASH总页数 */- h  Y& W) P0 A6 Q* I7 _0 D
  25. #define STM32FLASH_PAGE_NUM  (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE). y/ H; i. m! J: }
  26. " v! n9 @% h5 `7 C
  27. /// 导出函数声明
    3 A7 q7 x- [1 ^( F, T/ i/ j! r2 J
  28. void FLASH_Init(void);
    8 t( t/ J, `. s0 ?7 u; t6 K5 `: r
  29. uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);6 A0 |* {/ ~% _2 v# G  H0 m% r4 F0 b. s
  30. uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);' \5 d! Q3 {! f9 f, _& S' G
  31. int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);! u3 k6 j* Y  }* d# H  T* b8 ~
  32. uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
    % p9 t- T) `  b9 O* r) R5 L! b: E' I8 V

  33. 9 i# n- S" ]7 K& k+ L& G
  34. #endif // !__FLASH_H
    ! r% U0 ?& t3 Z( j9 ]& d5 S  g
  35. , O: ]6 N- v" ?' A( x; U
  36. end of file
    % D) U. U+ V+ |, Y
复制代码

3 g2 x' i9 N& f4 Z) I; |+ M' u' d源文件
9 L( S  {7 X! W& c

$ `* D  N* d, [0 M* a% K; r) E
  1. /**
      _5 s& h3 F7 g6 z; O% w
  2. * @file  flash.c
    1 o6 Q% j! I! L* `; f- `3 k4 f
  3. *
    ' |  H- u; f& Q& z: X
  4. * @brief Create by AnKun on 2019/10/10& b, h3 c5 h; S9 j, g$ w/ N, s' F4 P
  5. *$ o' q7 E2 x9 G$ v
  6. */" m% i4 \1 `6 o) A) r

  7. ; E, E. n9 a8 V  U: t
  8. #include "flash.h"
    + f) z& c* J+ L4 d
  9. #include <string.h>/ l$ d/ U) s2 G1 e/ N

  10. , M) _9 S5 @  _' E
  11. static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
    1 ?8 J  y8 N/ K# {; Q

  12. ) A+ ?9 T, e6 H0 ^, A5 s
  13. /// 初始化FLASH
    1 U. ]& ~% r" _- ]9 E; E' ~0 H
  14. void FLASH_Init(void)
    2 }% a, r6 ^+ ]( a& n/ V
  15. {
    1 R; }: Y) m6 m& L! ~! n$ C
  16.     HAL_FLASH_Unlock();3 t0 {# Z9 j& P. E, W
  17.     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
    ' O, ~0 ]" I+ X: E
  18.     HAL_FLASH_Lock();  H# K* ^& a# H- _/ U
  19. }0 u- h  g" f, ^6 s* O
  20. 3 t0 i, |! z% U2 y0 b. _
  21. /**- x0 z/ E. e6 Z  G' a
  22. * 读FLASH9 R/ t4 M/ i/ K4 p& o
  23. * @param  Address 地址
    , n2 o4 m- T& f/ |. W1 F7 P
  24. * @param  Buffer  存放读取的数据
    % C* z2 x: t6 p: z0 k, }; _7 P  J
  25. * @param  Size    要读取的数据大小,单位字节5 R; F3 l7 T) W8 V. _) x+ p) y& j, M
  26. * @return         读出成功的字节数
    8 T* d8 |+ {( o+ K8 X
  27. */1 P  ~, w% f& A- D" `
  28. uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
    ' `- ?/ h2 @7 `9 Q+ w
  29. {
    4 B* v( Y5 U3 J8 G
  30.     uint32_t nread = Size;4 @% @8 S( n" v& A) Q
  31.     uint8_t* d = (uint8_t *)Buffer;/ L- t) S" d& p+ G' H& S
  32.     const uint8_t* s = (const uint8_t *)Address;
    * \/ ?; _% f9 g4 m

  33. 0 {# c- r& f7 T/ m
  34.     if (!Buffer || Address < STM32FLASH_BASE || Address >= STM32FLASH_END)0 Y  R9 Y/ d! d% V3 Z4 E% Z
  35.         return 0;
    4 I! w+ b3 W2 [. X

  36. : t, N- K* X2 ~8 N: _. b
  37.     while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (STM32FLASH_END - 4)))
      j# J! k% i/ U8 K4 K
  38.     {4 \- m1 `4 D- M! t5 z  O$ O
  39.         *(uint32_t *)d = *(uint32_t *)s;
    : J& h$ N; s/ R  T  K+ z5 H
  40.         d += sizeof(uint32_t);" e. h8 A5 x+ m. Y7 U  |
  41.         s += sizeof(uint32_t);+ {8 L6 X$ N4 L$ f+ m7 y3 J5 Y
  42.         nread -= sizeof(uint32_t);
    $ [7 B' A" l, r0 _2 p. l5 M
  43.     }- O" E9 N  [+ _
  44. ' T- d2 R5 u+ y7 F! F
  45.     while (nread && (((uint32_t)s) < STM32FLASH_END))
    4 i+ x/ O$ h" |; s$ {* X
  46.     {
    ; z+ y+ M3 `+ o9 Z& i8 z, m
  47.         *d++ = *s++;2 |4 H; `" p1 H
  48.         nread--;2 b" H7 t* W, Q, `  O0 N
  49.     }+ A, t. I6 j# ]0 h9 K

  50. $ V6 |- r1 q9 q7 G: e% ?* x8 X
  51.     return Size - nread;
    , s1 J& o. J, D, d# c
  52. }
    3 }! R' J$ ^6 z/ V4 n1 Y: Q

  53. & x0 b3 t3 z- _
  54. /**
    ( _( M) h& q$ I0 n4 \+ |4 Y
  55. * 写FLASH6 d, f0 |: [- J* E: q, [
  56. * @param  Address    写入起始地址,!!!要求2字节对齐!!!2 u3 F+ v1 N4 B9 l
  57. * @param  Buffer     待写入的数据,!!!要求2字节对齐!!!
    % b. X* ]( y+ P9 ?
  58. * @param  NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!
    ! c( b* N; H( f9 i' O7 x: d$ j( j4 T& l
  59. * @return            实际写入的数据量,单位:字节
    * Q; N0 x  _7 F# }
  60. */
    ; L7 Q( s! _# |4 r; h) s% [
  61. uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
    1 W8 e" t% ^: g' u# V% [
  62. {  `* I3 D0 J& v9 W+ I" X% s
  63.     uint32_t i = 0;
    ( e+ [+ e2 H% D
  64.     uint32_t pagepos = 0;         // 页位置- V, l; F* W2 i! L) h& j1 F! t$ \
  65.     uint32_t pageoff = 0;         // 页内偏移地址- j, m) w  B# j7 ^
  66.     uint32_t pagefre = 0;         // 页内空余空间
    / R3 ^: N  P& x5 H8 {
  67.     uint32_t offset = 0;          // Address在FLASH中的偏移
    6 X9 T, T6 T" }7 v% t1 Z
  68.     uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量$ b' a0 J. A" U. k
  69.     const uint16_t *pBuffer = (const uint16_t *)Buffer;% p% A% _2 k: E- ^

  70. , W0 }" h- [5 j! X" ^
  71.     /* 非法地址 */  @9 h8 }1 D2 v
  72.     if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)# h7 [; I  C5 M, G2 n0 A( y6 [, J: Q
  73.         return 0;
    4 V7 c5 m$ n& a# q3 W/ b
  74. * c* e. ~$ u# Y4 ^/ n3 }7 t; B/ A% ~
  75.     /* 解锁FLASH */
    - [( Z! l- Y1 f8 ]
  76.     HAL_FLASH_Unlock();1 b5 u- s$ j, _9 W' J$ p5 E

  77. 3 j; T' d# w% r: O6 X
  78.     /* 计算偏移地址 */' H0 y6 F" P. ^* t' Y1 |, N# Y
  79.     offset = Address - STM32FLASH_BASE;
    2 {9 U. h# V' Y- J3 @: \: i. ]
  80. 4 @" K/ S( H, e: Y: F8 V
  81.     /* 计算当前页位置 */
    ; o& t1 o$ |1 I4 D
  82.     pagepos = offset / STM32FLASH_PAGE_SIZE;
    ( K7 {) y! [( w7 p" z: o$ W- j
  83. / c8 C3 X" r7 }0 W/ U9 L
  84.     /* 计算要写数据的起始地址在当前页内的偏移地址 */$ D: ]( E1 a8 z3 ]% |
  85.     pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);
    3 D$ O' q4 T7 c  P

  86. 5 E! c# \$ ?% c7 d% r
  87.     /* 计算当前页内空余空间 */
    & n, M3 V$ f0 F- X4 K1 f* y
  88.     pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);1 W$ v5 ]$ `* G& N7 `$ ?9 `& ~& u/ l

  89. - A9 K7 u2 P9 N6 Q( t7 x2 \0 K: x
  90.     /* 要写入的数据量低于当前页空余量 */
    1 k' k6 z6 D1 m. y6 E. V8 J
  91.     if (nwrite <= pagefre)
    7 _+ b; J8 e0 Q+ ?8 p; f
  92.         pagefre = nwrite;) ~1 i- S+ x. A4 V# y. ]8 r

  93. ) v$ ?/ X" {9 f. [9 h- P! H
  94.     while (nwrite != 0)6 D4 U4 `* G1 n& V/ Z
  95.     {
    0 t4 V, }  b" q$ H- K/ o
  96.         /* 检查是否超页 */+ G5 m3 Q# M( W9 z3 U
  97.         if (pagepos >= STM32FLASH_PAGE_NUM)  @9 `, C6 Q0 w/ V/ o
  98.             break;8 I; c) c4 f- S0 w0 q- ?

  99. ) o9 y* v% c5 |7 @, Z" f
  100.         /* 读取一页 */
    / h) T. h- P  k2 s$ u; y) l0 k
  101.         FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE);1 _3 n+ X3 ?* {

  102. . k0 p2 F( H- G9 U3 C. P( L' k
  103.         /* 检查是否需要擦除 */
    ) j5 m$ `3 m& a$ `4 w8 D+ z% ]. o
  104.         for (i = 0; i < pagefre; i++)
    + J* [* u- \3 J' S  v4 ]& C- R
  105.         {
    5 }0 E0 Q* I5 \$ V; c
  106.             if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */+ L6 J- Z) Z, X! F8 i5 P
  107.                 break;
    4 M' f3 Z3 \5 q4 E' ?: K, _
  108.         }
    + f, P# X* Z  x! F4 L  b+ l) Q
  109. 9 q9 B% O+ J1 U) c3 v; i; J
  110.         if (i < pagefre)
    % C0 s7 T3 n( h# v/ U
  111.         {
    ' p/ d5 a) P+ I0 O
  112.             uint32_t count = 0;0 }% @: }. E6 S0 H3 w6 }( ~- k/ m
  113.             uint32_t index = 0;
    . p/ a7 c; R. ~
  114.             uint32_t PageError = 0;
    + |: r) T/ e* m/ q6 B) O. c4 w
  115.             FLASH_EraseInitTypeDef pEraseInit;5 V/ E/ T/ }  L( P! c6 U! C) s2 m" X

  116. ' a! B" F3 A+ O0 r/ d% Y$ w
  117.             /* 擦除一页 */+ j% e/ k1 Q/ C& a/ s
  118.             pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;% ?- v9 d$ E: @0 ~
  119.             pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
    ' f9 V: [3 e; l* Z7 X
  120.             pEraseInit.Banks = FLASH_BANK_1;
    * L! S9 _, Q8 Z  e
  121.             pEraseInit.NbPages = 1;
    1 X* C, c. d. m- ~0 h
  122.             if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
    ! {& F! `: K4 j0 E
  123.                 break;
    ! N/ F! r- s$ E5 G
  124. & Y" o3 `- \0 N
  125.             /* 复制到缓存 */
    ! w* U$ C8 E8 a& A7 J0 m
  126.             for (index = 0; index < pagefre; index++)' [# A9 m1 ~2 b& I7 I' F' p) _
  127.             {3 k& _  o+ ^& b& G8 A
  128.                 *(FlashBuffer + pageoff + index) = *(pBuffer + index);, |& t. c  ]) X% ?
  129.             }9 l4 o2 P/ y! I# y

  130. 5 J* s. n8 [+ R9 {2 i* `
  131.             /* 写回FLASH */
    9 @! }* F: D/ M
  132.             count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
    2 y* O6 I5 k2 ]0 `! O
  133.             if (count != (STM32FLASH_PAGE_SIZE >> 1))- N/ H, a9 J4 o4 t
  134.             {" u* J0 _! v% a* |4 |
  135.                 nwrite -= count;! O: T7 V( x6 G5 ]/ `! e5 D5 r
  136.                 break;1 F/ N, o1 D& D( _7 }8 w+ N
  137.             }
    6 `/ ]0 Q6 @$ n
  138.         }
    4 o+ |. s# _, O5 [
  139.         else5 B* ?, V( e  e5 ]( I" d) y
  140.         {' K! @& V# ?$ o2 E- w6 p
  141.             /* 无需擦除,直接写 */
    % s5 e7 K, \! l( A
  142.             uint32_t count = FLASH_WriteNotCheck(Address, pBuffer, pagefre);
    * ?9 {8 S8 i1 \7 B. _
  143.             if (count != pagefre)' m5 b/ K% S. }1 B! V- d1 P# L! |1 U
  144.             {" p/ p4 z4 U0 l1 m, y
  145.                 nwrite -= count;
    ! m1 G* r# q) V8 G" v4 R7 x% k
  146.                 break;0 O$ a0 D# \' [4 @( a9 x
  147.             }
    1 T: W# M9 D! Y2 K2 h* Z" q4 w
  148.         }8 `' q3 {( s- n2 {7 Y$ ]* u

  149. - y* F; Q' ~7 N. E
  150.         pBuffer += pagefre;         /* 读取地址递增         */
    / _6 B6 x' _: n1 I/ B" U
  151.         Address += (pagefre << 1);  /* 写入地址递增         */
    ! H1 D3 k& X3 c0 D
  152.         nwrite -= pagefre;          /* 更新剩余未写入数据量 */" A. o8 I( v5 |# t
  153. 7 [, }7 ^5 o. |3 C' ?
  154.         pagepos++;     /* 下一页           */
      D9 ?% M$ V* _" e& p' E
  155.         pageoff = 0;   /* 页内偏移地址置零  */2 Q3 j: z5 x5 `' h
  156. " ?& Q* l( }) L. h: |) P% A" U
  157.         /* 根据剩余量计算下次写入数据量 */
    * W4 J6 q5 i# L& |3 r. f6 @6 |
  158.         pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;6 p9 Y) W& R# [, _3 @
  159.     }
    $ N2 {- o& Z( x& v4 p& J

  160. ( S$ @$ `5 H  I0 e; r
  161.     /* 加锁FLASH */
    4 E7 W# f1 T, ~/ ]6 P0 K5 V; h' ~
  162.     HAL_FLASH_Lock();9 c1 {6 M5 V( E" B) b2 E

  163. ' h1 ]- v' {; U1 Q
  164.     return ((NumToWrite - nwrite) << 1);  a7 M' E* X" b
  165. }
    & W1 {1 i8 I/ a) s, n4 e2 T# W
  166. " A9 g) E+ n/ R
  167. uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
    5 F5 v2 l2 r& I+ _0 S  L
  168. {
    # r1 q' ^6 k/ T7 m) ]7 x
  169.     uint32_t nwrite = NumToWrite;
    . t% b0 ^% r7 \% ^
  170.     uint32_t addrmax = STM32FLASH_END - 2;
    ; K! M% X: ]! j% d
  171. * {- e- e6 n0 w2 j
  172.     while (nwrite)9 d$ z, V. C2 v3 T1 n
  173.     {
    * c7 a3 Z- W8 f% h6 Q. l1 {$ b
  174.         if (Address > addrmax)
    $ `& D( U& }+ ^3 s( b; X
  175.             break;
    " J7 s: n- B9 o; q) t  A+ N7 ?6 _' g
  176. " b1 c  X# N! V$ l& E/ D6 b7 T
  177.         HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);4 J6 G- o" q6 M: Z2 ~9 @
  178.         if ((*(__IO uint16_t*) Address) != *Buffer)
    6 \' v% F+ E. R. ?, ?" U# u
  179.             break;
      {3 W2 l1 j- I& m9 c3 ]

  180. 7 E& s! Q/ s& _( i2 d8 K3 K
  181.         nwrite--;+ a! B  f& V/ C! O$ K
  182.         Buffer++;+ d- ]& r- N5 k% A. E
  183.         Address += 2;
    # m1 `3 Y9 ^& Z! ~
  184.     }
      A0 _0 ^$ y7 ?2 b2 t( M
  185.     return (NumToWrite - nwrite);
    * |$ |/ d8 h/ Z2 }9 h
  186. }
    : E; [2 D0 @0 S* S
  187. ! a9 b6 n" P' f5 ?2 ~7 `+ _
  188. int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)) I0 F: T" l# W! s! s/ i
  189. {  B5 ^8 x# o/ Z. }7 A7 {
  190.         uint32_t PageError = 0;
    ; I) l# u4 v1 t# j* U# e6 n, m
  191.         FLASH_EraseInitTypeDef pEraseInit;; o* j- x+ Y+ l9 K
  192.         pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;$ O. L; M- |7 t' d
  193.         pEraseInit.PageAddress = PageAddress;
    : ^6 [. `0 Y) \' ^6 c6 [
  194.         pEraseInit.Banks = FLASH_BANK_1;
    4 p# K, e4 p' o  h$ x8 ~% J3 H
  195.         pEraseInit.NbPages = 1;
    + B8 B( ?( g& w6 |; Q) Q
  196.         if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK): z, J$ Y! ^, t5 s* B7 v, p9 T
  197.         {
    9 _! c+ _& [. f
  198.                 return -1;1 I9 y8 J1 N- R
  199.         }7 @' J/ t' K/ I: K9 B
  200.         return 0;
    $ i' t$ v0 F- J- k; D
  201. }  \0 i+ p! H2 [4 F0 X) P

  202. ! Z6 L! z  |: I5 B; @9 r) k  N2 y
  203. end of file
复制代码
5 `" {2 P% L+ s! ]5 @
- @$ X! X8 i( s/ O+ \" `" y

2 _6 Z  L9 T; V! C" F7 ?
; f& p7 J6 ^5 \$ t8 K2 D
' w6 t: w9 l" B6 u
2 h5 h+ I4 P& R% E% H" @
6 K7 @' |5 p- o% ]# e: u6 g: X$ `
赞 收藏 评论0 发布时间:2022-4-11 10:16

举报

0个回答

所属标签

相似技术帖

官网相关资源

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