测试环境:/ E5 {7 o6 L9 ^3 [: A9 _' H
STM32F103RB
- q7 N' _" |, M* R; \" b; _: c* _20KBytes RAM
6 b, L. i6 |0 e9 N" p. V1 `128KBytes FLASH
# z" j& Z, t; C0 x. [注:本章节代码只适合STM32F1系列!
# t1 ^$ s3 h& ~0 m, r5 f( ?
9 I4 U: R* p) C& s2 j
! K- R; L, K1 e
0 K I& K- G G0 S |头文件
! r6 v% I8 k4 q* J- Z, z' K5 E
% ~4 q# u. M7 ^( z- /**
! L8 k. P6 \$ S+ p4 L; Y5 [. c- K" o - * @brief Create by AnKun on 2019/10/10
: ]& b" w* W7 y, K3 B - */
" ?1 o2 k |( O9 L3 D
# v' k7 p* P( z3 b4 j% N* Y# U) y9 g- #ifndef __FLASH_H9 G1 e4 d: d% Z8 Z8 j; d3 O
- #define __FLASH_H' s$ B+ S2 D. @2 \) ^4 Y/ M
/ H1 J. J4 R* \/ _ M! S) W- #include "main.h"
" X! g, Z: Z( _% k& r
6 j. P/ B2 l7 M; V6 Z- 移植修改区 ///
: ]% [' ^0 b' E) N9 _( q0 ` - 7 A# ]4 U* q7 D3 o9 X" Z2 c
- /* FLASH大小:128K */$ o1 F9 Z1 ^3 ?$ \; `- U! f- A2 ]7 n
- #define STM32FLASH_SIZE 0x00020000UL
! z: i& l' Y* s6 j+ l& _; s( l. O: q - : k% h: {7 y. a! t1 G @9 R
- /* FLASH起始地址 *// Z( w+ E3 \2 H; R2 t8 ~" z
- #define STM32FLASH_BASE FLASH_BASE
8 S. l$ j+ G6 G$ u0 N$ v* v3 b
, |' Z6 L, q9 v. ?$ A- /* FLASH结束地址 */
7 c9 b! t/ l, b- }9 H - #define STM32FLASH_END (STM32FLASH_BASE | STM32FLASH_SIZE)
# [- E9 V: ]5 O. p6 c$ X - % d. Y1 ?$ v3 Q) ?3 ` W3 @
- /* FLASH页大小:1K */
* o( f8 U$ D0 ?! y& S" w+ L5 L - #define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE6 S+ Y- {: @, l, M
- . I, k! L6 Z0 w
- /* FLASH总页数 */
, ]9 s% @; R7 a. G! e( G }* B$ U - #define STM32FLASH_PAGE_NUM (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE)! ^' F ]7 j, J( e/ q3 A3 a
% k9 \( C- P, ?& I& x- /// 导出函数声明
! ]! D( A; s' x) o5 y - void FLASH_Init(void);/ H0 a5 U& k2 ~) v6 _" E
- uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);
9 v, v' f0 z' M3 Y( s! f& z S1 u - uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
3 H" `1 ?; s; H; ^- R5 j, u* A - int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);3 S& L% z2 V2 N# t, f# D: ~
- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
9 g8 s8 M v% A3 n: K
3 r( i# a( B) q9 k- #endif // !__FLASH_H
7 r% P' m' [5 D; ?
: N2 A- o1 O+ a& ~8 }- end of file
4 ` I2 I( d0 U2 ^% t. B" v
复制代码
. y* R2 w* t; `/ v源文件
2 m$ _' ]2 h2 V1 B
+ A3 g- p, _# C1 {5 {8 t0 u% U- /**
* Q$ f8 F# E/ ]4 ~ - * @file flash.c
# D C& a8 f( V- k - *8 F v2 Z5 ?) S8 [ C
- * @brief Create by AnKun on 2019/10/10
, k6 G$ o3 @* g3 b/ w9 Z* ]! _+ e - *
" P' ?: f$ e/ |; R7 B - */
. ?4 ]* E) B: u3 }- {
( c& x2 Q) M& W0 w; m! ?. F5 P- #include "flash.h"2 l2 }5 c' ^# Q: C# H* m- p1 c ?
- #include <string.h>
3 E1 q5 A6 B1 u5 P9 h$ s1 s: w - 8 F6 R* q; S3 C& I: b9 r) i1 n. N0 ]
- static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
- R1 C" ~ f" Y" V4 X. ?+ q
- k: }5 B$ m# c- /// 初始化FLASH
) \; g8 Z8 y% f0 L. p/ }8 X - void FLASH_Init(void)/ X$ n. H& u% e4 b: w/ Q5 u1 ?( M
- {: Y+ { }& D: |, J- D x
- HAL_FLASH_Unlock();* i" R) {, k5 n
- __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);/ p9 G6 [4 |/ s) M0 k3 G5 S+ {) c
- HAL_FLASH_Lock();
4 C' [, f% r/ |) M$ j# S5 c. ` - }
9 a. C5 E! `- X. R
% K8 [. T* W' h i! c$ U- /**
5 i8 x; n; f( A0 I4 i3 j& M - * 读FLASH
8 C0 g, P# t8 p. i* r9 ]1 ?4 e5 R7 m - * @param Address 地址
3 n* X/ R& _" S2 j. q; O: ] - * @param Buffer 存放读取的数据
; _2 [6 h/ P& j& B1 H& ~: [0 Y - * @param Size 要读取的数据大小,单位字节+ o9 ~ C1 s% B
- * @return 读出成功的字节数. o$ w; X T: H! x
- */, O7 U* N2 O' v# |
- uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)0 z2 X+ h, G# t6 t6 j, f; ]
- {
1 i F b2 r' N0 h - uint32_t nread = Size;( m* p3 `1 x6 ~( ]
- uint8_t* d = (uint8_t *)Buffer;4 {4 y7 Y: V7 y( E% S* m1 m- _
- const uint8_t* s = (const uint8_t *)Address;
" S( t: v1 p; I0 |1 D9 j2 C0 Y - " l6 N; D! g3 L! m/ x' Y' ]" J" H7 D
- if (!Buffer || Address < STM32FLASH_BASE || Address >= STM32FLASH_END)$ {3 ]. ]' U. C% E: Z
- return 0;
! a, E7 W$ O8 L% i8 @$ f
% T1 j1 A3 E$ }. f- while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (STM32FLASH_END - 4)))
4 H, ^5 x- a& w+ L: Z2 `) o2 q! i - {! ] F4 j. i" [, g- @1 x
- *(uint32_t *)d = *(uint32_t *)s;
4 z- z, q, d4 } `' ~! O. N - d += sizeof(uint32_t);
6 A! E, @7 [4 d - s += sizeof(uint32_t);! S( v3 h' G$ z+ d/ |. f
- nread -= sizeof(uint32_t);4 |; f3 F+ m/ P- a( y
- }% A1 t$ k. o9 i
- % |/ T' _' a7 i3 b
- while (nread && (((uint32_t)s) < STM32FLASH_END))
+ t9 O& E; X8 @- B* k( @% f/ u - {9 ?* q' a, X0 w" V+ N8 v
- *d++ = *s++;3 R) w! I4 V+ G
- nread--;' y* M0 J$ |# C* H5 j3 `
- }6 X+ T% [3 Y& S' V) L. w
& {7 N+ c4 ]0 C6 {- return Size - nread;6 e! q& D2 q9 k3 m/ I; {
- }2 @3 ]) o9 U* p6 {9 n
9 g2 ^$ [5 ] {' I( F# Z$ L% z; f- /**6 |3 s2 R, V4 b# G# K
- * 写FLASH
" c" u" y* n0 A+ l - * @param Address 写入起始地址,!!!要求2字节对齐!!!
9 K) t. P) {& r* F: G- H - * @param Buffer 待写入的数据,!!!要求2字节对齐!!!
7 c/ x8 R; u4 U- u - * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!!
9 P" r3 }$ H8 v6 E - * @return 实际写入的数据量,单位:字节
. R+ c g2 W3 u; V - */
o% [4 G7 q Y4 A* X4 R& W" ~ - uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)) g3 s' K% e: T9 d8 s
- {
( a# }2 W1 c/ }, j3 Y& }, V9 L - uint32_t i = 0;
2 o+ b" M. I$ k; V' T - uint32_t pagepos = 0; // 页位置0 V p4 s' S' H& u
- uint32_t pageoff = 0; // 页内偏移地址
' q+ q& k" R4 v, D3 c7 t8 m - uint32_t pagefre = 0; // 页内空余空间
5 z k C( z R; h/ A1 M - uint32_t offset = 0; // Address在FLASH中的偏移
0 o+ o' O, _7 V - uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量# A+ |8 T3 n/ Q/ e2 i
- const uint16_t *pBuffer = (const uint16_t *)Buffer;5 K' U! u! J# ^; i' S0 u/ |
8 n+ j% s" p. @+ @: }) H8 n i/ ~- /* 非法地址 */
9 F9 H, `0 L7 n5 f: e- }" t - if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)
7 h* Q) ?% I1 w$ V - return 0;
/ ~2 u- o5 O- t( m( k& d: x - ) k! N# U3 q9 z
- /* 解锁FLASH */
5 f3 y; Y% v2 X - HAL_FLASH_Unlock();
" m3 a# T' y) i$ c* R2 A
# }. _" v+ K# w5 z- U) A- /* 计算偏移地址 */
0 |5 E3 H* |; u; Z& S - offset = Address - STM32FLASH_BASE;
7 v) J, q: \0 c: x/ @3 F1 e) e5 w4 X5 y
/ P( u0 M5 p4 u: m- /* 计算当前页位置 */9 B: n' I; L1 p6 ~% k# A
- pagepos = offset / STM32FLASH_PAGE_SIZE;1 F. l4 j2 X! h3 }2 {
; i: w4 {2 a+ a* Z3 Q4 l- /* 计算要写数据的起始地址在当前页内的偏移地址 */4 G: {" G1 o4 }! E; h5 [
- pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);
* _' j# E4 P5 r6 S! F. n% X) `7 a' m0 a - 6 v1 n1 C* e& C# Q, \" D: J
- /* 计算当前页内空余空间 */2 K* i; X8 T* Z
- pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);
8 E5 H$ N; t) O% R
- ]% ]$ @$ S7 N$ h- /* 要写入的数据量低于当前页空余量 */1 Y; u6 Y+ N1 Y$ q/ \% Q
- if (nwrite <= pagefre)3 g3 u" i& B- T; t4 `
- pagefre = nwrite;& C1 F8 G5 i, e) B0 _
2 e% V5 P+ F3 E( y9 U5 \. m: w- while (nwrite != 0)9 `5 i# [% `5 N
- {
! d' T8 I9 \3 ^; o1 Q4 t) x - /* 检查是否超页 */
( ?8 P* j! [# x% B% l! o - if (pagepos >= STM32FLASH_PAGE_NUM)% {+ v, c! O6 L h& @
- break;
* X5 f" E' ?+ a2 N - , D2 i: z, l2 x# b
- /* 读取一页 */) ?$ k9 c+ F; ?" X0 ^5 j# I {
- FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE);3 n- Q6 \/ a: q7 K6 {# z/ i1 [
; X. p% d6 ^/ y* n, p+ c- /* 检查是否需要擦除 */9 A C- u1 |7 _) E$ }
- for (i = 0; i < pagefre; i++)
: ?3 m V. s% D - {4 g: F3 F# k8 W+ I& s1 N' ~" v
- if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */6 K! {3 l2 h$ V Z3 X# C3 d( S, p# h
- break;2 l2 y7 F6 I4 p9 b9 r
- }
0 ], r3 x- N8 ?3 w# g0 e9 ~: h2 [ - ( P2 ?. w- u4 E: ~
- if (i < pagefre)- @$ N1 G( S" c7 q/ g
- {1 d' |0 f9 {6 n( h
- uint32_t count = 0;7 j" U% q: S* W" f. |7 I& D
- uint32_t index = 0;9 `4 o" c& |' z# f
- uint32_t PageError = 0;+ r/ y' [! |6 Z% w& a9 i
- FLASH_EraseInitTypeDef pEraseInit;6 @0 p8 {2 I. h: H4 W! A: b L7 S' n7 O
+ ^$ w$ G, o+ F# c4 d% @1 s- /* 擦除一页 */
^* t) U8 q" J3 x3 J$ s - pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
# N) g. z# [* E - pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
, ]8 {- D, b, c' D5 z2 N$ l - pEraseInit.Banks = FLASH_BANK_1;$ c, @ v2 y) t2 x) S& T! j9 u
- pEraseInit.NbPages = 1;/ }( Z1 C7 F- U3 R2 y
- if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)% h1 E. F5 Q4 m8 M) ?. A& e
- break;
$ r1 n, |* q R! y& u) H D; H - 9 ]5 \5 G& b! \) a
- /* 复制到缓存 */7 V7 R) u8 b( N( h2 J+ ?' O/ Z6 W
- for (index = 0; index < pagefre; index++)& H! G- q; x$ |2 _
- {
( C4 R. s* `$ i - *(FlashBuffer + pageoff + index) = *(pBuffer + index);
. A. }. N& O$ t' Q$ D" s) B8 A3 c - }
+ L* L) j6 H# F9 D, ?
& T* V) Z1 ^* s5 w- /* 写回FLASH *// B$ l2 B" t8 x" ?( A/ z
- count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
* f8 P, x* @5 ^: M) q1 a0 H - if (count != (STM32FLASH_PAGE_SIZE >> 1)). e2 b' X4 ], w1 [
- {7 [6 P6 e5 z" x6 @: l1 r8 r1 G; d" v
- nwrite -= count;
/ N8 H' q2 G. s# j7 N+ {$ c7 Y - break;: v4 o# ]9 p3 ?) |
- }$ J, |4 f6 M; ?6 W0 u% C
- }- T, D3 \+ R4 p. J' H, M4 {
- else
" n1 T/ _& R9 b - {/ i# Z/ f' |5 g& C) K) D
- /* 无需擦除,直接写 */* K+ |: x+ S t7 y
- uint32_t count = FLASH_WriteNotCheck(Address, pBuffer, pagefre);/ M5 L" ?- H8 C: K! {
- if (count != pagefre)$ w2 ?$ K | Z; r8 T. C8 w% Z
- {1 s7 _& }# M! q( n) w
- nwrite -= count;
, H) S T- Y5 E& T* Y F - break;
5 z) N# z7 T' f" L1 H - }
# _7 U( H# I' w" M/ x - }
1 |8 k" }/ `, U/ ^
+ s- P+ n1 s: E) d* O. i8 z9 R- pBuffer += pagefre; /* 读取地址递增 */
! c5 b0 [7 {& r) i5 G* o - Address += (pagefre << 1); /* 写入地址递增 */: G* @) I8 e* f0 E
- nwrite -= pagefre; /* 更新剩余未写入数据量 */
9 b0 `9 F/ Q5 D2 D3 Q6 \$ H - . [6 t4 ?% x7 l* B
- pagepos++; /* 下一页 */
8 V' N3 S! ]% k1 n - pageoff = 0; /* 页内偏移地址置零 */
7 m5 x& m$ y9 z$ E7 q+ c - 6 z8 l% H- M' e( S6 H# T1 s- [+ ^, t
- /* 根据剩余量计算下次写入数据量 */4 G- I4 k1 H4 n% T4 i" `
- pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;
: G" u$ v' U( Z7 L: E' p - }
, V) E3 a$ ~$ ? R
_& H& O5 p. h% Q, L0 ^# j- /* 加锁FLASH */: d% M$ Z% i9 c
- HAL_FLASH_Lock();* D& h% |0 V6 w; K4 I( N
3 n4 G1 d- B4 P7 O" M- return ((NumToWrite - nwrite) << 1);
2 V+ v3 @$ P, W: R- q9 \ - }! j: w4 B: A5 {7 Y6 n* H$ x
+ R2 ~ ?7 g) N6 Q0 D, u. N1 k: ?- uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
9 _! k7 B; M, V, G - { D" \$ z! h3 `8 {, G. o
- uint32_t nwrite = NumToWrite;
5 \8 x' y1 u4 P- n3 L2 e+ a - uint32_t addrmax = STM32FLASH_END - 2;
0 s. K3 D7 H, x/ y% q8 ^ - # S9 l' g% S: [8 r! z1 @! [ ~
- while (nwrite)
& \% W" K" s/ [. O) I3 H7 X3 ^7 V - {
9 K2 H* E {% E4 y# T3 Y - if (Address > addrmax). ?5 O/ F" q, J
- break;
. W( P ~" s7 d. V - 8 n, V1 M3 _. Y) W/ o( Z( {4 q
- HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);
& W1 G( m8 V: }$ H - if ((*(__IO uint16_t*) Address) != *Buffer)- g$ q; s9 a6 v* F1 R
- break;- t$ j: }/ z* I k' Z& f
( w e8 o6 @; B3 f- nwrite--;
" G9 c# U7 `' r# {/ w - Buffer++; U% g- R1 z: \- u
- Address += 2;
, l8 u! N: I9 ?, e! n9 r - }
; ^, w. z' C' B( u4 L - return (NumToWrite - nwrite);' W7 e# @: r+ M7 U1 @" h/ P. H: E
- }& I) W# T \9 @) M4 I2 s( g" ~! E
- 2 g8 I5 P: s, t, W9 _
- int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)
/ P- Z \7 m/ x5 A/ g( i' T - {# K* `* x4 l$ |: v C4 f, ^) {
- uint32_t PageError = 0;
; ^+ y: a5 ]! r6 V$ o8 ` - FLASH_EraseInitTypeDef pEraseInit;' w" @ L5 s7 I% V1 z9 [2 Y$ k
- pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
% @% i' [1 \: z - pEraseInit.PageAddress = PageAddress;
4 ~- T. A2 e! @ - pEraseInit.Banks = FLASH_BANK_1;
7 X0 Q. T* ~9 T: ]/ q - pEraseInit.NbPages = 1;
$ G9 V7 K: E& P" B) y T - if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
' n& z* N" z' d# ?. B8 X' b - {
0 L9 q% N0 L4 S% J7 \: _3 g - return -1;
5 O, _4 b6 {* Q+ d - }
2 N! z5 ^, q/ f0 f - return 0;7 |/ _% X$ `! U2 |
- }
! i2 p8 F- S. j3 D/ W
! V4 p' w9 P2 X' j) N- end of file
复制代码 5 t& Y5 |* u/ g/ C
- f0 f* j$ p5 E; A7 x% Q
4 }) ~- n. i) o0 @$ b, X
+ l: O& m6 `7 B4 j) {; Q |8 y) ?1 u7 k% V& ^+ j
( J; A6 \# H& A8 \* \
. @, m$ I6 J5 W2 P) g |