STM32G070的flash读写问题1 a9 n! L9 P$ U, L
STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。# ~; d. E3 W5 {' U! X
' {0 g9 Y$ _" _* p1 y! @7 K, q) @
3 R2 m) {, Q: s5 _2 K0 B( F2 B$ @8 _+ M
问题
/ u$ \. S& I0 ]/ n3 T; i- B& e3 C开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
+ I1 ^+ k5 `" S0 K. d; c" F2 v0 V0 e
- #define ADDR_USER_DATA 0x0801F800: s; A" S% s: c
- % Q6 a. I1 K: w: @( t' X1 ]
- HAL_FLASH_Unlock();8 P0 I$ I. m: M' P& R8 u
- FLASH_PageErase(63);( w- R- w9 h# x( z
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);9 ]' E5 U2 k2 H4 p
- HAL_FLASH_Lock();
* C9 ]7 L1 ?7 s$ j3 Y6 E - q" |3 |) u* m2 l) u4 c% e: ?
- if (ret != HAL_OK)
& C- o" [) p7 a0 d/ Z! i3 z - {
2 q1 y# G* E" v' Y/ l/ q - printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());
3 r& N2 H9 Q3 E0 o) a! e! S - }
复制代码
# z7 x+ L+ Q, }- T9 P# D9 E/ k( ]8 c% D7 h) a
' e6 b; {( r8 c后来终于在community.st找到了答案:
6 [' J0 C% X- ]0 x+ `' U
/ ^* I$ ]/ ~6 A$ Y) ]2 S J7 N& C
, o9 @ }3 h( u, h% q0 j
/ u5 A% I5 {3 S0 J2 H' n$ l% P+ s$ [STM32G070 flash驱动代码
; u. f9 U) R4 X- _" \好了,话不多说,直接上最终的代码,亲测有效:9 {4 v: i! ]; ~. j4 v( r
* r% V4 e: q; f( i4 z+ p! Y- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
) a) a% B' b0 R' p6 V' Y - {: ?4 O5 R9 Z# v! \, O8 O
- HAL_StatusTypeDef ret = HAL_OK;
- n6 D) ~* V6 ~5 z5 F& l0 C( O1 Z- c - # y! [: c. d8 E4 ?# r! g& ]1 n
- HAL_FLASH_Unlock();
( v) {6 {4 K* R0 v) }7 M# |9 F2 n - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);1 _5 ^" z6 z3 z
- HAL_FLASH_Lock();
% H, y, N/ f; Q, ]0 Z - 5 a) ^8 ]9 V; D- a7 o
- return ret;
: j( m* B6 ]- s7 C - }& M) B' O7 l b @2 q1 y3 s
- $ V2 l2 C" H, n, X/ U4 z e U
- void flash_page_erase(uint32_t page)# h+ B5 L5 o) [" t
- {" B" c. ^& ~( c
- HAL_StatusTypeDef test = HAL_FLASH_Unlock();
* E: B( c0 I9 [( q7 S3 |
* e; t& @ L0 p; G- test = FLASH_WaitForLastOperation(1000); //1s timeout
3 l T& M8 t% Q- l6 ?6 h% q; S - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
9 }- Z% z4 J8 c3 F ?0 U; Q1 i - FLASH_PageErase(page);: k3 `8 D* Y1 `* E5 \9 [. {5 D+ I
- test = FLASH_WaitForLastOperation(1000);8 W4 _1 S+ A, ~/ |
- CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
( q0 F' s/ Q$ G8 G1 k - 0 Z, } P' u6 \. P: I
- HAL_FLASH_Lock();
1 f0 v1 a5 G9 _ p* M: l# V1 I8 X! d0 p - }7 L' ^, O- S0 d* ~/ ~
- ( H4 W$ q' U* f/ {- P+ {
- /* 调用上述两个函数即可实现flash的擦除和写入 */
& X' h3 {! f8 Z2 H [- a - flash_page_erase(63);! ]8 s: n( O1 I. F7 L% c
- ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);
+ c: y S! w8 p2 ]) @9 k" z - ) c. \& t! o' D4 y- W9 ]
- /* 读取的话就简单了,直接使用地址即可 */
2 \) B7 R2 \; E) M3 R7 p - uint32_t u_data1 = 0;
v; o% `& Q: d ]3 q D% H - u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 3 A: s5 Q6 [2 D2 {
注意点
6 Q' K- K/ q4 d1 X3 g! xflash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:( }6 Z+ J7 G8 B1 ?1 O
- h( B* V5 B4 t( |& V$ n: f5 D& P9 K
- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
$ w& X% \' E* d - {
9 G4 O2 k% S' h' A0 `4 B0 E - /* Set PG bit */; Y7 c* H4 ~/ O7 g
- SET_BIT(FLASH->CR, FLASH_CR_PG); d2 X& T3 o W% N# p$ J0 n+ R7 q
$ e! F/ {8 ]% g6 l f- /* Program first word */& H6 k# o/ ~8 r( {/ v
- *(uint32_t *)Address = (uint32_t)Data;
9 ~6 c& {+ Z$ B6 y
4 q; ~1 ^+ n$ i: F+ m+ X- /* Barrier to ensure programming is performed in 2 steps, in right order' o* _$ h3 k7 B! U
- (independently of compiler optimization behavior) */; W$ M" q' g% ^7 ^/ l! o# B' ~- Y
- __ISB();* ^; B8 O# g- \+ t' q. K ^. i' K
- [# U. m. `2 w' U7 }- /* Program second word */* s# h( D3 Y/ Y" k3 c4 T4 h
- *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);
, `6 g: Z! o8 v" y6 h - }
复制代码 0 I+ s0 @' p4 d: n% V
该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。* z# ]: W+ A; T3 r8 }
7 a% Q# q( w; S5 i) }, a3 x- Z* |7 p9 A# k& S9 G, `) m, ~1 p" n' t
|