STM32G070的flash读写问题
+ W8 }! c Z2 L3 r! s, m: Y2 L7 J1 B# |STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。4 O, b S& m4 M3 d" {" h
/ B+ ^! E# n8 S' h5 G! K. m: O) T% }! g0 P, ~; z5 L5 R4 y* n
( Q& v" X& O' Z" x' v
问题
; Y) g, G1 u5 Q; n( [8 a开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
6 T2 V5 b: U% |, Y: H. f- T
+ D. c$ ?; u2 U* C6 `- #define ADDR_USER_DATA 0x0801F800; C' S5 m0 n q( Y% e
- : k3 H( d) ?$ _* O% |9 A4 |
- HAL_FLASH_Unlock();" l! Y F: N; d% m# Z
- FLASH_PageErase(63);
8 p( x- j# e( B; | H% \ - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);+ C! ~$ }4 }$ g3 m- t9 m0 u
- HAL_FLASH_Lock();
+ I# W; _+ I6 `
% L2 @* ?9 b, \0 y. Q$ a2 e9 c5 v" q- if (ret != HAL_OK)& B7 f ^ u8 |
- {, C/ F9 V' @7 V1 Q7 q7 A+ a# G
- printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());
* m& L6 C0 l3 q - }
复制代码 " p* f: N! ^6 k ~ ]/ S3 e: L
. ~& g# R; h( ^
% x. V" O+ \" r0 L n! }4 S( h7 ~后来终于在community.st找到了答案:
7 Y3 r3 U0 a' S+ P+ t# a% P7 }
. {2 U# Z1 \" @% c, l8 \, G. {' [0 E3 w# H
* L0 o: z' T0 ?* a& c4 XSTM32G070 flash驱动代码! X1 t$ E) [6 S; i0 C0 O0 l
好了,话不多说,直接上最终的代码,亲测有效:
8 B; O2 T! s1 i* l5 V5 \+ Y/ b/ N" g+ @9 s `/ l7 F0 `
- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
0 |2 Q( }- C+ ?7 H* Q - {
" N2 ]) p4 ]& h* v+ X - HAL_StatusTypeDef ret = HAL_OK;; b/ T& d, w6 V A
- 5 n; Y6 g$ P2 e; w6 m# c
- HAL_FLASH_Unlock();# z& o( h, ?" R$ B
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
& t$ V, M4 `" ` - HAL_FLASH_Lock();: Y* d/ O! v1 d
: b: \2 h$ h$ u4 M, s: N- return ret;
+ p, W n$ ~, f% Q) F* J - }
5 n- [9 J. G$ X5 t7 w% a - 8 V4 ?& l* L' J* F8 x; U( f/ ?$ r
- void flash_page_erase(uint32_t page)
2 r" A/ F: L6 M - {1 s/ o$ N8 x/ u2 P
- HAL_StatusTypeDef test = HAL_FLASH_Unlock();3 f+ U2 b) D8 e" C
- D4 H5 ]+ Z1 N9 \: D( j9 m8 R- test = FLASH_WaitForLastOperation(1000); //1s timeout
% n( f3 K7 R( T, x: y4 V, Y3 m, F; _ - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);3 \' I& r2 M, O6 g8 K; q+ @: t! E
- FLASH_PageErase(page);
; l3 u4 i! }* ]9 J, D - test = FLASH_WaitForLastOperation(1000);
' @' Q% i( Z9 e0 Z1 G' }# s t2 ]2 K - CLEAR_BIT(FLASH->CR, FLASH_CR_PER);! F V c/ r5 _7 w6 _1 U% U
- T( I) L, C+ i+ g; T) f, n
- HAL_FLASH_Lock();3 a5 Y9 e: S7 d, s+ ]. [
- }
# M" X3 w/ o. c Z, }) o& F - & B1 r+ e* Y0 m, G2 n% G% r
- /* 调用上述两个函数即可实现flash的擦除和写入 */
* J1 q. T8 L' v F3 G4 _$ m, y - flash_page_erase(63);2 [9 A1 S+ l# t2 Z) N
- ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);
. H E9 f. Q0 l% |( h - . `2 ^/ V4 ^/ Z2 i
- /* 读取的话就简单了,直接使用地址即可 */2 P; ^' M# X. x& O9 C' Q
- uint32_t u_data1 = 0;& _7 L6 W( f' P1 |
- u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 ( \& U% K$ w" C* }, ]; ~
注意点8 C9 Z* S% u* p9 X
flash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:( Q, T0 P* T8 x- J+ \. x. k
* J; ^6 J& V3 r, b2 y- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)/ W- p( I4 }; Z7 s; u* d0 P. f# G/ N
- {
2 t7 K) m5 R" M- E - /* Set PG bit */+ @* a% ?! Y0 `8 ~. h/ e6 f( S
- SET_BIT(FLASH->CR, FLASH_CR_PG);
, ]/ d0 c9 u) m1 k! e9 S/ s - 0 I$ v& S; v9 M3 I0 ^7 M
- /* Program first word */
# \" y3 L- w4 `* h - *(uint32_t *)Address = (uint32_t)Data;
2 O/ u% c4 e: C/ G - , N0 U( _' Z V6 h0 O+ b1 Y& W
- /* Barrier to ensure programming is performed in 2 steps, in right order
- u9 X- x) ~6 i, ]) R$ A - (independently of compiler optimization behavior) */3 N: P, F) y$ y1 N- ]
- __ISB(); z1 D1 a* q/ x5 \9 ]7 I7 J7 Z
- 7 f, y7 p5 B6 q$ k$ S+ s, ?- t3 q
- /* Program second word */
+ P4 D5 ~! q+ {" X+ u; Q - *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);
5 N8 `* z3 m; Z+ b( _! i; c - }
复制代码
' r m7 g4 l# k. g: _该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。
% ]. [0 ~" g5 `$ J8 b0 N) ^ j. i! q$ @
4 q% k) D& Y7 R2 S# } |