STM32G070的flash读写问题
# U3 p! D( ^$ }$ v: S2 \STM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。# T- c1 y, a; ~" b1 G, U
/ B% i" j5 _& C
+ E- A4 ?3 [$ w# h# y# j
" n* l- l; m4 O: r. M( X问题. b: M# D7 [: e/ K* `
开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:
3 T$ \0 X) u. f0 ]5 e# V. q: j: @1 k+ N5 _/ y; T4 j
- #define ADDR_USER_DATA 0x0801F800* O3 Z9 ]# v5 B: q1 ]$ u
- 3 I3 }2 _3 p2 i; K# p* \
- HAL_FLASH_Unlock();
+ z4 c/ D3 P! X4 f4 P1 C. C - FLASH_PageErase(63);4 u' K, j9 R4 T8 Y) o
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data);
3 n4 J4 B- a/ x. [% @0 `9 P - HAL_FLASH_Lock();2 Z3 j% S( z; n' G+ T0 j1 B2 A
( Z& M/ H) B4 z3 N$ z" T: M8 G- if (ret != HAL_OK)) P) v7 g8 t% r+ l& a: x
- {
/ C' T* l5 o- _) L' c - printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());
. R- k# A7 a; [3 }+ {4 v2 C - }
复制代码
! ?+ d' m& k8 n/ a! E; f) W' _
) k3 i# r6 r0 m' F
z0 b6 U9 K& f后来终于在community.st找到了答案:9 K' k+ @0 n* N/ w7 u; X
, R% A" J7 j4 O0 s7 o% z: _+ L7 X3 T4 ]8 z
( W# M2 A( p/ S( k! B0 ZSTM32G070 flash驱动代码
, Q2 L. f+ D6 i好了,话不多说,直接上最终的代码,亲测有效:8 b2 H( |9 B5 h9 N# q* x7 C5 |$ U
) y& Z/ d. G" O
- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
1 [0 S- c2 n0 W. N - {
" i c+ R- y+ q7 y - HAL_StatusTypeDef ret = HAL_OK;0 [; g/ w- [. g+ p+ x9 B8 P1 T
4 }& B% ?3 W: z- HAL_FLASH_Unlock();+ {+ O0 q. g# m& F% Y
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
, k+ `1 y5 q9 k1 t - HAL_FLASH_Lock();
* h1 A% r2 g4 Y7 L8 @; J+ `3 ?
( Y8 _+ u4 S2 }. m( ~- return ret;% ]; ], L! D' l6 N
- }" u+ B! a) j( e/ z" w
* M; e5 i$ x) c3 \) s" W- void flash_page_erase(uint32_t page)
3 d, M% s* r5 A+ A - {
' l4 _' d+ N$ o - HAL_StatusTypeDef test = HAL_FLASH_Unlock();
' t$ R7 C' P0 v# J - 8 K, J$ v: B- V, J. A* X2 _
- test = FLASH_WaitForLastOperation(1000); //1s timeout
! [) m' M! x7 [5 M" I - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR); M+ R f3 y! O+ R
- FLASH_PageErase(page);
0 ]3 \0 d3 F1 t' N9 g* q/ c" f - test = FLASH_WaitForLastOperation(1000);! K( A; N2 T7 U9 ~! c8 i/ e
- CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
) a* U# Y7 s0 g0 f6 Z* i" U( X5 w
3 D! c" k$ R, R( K, v7 D- HAL_FLASH_Lock();3 D, Z" h2 J' k# \, G1 y
- }
8 U4 @5 ]* m. [9 V% L* A; J* t - & s ]" _/ Q* q! J
- /* 调用上述两个函数即可实现flash的擦除和写入 */( K! F! l" c5 V, i% c
- flash_page_erase(63);
- w7 T. @. A* y1 `2 P% J - ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);
; x7 R; h; B) i9 j# v2 P- [2 N
' z* L0 Y7 X: c- w: v. M9 B$ l- /* 读取的话就简单了,直接使用地址即可 */9 S( N+ I9 t, v% Z* E5 d) u' x
- uint32_t u_data1 = 0;4 i* T @& X. [ U3 h1 K6 g! _
- u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 # v3 Q% a e9 ?' i
注意点
! |+ \5 |7 p5 ]* eflash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:
. s, W. [, s$ R! W1 R5 I# {- ! O0 F7 ^( ]: w/ w+ m+ D, E& G" q, _
- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
; H: ]3 }# l8 x/ _6 l - {
% l( B- X7 @& H; Y7 |/ c+ ^4 ~7 p - /* Set PG bit */
% p1 K' {7 s; I9 H6 s9 }& d ~ - SET_BIT(FLASH->CR, FLASH_CR_PG);4 d: t2 J. p# q d n+ l
- 1 l1 U) \: D8 @( ]
- /* Program first word */# s4 }- z: O! v
- *(uint32_t *)Address = (uint32_t)Data; q8 B' b+ t9 Y. _
2 ]* E2 C( H. Y8 N- /* Barrier to ensure programming is performed in 2 steps, in right order; u0 k3 P- }5 B, O7 k
- (independently of compiler optimization behavior) */
6 f" T* o9 d+ H6 O6 D$ x - __ISB();! c! u: K* i7 Z$ w8 ^! E H
# C1 {% V. r0 r6 L7 h" M- /* Program second word */
2 N G; i' B) c6 G2 y- X - *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);" ~6 P Z f c% }* P5 K5 a! @8 h5 d; A
- }
复制代码 2 g9 u$ x0 `1 I$ }
该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。
5 F. b' S) \$ w* y$ L" x( N" n( I% H6 C( Y# S1 I$ c
[4 }! ?- j& w
|