STM32G070的flash读写问题% S; x! J( P, b# o# \ n4 J1 ^
STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。
1 u3 Z3 K R \4 \4 T7 G
! U1 _' F3 {- z; E1 W! Z
( K* c" R1 f, a; u" G, m/ \/ a- S a6 w& \9 ?
问题& c# w7 E: g8 h6 q& ?
开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
6 y$ d, T9 p7 G5 x! E- t$ a7 v- ~. X8 d$ B% I0 Y
- #define ADDR_USER_DATA 0x0801F800# G2 L4 c' [6 ~' l! `: j
) |* Y0 W, q( N- k; S& c; w) ~8 ]- HAL_FLASH_Unlock();
5 l, [3 n. m/ j. n8 C4 y - FLASH_PageErase(63);
# ?0 Z0 D- r2 v( y - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);. S7 r. a7 l. h) b- F
- HAL_FLASH_Lock();
4 I( |0 D1 J0 j" K1 ]1 o - & w9 e A) X @* J4 W+ |( x
- if (ret != HAL_OK)' k0 ?: M( F+ v' o- J4 P; I
- {4 Y# r5 n' E! l: H+ i9 T
- printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());& C' ~( \4 ?* Q, r. O4 z
- }
复制代码 , Y( l9 R; j2 o/ [8 l
; c& {. P" _9 t: X
8 z& C/ c2 V5 j1 g3 u1 L6 O后来终于在community.st找到了答案:2 \% I4 s( K3 k1 a5 X, g
* q" @) L6 E+ v4 }2 H6 u
2 [0 F; J7 z; P I o. e; S# L
: C4 c) N4 @; r: g8 `
STM32G070 flash驱动代码7 ^. ]% C' T# M5 J
好了,话不多说,直接上最终的代码,亲测有效:8 v6 _. h! z: p
" o+ {& w# c1 A$ L; H& L/ {- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
& K- J9 i- \! K1 b" `: |2 O+ W+ w+ T - {
+ s1 z9 ~3 O" G) U0 X4 o - HAL_StatusTypeDef ret = HAL_OK;
* {7 Y9 J* ~- z' {) Z0 M6 w
. f! k) ^% ^6 ?) o- HAL_FLASH_Unlock();
8 \; b* A) G y- J3 n7 j) q5 U - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
" k9 [/ N7 w } - HAL_FLASH_Lock();
6 `, I7 W O/ x' f& h) J - 2 S1 b- p: }6 l; E- O" r
- return ret;
3 f0 S$ B- m7 J1 U8 ^; o - }
8 W- x' @0 s& i' ^: l0 X/ M - 0 x, Y. P4 @3 q# B1 F: D
- void flash_page_erase(uint32_t page)
) a- e5 N. u/ c8 F - {
0 z0 s3 l9 n2 B4 Z0 m* r2 K; m# U& h - HAL_StatusTypeDef test = HAL_FLASH_Unlock();
9 Z& _8 \8 r' t7 L$ n) q3 \ - : a) D- J7 t% U, S$ i$ a
- test = FLASH_WaitForLastOperation(1000); //1s timeout
2 |) r0 G G, R7 k - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);! I' [1 b) ^0 R' S1 M2 H2 X$ T
- FLASH_PageErase(page);
Z. e2 _8 I7 K% z) e0 s - test = FLASH_WaitForLastOperation(1000);
% ~% G, C. W" h4 Y - CLEAR_BIT(FLASH->CR, FLASH_CR_PER);: D8 J3 a- t# I9 g) f3 U; t
- 2 P( J: L9 [3 j8 M5 Y+ `
- HAL_FLASH_Lock();
, e) y; |1 h- b% | - }
! c) `0 \' u" P# Q3 Z4 k - ; `# c+ @8 f) n' P8 M
- /* 调用上述两个函数即可实现flash的擦除和写入 */6 E: a( F V- p. |: R! d5 ~0 c
- flash_page_erase(63);
# [( ?4 k7 I9 O, E9 C" _7 R. } - ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);
7 K3 n1 W2 r# t+ {. d: s$ o - 8 d. w: y9 J# Y3 |
- /* 读取的话就简单了,直接使用地址即可 */
8 M4 |; q% h3 L2 I. t. ^2 L8 [ M8 |! c - uint32_t u_data1 = 0;
7 Z( W/ `" I" v3 v" f% ^- x1 @+ x - u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 . i. [8 Y {' v5 w C
注意点
, `& I+ d1 d7 }2 U7 e% Fflash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:; Y- N L6 w$ H9 t* V
, g8 ?$ r {6 e( K; \3 b) ~- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)( j6 G/ t6 J# ^% v- o6 K
- {
8 |; h# V% ]4 P( }' ` - /* Set PG bit */) Q' P' k: y; z3 q- v2 v# ?
- SET_BIT(FLASH->CR, FLASH_CR_PG);, x; ?% k4 j! S6 G- Y! o
- # d: r, O% G: ]- m
- /* Program first word */+ J9 c W7 m* Q, r5 E3 ?9 m
- *(uint32_t *)Address = (uint32_t)Data;
G( P, e7 O' W
$ s* X, |+ ^- E& r/ G- /* Barrier to ensure programming is performed in 2 steps, in right order
0 j$ e0 m" F0 i: Y R - (independently of compiler optimization behavior) */
+ {+ V5 z1 T6 c) l) |- C# [ - __ISB();+ J' H7 N4 g$ X( o9 X
/ I" B5 `" |3 {% b7 i! D- /* Program second word */0 N/ G6 b; Y! {; {4 @7 g' m
- *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);) j6 Q" M9 f+ X0 e6 [' y+ `
- }
复制代码 ( o; ]0 N+ N2 ~. L: ^, C
该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。* i' z8 x" i1 Y# ?3 R. p# h* I
1 i' S M1 }' @
; x/ T9 {1 \* J$ ]9 ]4 N
|