STM32G070的flash读写问题% @! k/ Y B: ?
STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。
/ r( m3 R7 g/ V8 W& K. L* f
9 W- Y8 m% l3 `* d( U* ^- p c! j+ T S
7 @1 F/ \( [ t问题1 y- f- k# e! O& K
开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
8 }, c' t0 u6 z$ r g
! V# k w e& a7 I3 I$ T4 C) E1 D- #define ADDR_USER_DATA 0x0801F800& [6 W8 d! m! T6 g4 z7 S4 r
' ?$ Q1 m% J7 x+ }4 U- HAL_FLASH_Unlock();
, ?* {% W6 d3 c9 l - FLASH_PageErase(63);
' w' m/ Y4 ^& E5 J0 u. u( E5 t3 r - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);
$ b' G- ?% y9 C - HAL_FLASH_Lock();$ q0 G& e: s1 r: v3 A' u$ [
. K; E+ c% n( b/ [9 G- if (ret != HAL_OK)
. V6 O3 w% d& I- E* W- ?1 ^ - {5 l) y' O% L3 c4 k# @& z+ Q
- printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());
# b! }7 Z. ~" M - }
复制代码
. M7 l& U* o5 I$ e7 g2 ` j# j0 d2 }
. \5 T# Q5 j& \) V' N, q i8 ^
: R9 D' j) s% z' j {后来终于在community.st找到了答案:3 L7 V1 ^* [" T; G c. o
$ l# N+ q) v; c+ m& ?5 J, O1 w8 Q
' o5 R# a# T& v: S& L& H1 U' M
5 R: k- G( X8 K: ^% h2 X3 p( h, d2 n3 p, GSTM32G070 flash驱动代码
1 Y2 J% i$ z- v! q' m, `好了,话不多说,直接上最终的代码,亲测有效:
/ K$ j4 c2 g$ N7 d3 d6 O+ _
& K4 @: A* j& Y7 w$ C- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
; q* A& Y3 n6 a8 @/ _: O - {, h# g: {7 b8 l1 x0 y2 K* I
- HAL_StatusTypeDef ret = HAL_OK;
2 p b. }: |( H6 g: G. T
1 V& Y( L. z ?- HAL_FLASH_Unlock();' }( {; n) _" J) g% G! I
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
& c9 g( O h% I" _' W3 N - HAL_FLASH_Lock();
& `, }7 K. b) v1 Y, r
" D* m* ~0 D7 a5 @- return ret;( U: R6 Y+ A! t1 P6 V, O) M' ?8 j
- }
, q8 ]& O0 V2 y+ M# }+ W& M* h - 6 H! [; {+ q$ }6 J0 l; r4 B
- void flash_page_erase(uint32_t page)8 X# j0 a1 B1 d* r& o3 J
- {* m# Z# I( f/ E( X
- HAL_StatusTypeDef test = HAL_FLASH_Unlock();
8 _# w/ b0 P; H - 4 U, @: `& B H
- test = FLASH_WaitForLastOperation(1000); //1s timeout
+ z- V* |3 M& g B; z - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);5 J) c6 B. i' j# S: d; F
- FLASH_PageErase(page);- L+ [) ~2 W7 }) \- ^9 x4 j* v9 U
- test = FLASH_WaitForLastOperation(1000);
: j3 G1 e5 d5 v; g) _' Q! l - CLEAR_BIT(FLASH->CR, FLASH_CR_PER);( L: v9 I0 @* n5 d: F
- , _3 F' n1 D) ]1 a
- HAL_FLASH_Lock();
9 B+ V8 P1 B5 E6 K - }, W+ e& T) p& g$ B! k
; I0 ?" S, t8 h$ }6 t1 \( h- /* 调用上述两个函数即可实现flash的擦除和写入 */7 {0 |1 X R9 P
- flash_page_erase(63);
4 ~! Y$ A$ A3 Y7 s1 D$ w - ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);, @1 l' ?$ v4 ~ S
* m& w ^ r3 N4 G" ?- /* 读取的话就简单了,直接使用地址即可 */4 Z# Q# e" t% J' M$ W
- uint32_t u_data1 = 0;
( p: w; `( p, E4 Y4 Z+ ^3 s6 u. t - u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 . o$ n5 C1 r4 n2 H8 Q. t
注意点
) D. f! j# ]# N$ l: Y3 ~$ ^' h7 y2 A' t# vflash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:$ g5 A, c1 U% w7 B* [) r( p
8 b% X P& A/ {8 `) q5 C; E, I P1 f- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)8 l+ c. R& V$ p$ G
- {, U9 L4 w! S `( a! G, I
- /* Set PG bit */9 w/ z# `- R" t! W2 [
- SET_BIT(FLASH->CR, FLASH_CR_PG);& K2 h/ t2 `3 j. p/ j6 |
- ) D# n6 D* E0 e b9 [" t
- /* Program first word */4 G9 L! ~" X# i- g4 A) t& |) ^0 c* Z6 {
- *(uint32_t *)Address = (uint32_t)Data;0 ^% @4 \6 J# K
- 0 j! ]4 r! Q# @. G/ s0 ~8 Y3 W; e
- /* Barrier to ensure programming is performed in 2 steps, in right order' }. u5 S1 q; S5 g$ J/ B
- (independently of compiler optimization behavior) */
: h- y; M) f# }9 V/ R4 ~- ^' e6 } - __ISB();6 V* s- d9 u Z- _$ ?7 r: A
6 Z& P/ u- M6 i- /* Program second word */
% S% u3 ], }: |3 _# f - *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);) d T! A. T" V8 s3 Q& o/ z; _: n
- }
复制代码
: m [% U, w6 u& c1 L' K& l该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。% p: O7 w' _4 H( g# o
/ d7 \* K& l: N; B w6 W
/ r9 K( [/ y0 \/ c+ L' b
|