测试环境: p, @% C/ i( f* U ^
STM32F103RB
9 e6 e$ ?% P3 R0 l, ~& A20KBytes RAM
; ~8 f& m) Q: T i1 p128KBytes FLASH
$ Q7 u! [( J* a% _ r. h注:本章节代码只适合STM32F1系列!# l2 r7 N H" w
7 `5 T+ {; p7 v: S# X
2 [" J; y; z3 n6 @/ ?0 q' p
6 _7 P4 M, @; \7 f" f头文件# k1 M$ A* _8 X& i
& f4 g7 U3 A4 g+ @' z" R- /**' S1 l* J. }/ a& Y1 D
- * @brief Create by AnKun on 2019/10/10) u* W0 g2 l# x/ x9 S) ]" F
- */2 N- j1 T6 o7 A1 B0 Q% G
- ; u t- U$ j8 o
- #ifndef __FLASH_H
( r$ Z3 R7 W# u; s$ ?) z/ F5 I - #define __FLASH_H
2 X! e- ^$ g6 r' `! m | - 9 a6 A' `- N9 s- N ^( _. w3 U
- #include "main.h"
" j# e0 ?$ g6 s# K" g - $ s! Y$ @6 A ^, k5 B1 J3 o1 z8 t0 d
- 移植修改区 ///
" v2 {% V) c0 ?* m7 F" F! F
" g7 p' Z0 q7 Y- }$ `1 `2 B& `- /* FLASH大小:128K */6 r' q- U0 i6 l: x0 L: R
- #define STM32FLASH_SIZE 0x00020000UL
b8 u6 B( ]& y2 a8 \ - 8 r. l9 j. S4 v5 m+ |
- /* FLASH起始地址 */& L0 [. w$ f K
- #define STM32FLASH_BASE FLASH_BASE
! Y; ^* R* e5 J2 `$ B2 ~ - : G' d0 A/ p# C9 o) l( N8 R5 W
- /* FLASH结束地址 */
0 [( d& H7 w3 F% X, r# e' g - #define STM32FLASH_END (STM32FLASH_BASE | STM32FLASH_SIZE)
! y8 @: s" ?* i, G8 d6 W, b: V - 7 C( K/ a0 i( [- E) p! R
- /* FLASH页大小:1K */
. N- m2 H$ C/ q3 A - #define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE' j; z0 m; z2 t3 z1 B
- 3 \4 p% }% Q [, u3 U& w
- /* FLASH总页数 */
' r, _6 B3 ^1 @6 w; _( c4 D% X3 ]6 M - #define STM32FLASH_PAGE_NUM (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE)5 `' `( k3 h0 B
$ s9 J R" ^- y: S* V9 ~- /// 导出函数声明
7 X3 s% s) W k1 {) g' P2 r7 x6 c - void FLASH_Init(void);
8 b0 R d2 \4 A - uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);; P s) c% @: F# q
- uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);+ Q# Y4 y1 n6 O/ A8 P
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);# r+ Q( y1 \1 D1 M3 j# }4 F
- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
- Q7 }& B a/ `, e - % X' }7 z+ V) y5 d* \- c
- #endif // !__FLASH_H4 H9 Y5 L3 O6 j8 k2 k
2 q' |: ^. X5 K* B- end of file . l% Y3 G* y) c
复制代码
( _% x' F% Q" s8 Q; G3 w5 e源文件
6 U5 r1 E G' J5 P3 N; g \% L& M5 p+ r' {
- /**% ?5 x3 a' g% {- _ Z1 t
- * @file flash.c
4 x' K* M* D5 B) J* B - */ g% d' x1 n3 l1 i4 o, p
- * @brief Create by AnKun on 2019/10/10
5 U. B( O0 R/ D8 F1 W - *7 b) |( A+ }+ O" l$ n8 N
- */2 u3 G3 `0 \7 A$ k8 d
- 1 Y4 N6 a) w" ]6 v$ r
- #include "flash.h"# T; t! N( V6 l$ }+ y1 Z
- #include <string.h># s5 S. ~1 W7 W
- . F4 B" p1 O4 G- v+ y3 \7 D
- static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
x3 D9 z1 c* L4 D' i/ G8 r' ?/ Q0 p - % s, Z: g: g: `. \* ]0 F3 | l
- /// 初始化FLASH
6 j* G. G n' h( g1 M4 M - void FLASH_Init(void)9 ]$ P; }- K! _
- {- ^& W+ l5 ~6 b. A5 J
- HAL_FLASH_Unlock();
1 B1 z' q3 g/ m5 e' o; j - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);: C1 q0 ?: j7 c5 j2 K
- HAL_FLASH_Lock();2 P: M8 F$ T+ o1 \+ J) Y
- }
* m* F- r* d! o" s9 d6 ^
" C( V$ c4 J/ j1 s4 N. c- /** h& ^. D+ d2 U; K) Z6 h$ F& g
- * 读FLASH* C x( `% X; x# G3 _
- * @param Address 地址
6 i/ Z* f9 V. {; M) m/ ^& P - * @param Buffer 存放读取的数据
& ~! M) v5 P/ Z3 T6 K& B, ^* A - * @param Size 要读取的数据大小,单位字节
2 R3 ~; k! K! o - * @return 读出成功的字节数$ e) B4 Q% x3 T, a2 B$ h; H) S6 ]
- */
) d3 x- a* W: V! ]/ K: i8 D/ _ - uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
, M' n/ Z! i. s' e' m - {
7 v, d% l+ ?1 t3 ` - uint32_t nread = Size;
+ L! m, U+ C$ f D. K' O; C - uint8_t* d = (uint8_t *)Buffer;9 `( I1 l O0 \- o2 c9 x& P3 s
- const uint8_t* s = (const uint8_t *)Address;9 [+ K0 m$ a$ s# v
- % \' s ?+ L3 x# c
- if (!Buffer || Address < STM32FLASH_BASE || Address >= STM32FLASH_END)
6 o) I# _( C' ]0 G$ U7 ?1 ] - return 0;4 m: g! W3 \( F" t6 O
, ]+ p8 I0 W/ ^* w) ]! n" {- while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (STM32FLASH_END - 4))). X- b5 L5 N3 w. e+ I" \0 F
- {% m) k3 P& E( F/ b n4 C
- *(uint32_t *)d = *(uint32_t *)s;% ` m: [. B" `. q" _
- d += sizeof(uint32_t);
4 i4 p- R( v4 A4 }, g( N - s += sizeof(uint32_t);2 U5 m$ V3 n/ j) ~0 W% X
- nread -= sizeof(uint32_t);- p* F6 C0 Z$ A
- }
+ L3 [8 I7 o5 D7 i - 9 u. f, K: U1 p( E" |; `6 _# q
- while (nread && (((uint32_t)s) < STM32FLASH_END))
/ g6 A% h/ ~8 b [! H' C& @ - {
9 B. i* B$ L- R& I x - *d++ = *s++;
- L4 b$ s: b& ~" ~ G, ^' ]% j - nread--;& v, ]$ _0 S" |- r7 b+ ~; D9 g
- }
! i( U5 A( _3 U, ^: X) h - ; J8 I$ j, T4 N& u
- return Size - nread;
+ R4 L* \8 D: N: l9 K5 Q, F - }8 }) ^. v: D. ^1 W9 k4 X" N9 p) g
$ B+ y7 n# C* Q, K- /**5 d% e# H$ ^' e8 `
- * 写FLASH
2 L9 m; j$ C7 e - * @param Address 写入起始地址,!!!要求2字节对齐!!!
1 W( v0 ]8 P/ O, G8 p- e$ a& D( O3 q - * @param Buffer 待写入的数据,!!!要求2字节对齐!!!
8 o8 P( _/ ~* {) T - * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!; P9 f0 B4 @0 l) D0 B
- * @return 实际写入的数据量,单位:字节
& _) u) o- ?3 y- C3 U - */
/ Y1 ] I4 S4 m - uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite): W) n5 P) m- K k! Y( ?. T8 Y% ?6 k
- {
l* ^; o; m, U T5 { - uint32_t i = 0;; ^* {8 o5 b1 {" W1 N; u# b. ?/ u0 f" T" M# c
- uint32_t pagepos = 0; // 页位置1 a# r7 O) Y' J: c8 Z8 {
- uint32_t pageoff = 0; // 页内偏移地址
+ L( h( q, b4 G( `* M, } - uint32_t pagefre = 0; // 页内空余空间
8 ]( {% `0 t" d - uint32_t offset = 0; // Address在FLASH中的偏移" r. v3 A3 F; S' |6 m; d6 N+ t: N
- uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量0 R; \+ `; g _* Q
- const uint16_t *pBuffer = (const uint16_t *)Buffer;) o. L( C$ ]6 d U" Y; p* x' k
8 C6 r* ?$ d4 {# B- /* 非法地址 */
7 Q* t6 |7 k" t/ P% b, x E. | - if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)
5 Q3 N/ _* z0 Y- {) Q - return 0;
2 n2 e' O' z' J) Y4 b. G$ y
7 `! R2 H* l5 W" d, }1 ?- /* 解锁FLASH */
6 D) ]' u, M, O* }3 o( x# |2 H - HAL_FLASH_Unlock();3 g# t- r) }! `4 b1 m2 Z% }! ~$ I
% T; h. B* d0 r( j$ a- /* 计算偏移地址 */" g) n' y0 f& K# R
- offset = Address - STM32FLASH_BASE;
; `# ]; t' c @+ ?$ j - H- X& G9 N' M
- /* 计算当前页位置 */# Q; Z# u9 h) h6 ~
- pagepos = offset / STM32FLASH_PAGE_SIZE;
/ j! y; W$ C6 l/ h" b4 i" C - 7 \+ j3 y" ~8 X6 c: ?( x5 v
- /* 计算要写数据的起始地址在当前页内的偏移地址 */
# M/ y9 {4 x# ]. A. x% g - pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);
7 I; H) r) T, |7 W% f; B - 0 E/ g- P, |2 D ]+ O. j2 B$ _
- /* 计算当前页内空余空间 */
/ K0 O' Q3 [; |3 D. H. o# { - pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);
. ^# E7 w+ w+ n9 t! [' K - 9 j" G' q/ ]) L( G$ m' |- @! Q: `
- /* 要写入的数据量低于当前页空余量 */% i& V. \1 z8 v3 q' l9 X' O
- if (nwrite <= pagefre)& h2 O: n9 E) s# Z7 X, A4 o4 R1 X
- pagefre = nwrite;3 }# D& A1 p4 `7 P$ l
- % v3 M) E- O* x/ J1 C
- while (nwrite != 0)6 S7 l: i0 Z5 V0 H% Z1 B7 R
- {
$ L6 ]* o& _4 z6 f, j) U - /* 检查是否超页 */, e. n. Q1 R1 q% o+ ~3 f! y+ R; c
- if (pagepos >= STM32FLASH_PAGE_NUM)
9 r& ^) S8 E; |. R* c! I4 e - break;
3 j/ F9 y- H" z- Z - * v# E0 ~: z# s+ |- ]9 G& U4 i; D
- /* 读取一页 */, {: M) I7 W2 Y/ R6 r
- FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE);
6 D7 ^1 V- E R
( T7 g6 i; y. z6 {: v/ g1 S- /* 检查是否需要擦除 */
` U: ^. K/ T2 Y3 o1 A - for (i = 0; i < pagefre; i++)
@3 N9 w& U1 w" ~ - {
% l8 r6 O6 A9 I* }' @: a" Y5 m/ b/ e - if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */! f* b) t# m% r" B5 P/ u
- break;
& T9 [3 A' [' D8 p1 X# ?. S - }$ V) C" N o/ T
- ! z1 ?/ @. S, n: F8 h7 i
- if (i < pagefre)/ q( Z& |2 a+ V: y
- {
8 T% O# O, h8 d* m - uint32_t count = 0;
+ ?5 e5 c# ^; ` g: y0 ^, ] - uint32_t index = 0;/ f! z( n' I/ h; y0 A; r) f0 W# V
- uint32_t PageError = 0;
& g" J3 R( l, L9 X6 ` - FLASH_EraseInitTypeDef pEraseInit;
( l; A4 f- ], ~9 Z - * l- D0 G4 o# ~# d6 ~2 s
- /* 擦除一页 */1 V |- s+ x8 t- c" e: F2 F
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
: c% g c/ G7 y$ Q+ n& C - pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
: b0 w9 [* A: x/ T) e) k# _- q$ W$ \ - pEraseInit.Banks = FLASH_BANK_1;2 B5 h/ H% p, |3 |2 v
- pEraseInit.NbPages = 1;7 Q3 r2 M. ~* p
- if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
' S! q+ K7 H$ ]1 g: u - break;
. L2 G# U' s; j - 1 g, \# N! @ \7 L
- /* 复制到缓存 */% T5 a3 |" Q) W0 R, v6 ~
- for (index = 0; index < pagefre; index++)
7 G" H0 k# d. g8 R& L+ j1 D& l - {
]/ Z' P: d7 @% w5 |4 q* }# Y - *(FlashBuffer + pageoff + index) = *(pBuffer + index);
& `7 a# e _& |8 h1 Z0 w - }
; i2 l. \; c, ]9 e$ r7 G4 F
8 \) o. l5 U1 } t8 x) I- /* 写回FLASH */3 E/ v3 ^3 |1 J' e1 C7 `9 i2 E
- count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);$ C0 ]6 r& m5 X; U/ _7 G5 i, W
- if (count != (STM32FLASH_PAGE_SIZE >> 1))9 f$ {% I# b6 p. |6 G
- {$ U0 I: J# u/ S6 s; U! P
- nwrite -= count;# U$ c! l) g) @, H/ P- x" v" x
- break;
" i8 S" d, ?- u5 X - }
. M3 K& m8 Q0 `0 c - }
* g6 J; K. p, G7 A - else' l* p" V- |; \$ l( t, c
- {
# W M2 m% c8 P4 J J+ v7 K, d - /* 无需擦除,直接写 */. a% y% c4 F" k
- uint32_t count = FLASH_WriteNotCheck(Address, pBuffer, pagefre);
& I7 f& K6 M( U# R( q - if (count != pagefre)- O3 K) j) B: _- K
- {
/ Q" r7 h# {5 ~% j - nwrite -= count;# x c0 G, J- ^& W7 Q0 n6 a
- break;6 ?4 \8 U" T$ D Y6 B+ R
- }4 K! e9 J" _7 t, k
- }
' y: h# A- p' ^* k% s0 S* [9 |" j - ; o }% }4 o1 e
- pBuffer += pagefre; /* 读取地址递增 */! N. X( ]2 i& f o
- Address += (pagefre << 1); /* 写入地址递增 */" D+ S* B& ~7 X, F8 |" W/ P5 D
- nwrite -= pagefre; /* 更新剩余未写入数据量 */
. {6 r1 m8 n7 E+ b; K/ { - & G) Z# k# L& Y' u9 N8 e* N
- pagepos++; /* 下一页 */! u+ W# t& [8 M- H9 D7 {% D0 g
- pageoff = 0; /* 页内偏移地址置零 */
q/ G0 G! @! `* D
" C' U5 t. A2 B! \6 f% O7 V& l- /* 根据剩余量计算下次写入数据量 */0 O( z# y6 E5 ]! C' l3 i/ g8 k
- pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;
% {2 Z0 ?/ E' |, V% c! O - }9 V. N% ]3 W+ l, o2 Q+ R
- 4 n" S& T& k. a
- /* 加锁FLASH */
1 y7 w A& f g, P% l2 m4 ?( G1 { - HAL_FLASH_Lock();
8 i$ A, Q4 {5 @- K
9 Q: u2 v" F2 P u( [- return ((NumToWrite - nwrite) << 1);+ I$ Z7 w0 v6 ~
- }
! ^" E- \: B. a& Z5 I; _2 s! x' k8 v2 ]
Y" f/ ^/ h, d- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)3 Y% z4 c: Y7 G5 u5 Y7 n& e0 k0 j6 r
- {1 j) F0 m. `0 K. z& v
- uint32_t nwrite = NumToWrite;/ O- f! L/ P! D5 g) D
- uint32_t addrmax = STM32FLASH_END - 2;
- i) L* ?: d# S% w" c - 5 Y" R7 f; N3 o7 ]* t" a5 p# X
- while (nwrite); l2 \8 K8 c2 y
- {
' m5 @+ V+ v" l" F9 G0 O9 V - if (Address > addrmax)* d8 v; E5 h4 Y+ k5 w- N
- break;
, N4 @ N. t' ?" l$ D
- m& Z i+ D+ ^; Q2 w5 r- HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);
" T- i: @$ M! @4 m- c K6 n+ D4 O2 h - if ((*(__IO uint16_t*) Address) != *Buffer)
& k4 v q7 U4 @1 B5 m/ H/ P2 a - break; i' B& q! y% k q
- . a0 @. {! A5 ]
- nwrite--;# E4 ~& s; b7 Y# {) r( ~
- Buffer++;5 p7 e, S9 d" o7 P8 t1 ~
- Address += 2;
) C/ J, E! A/ V" d" K& q. H5 q( r - }( R+ X1 i X( E* Y6 x" E
- return (NumToWrite - nwrite);( q1 A9 t+ c% E& F$ [! l6 L
- }
3 k; z) T2 d% y) C: B( b& Z - % @5 l" |. T! X" ^2 C+ q) x6 z
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)
, y! T6 N+ t& | - {
7 ]* o A* b0 Q& Y5 Y! n$ G - uint32_t PageError = 0;
, {" O: \( o; ~ - FLASH_EraseInitTypeDef pEraseInit;2 \. m m3 M$ @% R _
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;: B8 n! g: ]8 l: A5 [# S8 z
- pEraseInit.PageAddress = PageAddress;
" [ Z" S" _' @5 X$ h - pEraseInit.Banks = FLASH_BANK_1;
, p% L' J3 T7 J/ Q - pEraseInit.NbPages = 1;
( |5 G# U, P5 N3 V - if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)/ P$ Q9 q8 j+ G5 e2 I7 Q; w. t! C8 R! L
- {( c6 T! x' a# I" m
- return -1;
) \; t1 m: ?( b# d5 d0 |! b - }
# b# ~' @$ l/ f - return 0;
7 f/ [: |7 M r# F7 l - }
( j/ `$ P# {2 x8 V; `$ \+ G - ' f7 A/ y8 `+ ]
- end of file
复制代码
( w0 h! X2 \& s- b4 |3 P3 T0 i% M5 u6 I& z$ q+ U
# o% F/ [) k4 l3 W" W
" }; p( d% k) w" U5 t2 P+ h8 Q+ j2 {* s/ v6 v
% ^" L- f8 Q3 H Z, q- j
: ]$ H+ B, }. ]& w |