STM32G070的flash读写问题# |) W4 t* V$ }/ y2 i: O
STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。, v9 B2 T/ i3 _( S$ @2 I9 x$ G+ U
# S" G' u1 m7 a1 ^1 \% N& N' @. @5 w$ Z7 g3 p( G
' p3 C$ U& B% a. D5 z问题
0 q! r# Y% [' M开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
" V9 ^0 M4 _1 u' P. g; }
5 x w/ G! N9 W6 G; h/ ]6 [" u* e- #define ADDR_USER_DATA 0x0801F800; {% Y! J& \* T2 j
2 e9 u7 ~5 i7 M. e( L# Y v8 \- HAL_FLASH_Unlock();
+ K: n/ _2 J2 v9 ` - FLASH_PageErase(63);5 w3 O: Y) f& u9 L
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);
) u, a( E8 Y5 j. Y* m/ {: y% H - HAL_FLASH_Lock();3 l6 e" v; n/ [3 g$ Y: x
- ' Z" h# V; S* U! W
- if (ret != HAL_OK)
* L8 Q+ L5 q, ]: w% l$ B- a- F( u: w - {. H$ Q6 Y, \: X8 ]
- printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());3 p& t$ O" u0 W
- }
复制代码 , M- p4 Y$ b+ b) ^
5 M) V. C4 _/ ]- ]
9 D# j* P2 ~# J Y% X
后来终于在community.st找到了答案: }/ s+ Y1 {' n. I% v
5 ^3 X4 a+ g+ l: l6 |( s6 Z9 g3 S1 c6 t; Y: n
5 E0 ~1 |, p9 R2 R- SSTM32G070 flash驱动代码1 d& e7 S4 F$ k! W) s$ M7 K
好了,话不多说,直接上最终的代码,亲测有效:4 x1 {9 h! D% L" F0 s& `0 U! P5 ?
, e# W% U; `9 W/ M
- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
/ O6 f% I1 q* a5 O5 N ^ w' o - {
E$ @( c$ _' a$ [ - HAL_StatusTypeDef ret = HAL_OK;
/ h0 ^1 u w4 \, k - 0 I4 C% c; K( a% k" F
- HAL_FLASH_Unlock();
% N& O; V' [+ w# K5 J" b' x. n - ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
1 s+ W5 b. f3 c1 ^, v$ g - HAL_FLASH_Lock();
' P0 S+ a) m/ A7 p: f1 g! i! f! l7 \ - 6 r& y R; z9 W q+ C
- return ret;/ U2 W; e# N! F, ?8 m$ E
- }
. z+ f P# H! {0 F" @
& m% ]; v. l# C2 `- void flash_page_erase(uint32_t page)+ P+ p3 \# J) b% ], C5 a) _
- {
. |- A: m- g5 a" t& U9 Y1 t# X - HAL_StatusTypeDef test = HAL_FLASH_Unlock();
8 J( ~# O" {+ L" A1 q
3 H d* G7 l u1 |5 q6 @& u4 V. h- test = FLASH_WaitForLastOperation(1000); //1s timeout
+ T& ~' @$ [1 L8 y4 H; M - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);3 O: [8 Z2 N( _; U& y+ }/ f9 W2 O
- FLASH_PageErase(page);
/ j# B- T3 J) |# j - test = FLASH_WaitForLastOperation(1000);
5 g4 m/ e0 H6 K# v6 E& ]7 l3 _ - CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
, w3 ^7 M( z3 w1 K s5 M
C+ @* U) [. \$ \( E; B* F$ D$ ~0 D- HAL_FLASH_Lock();' a8 ~- b z* _" M f- K% [( {
- }
1 L* e+ c B- P* c0 f
% \" J3 x4 s$ e+ {6 `- /* 调用上述两个函数即可实现flash的擦除和写入 */
% N- k o0 o3 ~ b2 h' ^: i+ o: k - flash_page_erase(63);% T, j3 ]5 p$ }" u; d4 y% c6 l
- ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);. w" o% j' m3 d- Y5 P
- 6 G& j2 S" n' X; L% v7 i
- /* 读取的话就简单了,直接使用地址即可 */! u' ?* c1 X. ]6 A5 P$ D9 w
- uint32_t u_data1 = 0;5 Q# ~/ y, a$ O; T- T) s3 p+ K# r
- u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码
P# f$ c: }3 {5 R% v; [; V注意点% e+ J6 ^7 [- C
flash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:
% v0 a: C/ X+ b( j
% }3 h2 E1 z7 P$ O- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
; [/ N( l' S: Z: h* d- j5 l5 w5 | - {
7 d% W4 ]; C2 b3 Y [9 H* P - /* Set PG bit */
6 f- i4 l7 f% O7 G+ y5 w5 g - SET_BIT(FLASH->CR, FLASH_CR_PG);! N" p/ Q4 ~" O) @
( l' P5 _7 e- s; w+ ?- /* Program first word */! A% z U4 v; M! e3 S
- *(uint32_t *)Address = (uint32_t)Data;: @3 z4 {& M2 b/ [$ T( n
! g+ l& \" |$ A- R. C4 |- /* Barrier to ensure programming is performed in 2 steps, in right order' }0 O4 D+ o8 M6 ?3 U
- (independently of compiler optimization behavior) */9 c( J# @7 C+ O3 l
- __ISB();
u5 y" Y3 E! D$ N) n1 q6 j
7 A: a4 R* |' r# q2 ^' U& k r- /* Program second word */% W3 i; S& x6 \4 Z" h$ H7 R, l+ Z
- *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);
. T% m/ L" S/ \" ^6 |8 r - }
复制代码 ! J9 p: ]8 v# V2 @2 }. v3 K9 O# g
该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。. n6 y4 `9 e, a2 o) j
/ n7 q+ K& C1 ^1 O4 ?
) c' w; b% L* N6 {. B. [) O |