STM32G070的flash读写问题
6 u9 }5 a1 {3 r/ P8 p# HSTM32G070xx的flash分布如下图,打算将Page 63用于保存用户数据。
1 [2 [: _6 |" z% t. J: z7 v, N* S! b3 f
2 L5 d+ C3 {- z6 k2 P& V0 M; X, |; c# b9 D6 S; Z( Y# J
问题
# V# y/ w6 `! c- v开始一直出现flash写入失败,从返回码来看是FLASH_FLAG_PGSERR,一直找不到原因,代码如下:6 m0 x" J @' D
- x& Z' _/ q5 w: V: m- #define ADDR_USER_DATA 0x0801F800
, b& T( ~6 T4 u7 M6 K) `# J - / c0 r' B' D. f* u2 R: D; Z
- HAL_FLASH_Unlock();
1 z2 @9 y y4 t3 l+ y( d q, c; S - FLASH_PageErase(63);+ n7 v' V# T6 F$ u7 [% U
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, ADDR_USER_DATA, (uint64_t)data); a+ j9 l( ?- \. e. ]: F R: {7 Q
- HAL_FLASH_Lock();
. Q' c' F) F7 o; l6 z+ O* ]- V) w - , Q* O! |% R4 w
- if (ret != HAL_OK)0 l8 E. P3 C! {! _, Q y0 s
- {
) J" l* ?/ h) l$ X& a - printf("\r\nuser data save failed, ret = %u, flash err = 0x%x", ret, HAL_FLASH_GetError());
, w' i K$ S* U7 `# `, W - }
复制代码 : I3 L, p A8 o' \" y$ M( \1 a
/ l+ a% D% u* Z. N7 H @$ d# G
9 Z$ G1 c5 x4 k9 A" h$ i
后来终于在community.st找到了答案:
$ X$ \4 c% L" G8 ?# M* a6 H5 V& U% T. D
2 n- N/ a+ r& ?3 _
( H5 j$ y( C5 B: Z1 z3 G2 wSTM32G070 flash驱动代码3 ]9 y' d4 q( F! p
好了,话不多说,直接上最终的代码,亲测有效:1 ]$ `7 X3 d9 m5 z
7 V4 T- g8 W: X2 b: X- HAL_StatusTypeDef flash_write(uint32_t address, uint64_t data)
+ r9 y: N# x, ]. n' J: G - {$ M. o0 d4 G/ A
- HAL_StatusTypeDef ret = HAL_OK;
0 N( K0 C8 p: s* U3 L, B - 6 h# u! E, v1 Y2 a! D/ B5 E1 E2 ^
- HAL_FLASH_Unlock();. ]: s7 ^$ y7 R( P# p9 k
- ret = HAL_FLASH_Program(TYPEPROGRAM_DOUBLEWORD, address , data);
- d: x& ~% D: E5 c) s4 Q- u - HAL_FLASH_Lock();
$ t$ K' g1 b9 I7 G- ^( Y
# ]$ C* \4 Z7 _6 D- H! r$ L1 X$ @- return ret;
$ ~2 H+ ~0 ^, s! p! M - }
: B$ s) o% x5 K, C: j' h - & |- K$ d& ~/ Y3 p& `& c
- void flash_page_erase(uint32_t page)2 j' b5 Q5 B$ x9 i6 a4 C
- {1 @ b2 x' L" A
- HAL_StatusTypeDef test = HAL_FLASH_Unlock();: P, B( t" N! a5 i2 B/ z
& T( p% B$ e2 O: w3 u- _- test = FLASH_WaitForLastOperation(1000); //1s timeout
, p$ |* o" a5 w, L& A4 [ - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
8 h, Z1 }% n; h( W# k0 Y7 A - FLASH_PageErase(page);
0 Y2 } |2 L% B5 d( @$ w0 y7 k ` - test = FLASH_WaitForLastOperation(1000);8 e) v' Y4 S, K1 Y
- CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
% [% R8 S. @6 }4 B - - N+ {& @/ @* O! l
- HAL_FLASH_Lock();
9 T$ ] U1 S' u - }! a3 P3 m$ m# X. F& O
- ) `" Q x7 X% f7 P2 k. v
- /* 调用上述两个函数即可实现flash的擦除和写入 */% X }. r" m" A$ a
- flash_page_erase(63);7 a0 U0 L T* V! M2 \ ^: q
- ret = flash_write(ADDR_USER_DATA, (uint32_t)u_data);3 U6 `* [7 }' p* I- [
5 h) z2 M9 H1 U. e7 I- /* 读取的话就简单了,直接使用地址即可 */
" u$ H \( C, ] @ - uint32_t u_data1 = 0;4 k: L5 e0 x$ r0 e
- u_data1 = *((uint32_t*)ADDR_USER_DATA);
复制代码 - F4 |$ V$ f% \- J0 i% L c! C
注意点
, R' d% L7 U L2 i8 c3 U# Cflash_write每次写入的是一个uint64_t类型的数据,其最终调用的函数为:
7 s$ m) R1 y5 }3 I& v2 }* H! v- & C! E6 f3 m7 U) c, ?4 Q0 B$ {
- static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
# f d5 g k$ s$ b - {6 |! {. o( P8 |( C @8 C% y1 L
- /* Set PG bit */
4 Q3 j4 Y' z$ b4 n2 E2 o) k! u( z - SET_BIT(FLASH->CR, FLASH_CR_PG);/ q) A% j9 q+ A' W! i7 D8 \' c
- 3 u: h; O% S' F- T" g
- /* Program first word */$ B$ C* [4 S. G3 Z4 D9 q* I
- *(uint32_t *)Address = (uint32_t)Data;
# Y6 P5 ]; u$ J" m# J! c - - {9 `( V( T" g) V( Z
- /* Barrier to ensure programming is performed in 2 steps, in right order
$ Q% j5 k5 V0 N. A& y0 `/ j - (independently of compiler optimization behavior) */
! w, S. p4 T3 t+ _ - __ISB();
! D5 N2 U5 e! ~. i4 v - 5 z3 @: }1 P6 |% \: Z# y7 H
- /* Program second word */
) c4 g8 l$ t& c/ v0 }* N - *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);# B) P) t) V& t; x4 _- X0 d m
- }
复制代码
. L3 q5 P- M# x" u8 y该函数每调用一次,其实是写入了2个word,所以在使用时需要注意Address的递增。0 t* ]5 l, R0 C6 Y: W% g
. |( J; X) a) A& Y; R6 E3 I6 ^* t% f0 i) G. Y/ i5 y) E+ E$ U
|