测试环境:" ]- @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
+ \! 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/ ~
- /*** ^0 B8 ?; ~: r. O
- * @brief Create by AnKun on 2019/10/10$ L4 k6 b' {/ [9 `: X3 X* e
- *// ]6 F8 H9 c+ G. y
" F% f. z9 u: [% E# I8 Y' T0 K$ o V% N- #ifndef __FLASH_H
6 k9 z% T; w+ O2 g+ ^& D6 U2 x - #define __FLASH_H
5 p7 e) w2 m N/ J. [. B
; l/ R1 T' Z8 C) n! E- #include "main.h"" \+ Q1 K5 n+ V& G, R
8 G9 X( C# \# H7 p3 ^, ^0 A- 移植修改区 ///- I( {) K# R B) h* G
- 8 t: c$ \2 X. |$ |" }
- /* FLASH大小:128K */
* X) ]' H$ o3 P1 Y1 T, F - #define STM32FLASH_SIZE 0x00020000UL- h( E/ g1 y9 o, G, d0 p! J
9 n+ E3 Y9 W4 o8 ^) ^- /* FLASH起始地址 */. C- o+ I) @7 g9 b* a6 U
- #define STM32FLASH_BASE FLASH_BASE5 b! X& {7 T2 G) i
) V! ~1 w$ p0 _" j! Z- /* FLASH结束地址 */
& q! e, g/ y/ V. r, i9 }; g' ^+ `4 m - #define STM32FLASH_END (STM32FLASH_BASE | STM32FLASH_SIZE)
7 \: k0 A) b! I* Z. m$ n( {1 f+ f - 6 o3 @4 B# k6 \7 m+ [( P
- /* FLASH页大小:1K */
" Q+ s8 r/ x6 Y: W - #define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE8 A5 s3 ?% p* Y- ?/ H& o& _
5 d# o) K" n8 o1 J* Z9 \, @9 E" o- /* FLASH总页数 */- h Y& W) P0 A6 Q* I7 _0 D
- #define STM32FLASH_PAGE_NUM (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE). y/ H; i. m! J: }
- " v! n9 @% h5 `7 C
- /// 导出函数声明
3 A7 q7 x- [1 ^( F, T/ i/ j! r2 J - void FLASH_Init(void);
8 t( t/ J, `. s0 ?7 u; t6 K5 `: r - uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);6 A0 |* {/ ~% _2 v# G H0 m% r4 F0 b. s
- uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);' \5 d! Q3 {! f9 f, _& S' G
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);! u3 k6 j* Y }* d# H T* b8 ~
- 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
9 i# n- S" ]7 K& k+ L& G- #endif // !__FLASH_H
! r% U0 ?& t3 Z( j9 ]& d5 S g - , O: ]6 N- v" ?' A( x; U
- 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- /**
_5 s& h3 F7 g6 z; O% w - * @file flash.c
1 o6 Q% j! I! L* `; f- `3 k4 f - *
' | H- u; f& Q& z: X - * @brief Create by AnKun on 2019/10/10& b, h3 c5 h; S9 j, g$ w/ N, s' F4 P
- *$ o' q7 E2 x9 G$ v
- */" m% i4 \1 `6 o) A) r
; E, E. n9 a8 V U: t- #include "flash.h"
+ f) z& c* J+ L4 d - #include <string.h>/ l$ d/ U) s2 G1 e/ N
, M) _9 S5 @ _' E- static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
1 ?8 J y8 N/ K# {; Q
) A+ ?9 T, e6 H0 ^, A5 s- /// 初始化FLASH
1 U. ]& ~% r" _- ]9 E; E' ~0 H - void FLASH_Init(void)
2 }% a, r6 ^+ ]( a& n/ V - {
1 R; }: Y) m6 m& L! ~! n$ C - HAL_FLASH_Unlock();3 t0 {# Z9 j& P. E, W
- __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
' O, ~0 ]" I+ X: E - HAL_FLASH_Lock(); H# K* ^& a# H- _/ U
- }0 u- h g" f, ^6 s* O
- 3 t0 i, |! z% U2 y0 b. _
- /**- x0 z/ E. e6 Z G' a
- * 读FLASH9 R/ t4 M/ i/ K4 p& o
- * @param Address 地址
, n2 o4 m- T& f/ |. W1 F7 P - * @param Buffer 存放读取的数据
% C* z2 x: t6 p: z0 k, }; _7 P J - * @param Size 要读取的数据大小,单位字节5 R; F3 l7 T) W8 V. _) x+ p) y& j, M
- * @return 读出成功的字节数
8 T* d8 |+ {( o+ K8 X - */1 P ~, w% f& A- D" `
- uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
' `- ?/ h2 @7 `9 Q+ w - {
4 B* v( Y5 U3 J8 G - uint32_t nread = Size;4 @% @8 S( n" v& A) Q
- uint8_t* d = (uint8_t *)Buffer;/ L- t) S" d& p+ G' H& S
- const uint8_t* s = (const uint8_t *)Address;
* \/ ?; _% f9 g4 m
0 {# c- r& f7 T/ m- if (!Buffer || Address < STM32FLASH_BASE || Address >= STM32FLASH_END)0 Y R9 Y/ d! d% V3 Z4 E% Z
- return 0;
4 I! w+ b3 W2 [. X
: t, N- K* X2 ~8 N: _. b- while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (STM32FLASH_END - 4)))
j# J! k% i/ U8 K4 K - {4 \- m1 `4 D- M! t5 z O$ O
- *(uint32_t *)d = *(uint32_t *)s;
: J& h$ N; s/ R T K+ z5 H - d += sizeof(uint32_t);" e. h8 A5 x+ m. Y7 U |
- s += sizeof(uint32_t);+ {8 L6 X$ N4 L$ f+ m7 y3 J5 Y
- nread -= sizeof(uint32_t);
$ [7 B' A" l, r0 _2 p. l5 M - }- O" E9 N [+ _
- ' T- d2 R5 u+ y7 F! F
- while (nread && (((uint32_t)s) < STM32FLASH_END))
4 i+ x/ O$ h" |; s$ {* X - {
; z+ y+ M3 `+ o9 Z& i8 z, m - *d++ = *s++;2 |4 H; `" p1 H
- nread--;2 b" H7 t* W, Q, ` O0 N
- }+ A, t. I6 j# ]0 h9 K
$ V6 |- r1 q9 q7 G: e% ?* x8 X- return Size - nread;
, s1 J& o. J, D, d# c - }
3 }! R' J$ ^6 z/ V4 n1 Y: Q
& x0 b3 t3 z- _- /**
( _( M) h& q$ I0 n4 \+ |4 Y - * 写FLASH6 d, f0 |: [- J* E: q, [
- * @param Address 写入起始地址,!!!要求2字节对齐!!!2 u3 F+ v1 N4 B9 l
- * @param Buffer 待写入的数据,!!!要求2字节对齐!!!
% b. X* ]( y+ P9 ? - * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!
! c( b* N; H( f9 i' O7 x: d$ j( j4 T& l - * @return 实际写入的数据量,单位:字节
* Q; N0 x _7 F# } - */
; L7 Q( s! _# |4 r; h) s% [ - uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
1 W8 e" t% ^: g' u# V% [ - { `* I3 D0 J& v9 W+ I" X% s
- uint32_t i = 0;
( e+ [+ e2 H% D - uint32_t pagepos = 0; // 页位置- V, l; F* W2 i! L) h& j1 F! t$ \
- uint32_t pageoff = 0; // 页内偏移地址- j, m) w B# j7 ^
- uint32_t pagefre = 0; // 页内空余空间
/ R3 ^: N P& x5 H8 { - uint32_t offset = 0; // Address在FLASH中的偏移
6 X9 T, T6 T" }7 v% t1 Z - uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量$ b' a0 J. A" U. k
- const uint16_t *pBuffer = (const uint16_t *)Buffer;% p% A% _2 k: E- ^
, W0 }" h- [5 j! X" ^- /* 非法地址 */ @9 h8 }1 D2 v
- if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)# h7 [; I C5 M, G2 n0 A( y6 [, J: Q
- return 0;
4 V7 c5 m$ n& a# q3 W/ b - * c* e. ~$ u# Y4 ^/ n3 }7 t; B/ A% ~
- /* 解锁FLASH */
- [( Z! l- Y1 f8 ] - HAL_FLASH_Unlock();1 b5 u- s$ j, _9 W' J$ p5 E
3 j; T' d# w% r: O6 X- /* 计算偏移地址 */' H0 y6 F" P. ^* t' Y1 |, N# Y
- offset = Address - STM32FLASH_BASE;
2 {9 U. h# V' Y- J3 @: \: i. ] - 4 @" K/ S( H, e: Y: F8 V
- /* 计算当前页位置 */
; o& t1 o$ |1 I4 D - pagepos = offset / STM32FLASH_PAGE_SIZE;
( K7 {) y! [( w7 p" z: o$ W- j - / c8 C3 X" r7 }0 W/ U9 L
- /* 计算要写数据的起始地址在当前页内的偏移地址 */$ D: ]( E1 a8 z3 ]% |
- pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);
3 D$ O' q4 T7 c P
5 E! c# \$ ?% c7 d% r- /* 计算当前页内空余空间 */
& n, M3 V$ f0 F- X4 K1 f* y - pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);1 W$ v5 ]$ `* G& N7 `$ ?9 `& ~& u/ l
- A9 K7 u2 P9 N6 Q( t7 x2 \0 K: x- /* 要写入的数据量低于当前页空余量 */
1 k' k6 z6 D1 m. y6 E. V8 J - if (nwrite <= pagefre)
7 _+ b; J8 e0 Q+ ?8 p; f - pagefre = nwrite;) ~1 i- S+ x. A4 V# y. ]8 r
) v$ ?/ X" {9 f. [9 h- P! H- while (nwrite != 0)6 D4 U4 `* G1 n& V/ Z
- {
0 t4 V, } b" q$ H- K/ o - /* 检查是否超页 */+ G5 m3 Q# M( W9 z3 U
- if (pagepos >= STM32FLASH_PAGE_NUM) @9 `, C6 Q0 w/ V/ o
- break;8 I; c) c4 f- S0 w0 q- ?
) o9 y* v% c5 |7 @, Z" f- /* 读取一页 */
/ h) T. h- P k2 s$ u; y) l0 k - FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE);1 _3 n+ X3 ?* {
. k0 p2 F( H- G9 U3 C. P( L' k- /* 检查是否需要擦除 */
) j5 m$ `3 m& a$ `4 w8 D+ z% ]. o - for (i = 0; i < pagefre; i++)
+ J* [* u- \3 J' S v4 ]& C- R - {
5 }0 E0 Q* I5 \$ V; c - if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */+ L6 J- Z) Z, X! F8 i5 P
- break;
4 M' f3 Z3 \5 q4 E' ?: K, _ - }
+ f, P# X* Z x! F4 L b+ l) Q - 9 q9 B% O+ J1 U) c3 v; i; J
- if (i < pagefre)
% C0 s7 T3 n( h# v/ U - {
' p/ d5 a) P+ I0 O - uint32_t count = 0;0 }% @: }. E6 S0 H3 w6 }( ~- k/ m
- uint32_t index = 0;
. p/ a7 c; R. ~ - uint32_t PageError = 0;
+ |: r) T/ e* m/ q6 B) O. c4 w - FLASH_EraseInitTypeDef pEraseInit;5 V/ E/ T/ } L( P! c6 U! C) s2 m" X
' a! B" F3 A+ O0 r/ d% Y$ w- /* 擦除一页 */+ j% e/ k1 Q/ C& a/ s
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;% ?- v9 d$ E: @0 ~
- pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
' f9 V: [3 e; l* Z7 X - pEraseInit.Banks = FLASH_BANK_1;
* L! S9 _, Q8 Z e - pEraseInit.NbPages = 1;
1 X* C, c. d. m- ~0 h - if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
! {& F! `: K4 j0 E - break;
! N/ F! r- s$ E5 G - & Y" o3 `- \0 N
- /* 复制到缓存 */
! w* U$ C8 E8 a& A7 J0 m - for (index = 0; index < pagefre; index++)' [# A9 m1 ~2 b& I7 I' F' p) _
- {3 k& _ o+ ^& b& G8 A
- *(FlashBuffer + pageoff + index) = *(pBuffer + index);, |& t. c ]) X% ?
- }9 l4 o2 P/ y! I# y
5 J* s. n8 [+ R9 {2 i* `- /* 写回FLASH */
9 @! }* F: D/ M - count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
2 y* O6 I5 k2 ]0 `! O - if (count != (STM32FLASH_PAGE_SIZE >> 1))- N/ H, a9 J4 o4 t
- {" u* J0 _! v% a* |4 |
- nwrite -= count;! O: T7 V( x6 G5 ]/ `! e5 D5 r
- break;1 F/ N, o1 D& D( _7 }8 w+ N
- }
6 `/ ]0 Q6 @$ n - }
4 o+ |. s# _, O5 [ - else5 B* ?, V( e e5 ]( I" d) y
- {' K! @& V# ?$ o2 E- w6 p
- /* 无需擦除,直接写 */
% s5 e7 K, \! l( A - uint32_t count = FLASH_WriteNotCheck(Address, pBuffer, pagefre);
* ?9 {8 S8 i1 \7 B. _ - if (count != pagefre)' m5 b/ K% S. }1 B! V- d1 P# L! |1 U
- {" p/ p4 z4 U0 l1 m, y
- nwrite -= count;
! m1 G* r# q) V8 G" v4 R7 x% k - break;0 O$ a0 D# \' [4 @( a9 x
- }
1 T: W# M9 D! Y2 K2 h* Z" q4 w - }8 `' q3 {( s- n2 {7 Y$ ]* u
- y* F; Q' ~7 N. E- pBuffer += pagefre; /* 读取地址递增 */
/ _6 B6 x' _: n1 I/ B" U - Address += (pagefre << 1); /* 写入地址递增 */
! H1 D3 k& X3 c0 D - nwrite -= pagefre; /* 更新剩余未写入数据量 */" A. o8 I( v5 |# t
- 7 [, }7 ^5 o. |3 C' ?
- pagepos++; /* 下一页 */
D9 ?% M$ V* _" e& p' E - pageoff = 0; /* 页内偏移地址置零 */2 Q3 j: z5 x5 `' h
- " ?& Q* l( }) L. h: |) P% A" U
- /* 根据剩余量计算下次写入数据量 */
* W4 J6 q5 i# L& |3 r. f6 @6 | - pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;6 p9 Y) W& R# [, _3 @
- }
$ N2 {- o& Z( x& v4 p& J
( S$ @$ `5 H I0 e; r- /* 加锁FLASH */
4 E7 W# f1 T, ~/ ]6 P0 K5 V; h' ~ - HAL_FLASH_Lock();9 c1 {6 M5 V( E" B) b2 E
' h1 ]- v' {; U1 Q- return ((NumToWrite - nwrite) << 1); a7 M' E* X" b
- }
& W1 {1 i8 I/ a) s, n4 e2 T# W - " A9 g) E+ n/ R
- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
5 F5 v2 l2 r& I+ _0 S L - {
# r1 q' ^6 k/ T7 m) ]7 x - uint32_t nwrite = NumToWrite;
. t% b0 ^% r7 \% ^ - uint32_t addrmax = STM32FLASH_END - 2;
; K! M% X: ]! j% d - * {- e- e6 n0 w2 j
- while (nwrite)9 d$ z, V. C2 v3 T1 n
- {
* c7 a3 Z- W8 f% h6 Q. l1 {$ b - if (Address > addrmax)
$ `& D( U& }+ ^3 s( b; X - break;
" J7 s: n- B9 o; q) t A+ N7 ?6 _' g - " b1 c X# N! V$ l& E/ D6 b7 T
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);4 J6 G- o" q6 M: Z2 ~9 @
- if ((*(__IO uint16_t*) Address) != *Buffer)
6 \' v% F+ E. R. ?, ?" U# u - break;
{3 W2 l1 j- I& m9 c3 ]
7 E& s! Q/ s& _( i2 d8 K3 K- nwrite--;+ a! B f& V/ C! O$ K
- Buffer++;+ d- ]& r- N5 k% A. E
- Address += 2;
# m1 `3 Y9 ^& Z! ~ - }
A0 _0 ^$ y7 ?2 b2 t( M - return (NumToWrite - nwrite);
* |$ |/ d8 h/ Z2 }9 h - }
: E; [2 D0 @0 S* S - ! a9 b6 n" P' f5 ?2 ~7 `+ _
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)) I0 F: T" l# W! s! s/ i
- { B5 ^8 x# o/ Z. }7 A7 {
- uint32_t PageError = 0;
; I) l# u4 v1 t# j* U# e6 n, m - FLASH_EraseInitTypeDef pEraseInit;; o* j- x+ Y+ l9 K
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;$ O. L; M- |7 t' d
- pEraseInit.PageAddress = PageAddress;
: ^6 [. `0 Y) \' ^6 c6 [ - pEraseInit.Banks = FLASH_BANK_1;
4 p# K, e4 p' o h$ x8 ~% J3 H - pEraseInit.NbPages = 1;
+ B8 B( ?( g& w6 |; Q) Q - if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK): z, J$ Y! ^, t5 s* B7 v, p9 T
- {
9 _! c+ _& [. f - return -1;1 I9 y8 J1 N- R
- }7 @' J/ t' K/ I: K9 B
- return 0;
$ i' t$ v0 F- J- k; D - } \0 i+ p! H2 [4 F0 X) P
! Z6 L! z |: I5 B; @9 r) k N2 y- 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$ ` |