测试环境:- V: r, S$ n6 L9 ~2 A3 A
STM32F103RB
- w8 y3 `) i1 I- X" |20KBytes RAM
4 j( l' I6 Z6 ]9 E6 H9 @8 Y8 s128KBytes FLASH7 Y# }5 X, [2 i9 _9 F0 d0 j
注:本章节代码只适合STM32F1系列!
% I; V" x4 N( [, H
6 w6 G- [2 z3 S
. O6 i' G n) |4 ] K8 J7 H/ G- k, n/ M
头文件$ B; G M+ _# ]8 s+ w& x2 L, f ~
1 d$ V9 w5 X# A5 \, ?- /**0 S8 r4 |: i% N5 f- O- V
- * @brief Create by AnKun on 2019/10/10
+ I3 }7 i2 _; B% m1 d* n - */9 ?# T! o' F5 s6 O$ F- Y' n: X
6 L( K( {/ N( K3 @. o- #ifndef __FLASH_H
- V3 g) R7 o" D4 t) f# o - #define __FLASH_H
1 \# n2 y3 c# J7 ~( t - 9 d) O& u" q2 ~& a
- #include "main.h"& i s) z6 b, x
- " R& m0 [/ \" v
- 移植修改区 ///8 f! V$ a* g2 ]0 w: s
* f7 o( y# n) n1 {0 K8 e# y+ k+ T- /* FLASH大小:128K */
: _$ Z1 r) h1 x+ d - #define STM32FLASH_SIZE 0x00020000UL! N. r6 j9 N( c+ H4 ?6 p- C; ^5 r
) ^6 d" {& F- Y- /* FLASH起始地址 */5 p7 z4 l8 ~0 q8 v' z9 M
- #define STM32FLASH_BASE FLASH_BASE3 ? ?% ]/ w( V, u
- 1 ?! b) [8 d! D. d
- /* FLASH结束地址 */. [* g' |+ a! ~# v( V
- #define STM32FLASH_END (STM32FLASH_BASE | STM32FLASH_SIZE)
; N, x* W m! N, P6 w5 Z! z7 {! s/ M; Z - % C" s6 d3 E# a
- /* FLASH页大小:1K */
& x7 } s) x1 V( @4 V% f6 ~: F( e - #define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE0 d* n6 ~, m! `$ r! |% i
) c" y1 Z/ F! _ I0 W- /* FLASH总页数 */
I& W* S1 X! n7 y, P2 d/ Q - #define STM32FLASH_PAGE_NUM (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE)
( C3 G/ ~) U& Z! M
" k# x$ v4 B4 ] z8 x% r' j% A- /// 导出函数声明
9 Y' E* K+ p) i/ a, t8 t - void FLASH_Init(void);
, O8 q! p+ Y# b* P+ q6 A+ s - uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);; q! a% m" J/ A) L- p: e
- uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
6 U& t3 B% z4 H' g3 \ - int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);
9 b6 I; H. ^" ^0 i5 U# ?8 A - uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
* R' T! C' l0 x J0 Z# F - 2 ]) ?$ L5 _8 ]
- #endif // !__FLASH_H
& J% C& T) b" X0 q$ q* @) [
$ ]+ B3 Q- J; w& Y. ?- end of file : J# Y2 d. ~& B% ?+ e
复制代码
) M7 U4 Q1 o/ Q* _0 n# n源文件9 g6 d# W$ t1 j; e2 v$ I7 N: D: {
8 I- W0 @) p0 ]/ M6 I- /**" R- _* \1 c( P6 t) a
- * @file flash.c
4 X" l; |" x0 _3 n - *- s& j1 p1 b8 u5 s, i
- * @brief Create by AnKun on 2019/10/10% F& B( H. {' |: z( _
- *, h' j7 B" B8 q; Q- V" f
- */7 e: O7 Z& ?( {/ }
- ; V0 m9 |% E+ O& b* p
- #include "flash.h"/ f$ f& ?) J: V/ J) c) v$ z
- #include <string.h> l! y% {- X2 y/ }3 v; d* ^
- / i- P9 X+ Q* ~- l" O3 N
- static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
2 R6 F$ B8 d0 R) _ t8 W) s - 9 p( n- _ d3 _( ]
- /// 初始化FLASH3 k, P- L& `8 u* ?/ l
- void FLASH_Init(void)
0 H5 j( N( O; S9 S+ t% G" z! A; m - {% _! r% W! g9 Y% B5 l* X
- HAL_FLASH_Unlock();
% M0 _! [/ S1 u/ p3 v - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
4 M# p0 [5 u; J& ^" b% w1 K7 G8 r - HAL_FLASH_Lock();
+ G& R6 g2 y( r0 W2 s s - }
9 h4 `8 n4 w7 ^2 o' Q - 8 [ X- p, O% o
- /**3 N2 S3 v( {$ P/ g( e
- * 读FLASH# n/ u. `# L0 [7 H1 w
- * @param Address 地址' |- y/ ?+ T, U) e* x( _) D
- * @param Buffer 存放读取的数据3 k0 p! C1 y/ T' g/ I+ s
- * @param Size 要读取的数据大小,单位字节
6 o9 V, |' K. p6 w, J - * @return 读出成功的字节数4 x- D) P0 a, K2 Y; o
- */
/ c2 n% Q' k1 S# x$ k4 N: g; w7 t - uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
/ @$ f5 d' a0 E7 W) G1 B, ` - {7 u: E; n3 q0 O* R! V
- uint32_t nread = Size;. q/ A* D% I [
- uint8_t* d = (uint8_t *)Buffer;
7 k1 e3 n: R' k, Q1 X7 R& o - const uint8_t* s = (const uint8_t *)Address;
* `% ~# Q4 Q# M! L$ O5 P) w1 `
! v$ [7 X2 O* `$ _1 f- if (!Buffer || Address < STM32FLASH_BASE || Address >= STM32FLASH_END)- |$ t5 \, t) g. w1 X: D% J
- return 0;2 i" P. D z$ h9 d
! u6 s! B' @/ F0 U, B$ o- while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (STM32FLASH_END - 4))); S0 { x/ ^! t" J
- {
! {# p4 w; p" g- ]' l9 `) t - *(uint32_t *)d = *(uint32_t *)s;' \7 X. F- w" z; B1 W
- d += sizeof(uint32_t);- o# y3 M, m/ e- G1 ~
- s += sizeof(uint32_t);
7 u) P5 S/ n$ `+ K4 d8 ~ y: e - nread -= sizeof(uint32_t);
- f3 d! I2 x5 n( t- l( m - }- x6 r+ V* I9 B/ E2 Q8 e$ t: q b
1 S2 j% I/ C+ l3 S- while (nread && (((uint32_t)s) < STM32FLASH_END))
0 O1 ?( q" l- |/ _# r( Q4 E - {
1 \+ y; R; f$ B# _0 `% i$ M - *d++ = *s++;/ T. f) a V3 C
- nread--;
- Y! ?$ p+ s! P, E7 Z( h/ k) y' x$ [$ F - }- k* Y$ T! K A$ {. X/ e& `6 l" H7 I
- 7 u( c4 r) v8 S/ V# b
- return Size - nread;
2 j' P4 o% r T$ R4 V" i - }
3 a3 B( j, a7 o. U* M - 7 g8 ^* N+ y( D: ^
- /**
& F' }: P9 z, Y - * 写FLASH! o$ y$ S4 R% G3 X
- * @param Address 写入起始地址,!!!要求2字节对齐!!!+ ]% t- V0 ^- e q; p" t
- * @param Buffer 待写入的数据,!!!要求2字节对齐!!!
0 o0 J3 l. f! G" w* I - * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!
* L! x# {9 s% n, ^! s/ m - * @return 实际写入的数据量,单位:字节
i s0 z ]' q6 K7 |1 b - */
' F0 a/ q: V5 ~& d7 f A - uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)' ~- J7 W4 f" m: \& ]
- {
/ @3 K/ a+ ?. n6 S0 }5 I - uint32_t i = 0;) q0 O! M+ p- u: X8 C
- uint32_t pagepos = 0; // 页位置
4 }/ r. i/ e, m4 M1 s - uint32_t pageoff = 0; // 页内偏移地址
) K- P) |1 U6 j0 L - uint32_t pagefre = 0; // 页内空余空间
9 ~$ v1 E, O% X: L - uint32_t offset = 0; // Address在FLASH中的偏移6 z# j$ F1 l4 A1 B' H8 r6 G
- uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量
* \' c' r* F& ]5 @( P2 l - const uint16_t *pBuffer = (const uint16_t *)Buffer;. Y1 G/ _* q' I$ }
- % {# n3 g( L# D4 j/ ?
- /* 非法地址 */- u) `- v$ u3 O. C
- if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)
" N+ I1 U0 m% p' x9 b$ v( I6 j - return 0;& [( K" ~- g+ g# [+ R# [/ J+ }
- : _1 Q+ o) p9 c9 u% |
- /* 解锁FLASH */
, L& u( N* a% G- ~ - HAL_FLASH_Unlock();
. m; m9 w4 \$ t4 P2 W
. d6 I' ^( d" ?- /* 计算偏移地址 */: a8 v, H, i7 E) t, r* H
- offset = Address - STM32FLASH_BASE;
8 m, W1 A1 B; N/ n: O X
J {' w8 Z3 j/ {: R$ {) |' | U- /* 计算当前页位置 */9 |; }6 c: s) d5 H3 m
- pagepos = offset / STM32FLASH_PAGE_SIZE;/ ~4 ]( b& v2 R' h$ ]
- 2 H# @% N( [& t; i
- /* 计算要写数据的起始地址在当前页内的偏移地址 */
# b) m! Q; Z* f2 B* q' M - pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);; N/ U- A: _9 D1 ~- h) K! L0 N
- 8 r$ f; s9 {; _8 X: r
- /* 计算当前页内空余空间 */; O4 y+ J3 d" S: @3 E* w* q, _! i+ t) K
- pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);) @( Z8 u# g& a' _9 Y
1 T# F$ n F! G1 L& N- /* 要写入的数据量低于当前页空余量 */. n9 Y" g' r9 R) y: z) z
- if (nwrite <= pagefre)
: A) P8 l9 l6 N - pagefre = nwrite;; P7 g# N5 \- @' C
- - ~( F( C% H$ { S" ]) E
- while (nwrite != 0)6 q4 ~& S0 \) a- u% Z
- {& L+ `; U% f- Q( F. Y
- /* 检查是否超页 */
# c# U+ T" ~- H: x - if (pagepos >= STM32FLASH_PAGE_NUM)
( n, y( P9 A4 g- X! {; V) ] - break;
- P W5 ?$ |7 U9 P' b& o# _- [ - / k& H. V" H# h8 A
- /* 读取一页 */5 K, r) b$ o& X& j4 x' s
- FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE);" H. d* S- @' Z7 [& }# \
" n" \7 i/ _3 A+ ^- /* 检查是否需要擦除 */
8 W$ ^9 Z1 F, }! g: F* O) r - for (i = 0; i < pagefre; i++)
- C4 {& c3 f* w8 {* ? p: \) f - {
$ _2 p/ h9 B& C - if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */
% n6 f. H$ Y* R. k - break;
9 ]' x+ m4 A7 d. | - }9 b. j: x$ h {1 ?9 Q% P
- * r7 P5 V1 R/ p3 y
- if (i < pagefre)
: H: T1 ~ U1 q( | - {% L+ I% g4 |, l( e2 n" ]+ u, m6 i. J
- uint32_t count = 0;
N9 n: j8 _) T0 k* T% K: [& y8 d - uint32_t index = 0;$ m: s+ y9 C0 T. q, L9 @% |
- uint32_t PageError = 0;
; l1 b/ A* D8 w6 Z - FLASH_EraseInitTypeDef pEraseInit;+ |" m5 D" ^% }8 i' G
- % T; R) ?: R# T6 L
- /* 擦除一页 */
* P M6 R; U& ?4 t# z - pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;/ z& d5 L3 B/ \3 w! y5 A" Q
- pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
+ Q5 `) m; y/ { - pEraseInit.Banks = FLASH_BANK_1;& v* @* k$ v, k, q- ]2 D
- pEraseInit.NbPages = 1;
- m) A0 {' g. {1 W# _! k' \7 L - if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
5 w8 n o, E7 n2 Z1 I. i - break;9 X! f. {# c- ?9 e9 L
- : k. z2 D( T* d
- /* 复制到缓存 */
; ^9 e; y7 Q) [# C - for (index = 0; index < pagefre; index++). u% E) _. n6 T$ D* T
- {7 I/ | |) {3 h- a
- *(FlashBuffer + pageoff + index) = *(pBuffer + index);) I6 {* D* y5 }+ Q- @+ ^- e4 {
- }
* s+ P6 l, }/ z$ w7 q; p; F9 c - 1 L* X# M0 ^. o d' a- m# Z
- /* 写回FLASH */
7 ?; H: v: u2 _2 ^6 Q/ K' R+ F4 {) X - count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
7 ^/ T. u/ M* ^ m2 L1 e - if (count != (STM32FLASH_PAGE_SIZE >> 1))
. ~! q& E! C' [ - {3 I M4 E! Y5 E. h: y
- nwrite -= count; x0 [7 H( A' G: @4 g5 o
- break;, v% ^1 \% v5 K/ B) k
- }) V9 ^3 _$ C* I9 Q8 M
- }
8 Y, q. s- u) f9 `' r& h7 x' K - else
( N# p1 |6 |0 }3 H; e- l; E! [- j% f - {0 ^3 T6 c9 s+ a3 ~! Q% K
- /* 无需擦除,直接写 */# {9 q: n* ]9 W8 z& M8 t! Q" A
- uint32_t count = FLASH_WriteNotCheck(Address, pBuffer, pagefre);( b+ g6 k+ O2 Z7 w
- if (count != pagefre), c ]9 |/ k( L
- {
V2 H/ U7 `0 B) g4 Z! O: q - nwrite -= count; o$ x/ f) l! ]1 ]
- break;6 V' s0 n& [6 A7 ~4 m6 S
- }8 N2 L( X2 Y8 F+ V7 X) C
- }- @+ S# |: `. K$ ]1 R1 d& U
- 0 U+ O$ k2 C" k% g' m
- pBuffer += pagefre; /* 读取地址递增 */
& A( d% o/ s- \ H - Address += (pagefre << 1); /* 写入地址递增 */
: f% J! h+ ^9 d+ @4 F. ~+ F* ^ - nwrite -= pagefre; /* 更新剩余未写入数据量 */
, q, U* P( ?* d- o; L, a# E - % o7 m+ I9 R% C1 [
- pagepos++; /* 下一页 */, I' @) o; d" P' E" x5 j. o0 l
- pageoff = 0; /* 页内偏移地址置零 */
: Z+ [8 ~" q, ]
& |( O+ ?. V9 O% }' r/ Q& ?0 ?- /* 根据剩余量计算下次写入数据量 */
5 M, S. g* l. m7 v - pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;5 Q3 b; s- `" B6 E0 k$ s
- }
- s, ?7 ^/ p' X
# j- _* k( u* E" @6 T' u6 r) c- /* 加锁FLASH */8 `% X! Q- x d( Z2 S7 x
- HAL_FLASH_Lock();( n7 ], Y: M2 ^
% ^) M0 v5 _- o- return ((NumToWrite - nwrite) << 1);
$ z' h& K' T/ _$ O4 u* e+ _ - }1 S3 w, Q8 D7 j& z1 E
) R: |6 A9 Y8 R- L- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
& l `! `6 }& p - {* Q X2 f- l+ k1 O
- uint32_t nwrite = NumToWrite;3 n3 [0 k$ Y, {8 \; ~
- uint32_t addrmax = STM32FLASH_END - 2;' Y w( J5 o' D4 w5 L: x
- 2 F: X. q6 D+ u+ j
- while (nwrite)
+ G4 {& |( D' V: J: T! {. |! f - {
! i' S) `% ?+ s6 ]5 E' `: N - if (Address > addrmax)
. H- N3 n* D; i- k1 H - break;
$ ?% o" v% y6 D$ V; H5 Y* R/ M0 v. M
2 D! H7 F2 C: J. _- HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);
+ X4 Y: v: L7 C% ]# I1 U8 a1 Q - if ((*(__IO uint16_t*) Address) != *Buffer)1 z2 K" E: ~+ h$ W4 l
- break;
4 X$ B5 |* B. k( F% Q& n - * ?* g7 c+ a, L( g
- nwrite--;
; i0 N* U L8 V& P - Buffer++;6 [+ q% K8 T w' H4 s
- Address += 2;1 p9 M7 i1 E" P8 p2 q
- }4 I! O0 c& ^* I# j& a6 M1 B/ M9 I
- return (NumToWrite - nwrite);! z/ k2 r# h; E8 t" h6 U1 @, t* O: W
- }* E; B4 ?5 z( g) @
- 8 W, J" E; ]# U* H
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)1 X Y. m6 X3 ]% G5 b
- {) B+ u. Q! \7 [2 ?- `
- uint32_t PageError = 0;% ?* k2 ]6 _( n7 c ^1 t1 `) `) G' D2 L
- FLASH_EraseInitTypeDef pEraseInit;
5 @- L y+ I k: B5 W4 Z& q; K- t - pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;8 w& K& ]: H; n' N! w4 ~( G3 D
- pEraseInit.PageAddress = PageAddress;
8 [& _) d9 Z5 s. t1 U0 M7 r& a - pEraseInit.Banks = FLASH_BANK_1;
- @! c8 T# b* N$ x0 T - pEraseInit.NbPages = 1;
( C9 h( T* E5 H9 |& y - if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)7 r T4 J* i. W( p( I
- {: `7 F* Y" I" O6 `+ [ m
- return -1;$ _' T% `1 L5 R# T1 u% p0 }
- }, |2 i: u1 Y7 s2 ?6 G6 C
- return 0;
5 l, R+ x1 O9 c2 d+ D - }
: x; c' @2 F+ y) e$ u7 I" D! L
# U: E. j! a+ h- end of file
复制代码 2 s4 T% c0 H; c' ]& X1 a
/ L& S3 e' v2 c+ V6 `: k9 N# s4 |1 m$ K1 ?% F$ M' p
) w6 ?5 w' n) Y- ~
1 e5 @7 P7 [0 Q
2 P1 l7 ^: R' L% W, A- P1 Y4 X
: G. V% ]) V1 l/ e
|