本帖最后由 creep 于 2018-1-9 16:18 编辑 ; B m: l0 W. d/ N$ [
( Y# i2 @" U2 c: g
STM32L的EEPROM支持字、半字和字节的读写操作。写操作之前自动擦除,如果写的数据为0,则只执行擦除操作。4 i% j( w# Q3 z2 D& T z2 O" @
& k0 V) H& J, j _, `5 Q 使用STM32Cube库对自带的EEPROM进行操作,代码如下:
3 ~; F) }3 v3 \* j1 M
2 R- ?3 k9 @* E9 L* H- #define EPROM_WR_TYPE_BYTE ((UNS8)0x00)
; N: X. v- b7 a1 H% h - #define EPROM_WR_TYPE_HALF_WORD ((UNS8)0x01)
2 v4 y/ g4 s. j# l) `/ e \ - #define EPROM_WR_TYPE_WORD ((UNS8)0x02)
# i) x# K- e2 _% Z; B& D& s
2 ^* ^) U3 G8 d3 t& ~3 o0 ~- #define EPROM_TEST_ADDR (STM_EPROM_ADDR_BASE + 12)
e: R; p& M g9 H" u" u - #define EPROM_TESTE_ADDR (STM_EPROM_ADDR_BASE + 32)
2 @0 c) i$ Y5 v& d T2 ` - #define EPROM_TESTEE_ADDR (STM_EPROM_ADDR_BASE + 61)# F- a( Q/ h/ K1 y
* B4 O) U) Q+ L0 e j, V9 [2 S- //// Unlocks the data memory and FLASH_PECR register access+ E7 Z' i- M* i5 T! x- g: M
- //// ret :" s; P2 [1 w1 z' W" K4 ?
- //// OK = 0x00U,
a S: J3 u7 w, E/ S/ M - //// ERROR = 0x01U," b! o: ~, p: i% f
- //// BUSY = 0x02U,# Z7 D3 J3 N0 q, K
- //// TIMEOUT = 0x03U
2 u8 p8 e) O2 L - UNS8 StmL0xxEpromUnlock(void)2 {- R/ U% D6 ]
- {
4 h P1 t+ G' F: u4 g% o4 | - UNS8 ret=0;/ G( E: d2 P5 m% Z
- * Q r y6 \; Q4 } h
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Unlock();
0 S# m4 f0 y! L# @ -
# C- P3 v5 I3 l% }/ @ - return ret;, x- Z1 |7 D/ s& C1 B3 O0 J
- }, S7 Z- i0 A# i. I2 A3 h+ Q4 Y4 T
- : T$ K# {8 v7 s0 }: \- }
- //// Locks the Data memory and FLASH_PECR register access; I6 u2 M5 W/ d; K! a+ M/ o
- //// ret :- K" u1 x( I2 ^
- //// OK = 0x00U,; d- s9 t* `; _/ u% V4 n( X+ T4 f% g
- //// ERROR = 0x01U,
# a: X& @4 J& G( M5 s' e - //// BUSY = 0x02U,( {0 k: C" n7 j- u2 p# Z
- //// TIMEOUT = 0x03U) t, D0 p; O* D+ i
- UNS8 StmL0xxEpromLock(void), P9 A" a1 `2 O9 {
- {
% h1 c) u; X7 Q9 t, q) U - UNS8 ret=0;
" g8 h, s/ N) N" h" f o - 6 g) D6 q& x9 v0 w+ A& g
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Lock();
, [- k# |+ b/ |2 T; Q+ } -
7 b2 e' D) [' t - return ret;9 a6 l! V: w/ Q' D% D
- }
5 a Y1 b* K) U1 T% J) x3 Y/ K - $ M) X5 O4 {. E6 G6 [
- //// Erase a word in data memory.
2 c& u/ J+ R9 H+ F; r: ~; w - //// To correctly run this function, the @ref StmL0xxEpromUnlock() function# u, W, [8 u- N2 h7 T
- //// must be called before.% n6 V; u- m4 E6 @8 t" l4 e
- //// addr -- specifies the address to be erased.
( l6 U( H3 M& { - //// ret :
, \" N, [. U* l" |" O5 ^ - //// OK = 0x00U,' w7 q6 a4 r) G: O
- //// ERROR = 0x01U,
& u2 u h: o q$ ]( X; O/ F7 o - //// BUSY = 0x02U,
1 {( p$ L" ~7 N0 F- P - //// TIMEOUT = 0x03U: G/ q" f$ W; a- `# ^
- UNS8 StmL0xxEpromWordErase(UNS32 addr)( e7 z) z$ S4 l6 N
- {
. z( e) O2 I) E - UNS8 ret=0;% l& i F" i/ ?' H2 G
- v% z* U9 r( K5 q
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
+ f/ l1 Y: f; a% U - {1 u" Q4 O! R9 W5 l
- return ret;1 N& _0 ^, ~' Y k& P
- }. B* `3 S6 Y+ G. {4 _( x
-
2 a& N ^6 @# l# p# G9 r9 I( l6 G - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Erase(addr);* R% B7 R: h# H/ j# Y: X5 Q8 M
- * y6 X/ Q' ^( ^' h- k
- return ret;
7 ?) A5 i9 u& Q7 m7 D - }0 ]$ `* Y/ {' J0 z. K, r
- & X. v! y& ~' R5 ~: s
- //// Program data at a specified address: R4 p+ ~% B& T1 O- Z
- //// type :/ }. R* A+ F8 m& j. d: w$ |) O
- //// Byte -- 0x00+ Q3 J6 H" [# \. t* f
- //// HalfWord -- 0x010 ?) ~; U p: U
- //// Word -- 0x02- k, t! T9 k( P
- //// addr -- specifies the address to be erased., w; k& U& `+ M* b; I9 L- O9 V
- //// ret :
" O4 N' |' Q. P I& G3 j - //// OK = 0x00U,( \) a8 M' o; l9 J5 V; v1 [
- //// ERROR = 0x01U,, s* b; c) P# T1 V& c7 z* R1 T* |7 N
- //// BUSY = 0x02U,& | W. l3 C1 n% o3 h4 h
- //// TIMEOUT = 0x03U
3 k( U# k1 Q9 r Z% X - UNS8 StmL0xxEpromSingleWrite(UNS8 type, UNS32 addr, UNS32 data)9 _- d- w+ _* }8 L
- {- C# [8 v3 d, n D$ }
- UNS8 ret=0;' S; k( A- H+ [7 E0 p7 B% M
- : b+ f. M" f; e9 a
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )2 ]+ D9 v4 W N
- {! d- r4 I. Z8 W8 z1 p: x
- return ret;
5 Z+ q# u# U; ?: f) o7 P+ d4 @ - }
. e5 b9 C3 [" @% k - * m! W! _# [: U. l4 _
- StmL0xxEpromUnlock();
3 Z5 i" B5 w' m a2 T6 W6 x+ V7 v9 b) q - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Program((UNS32)type, addr, data); //// 库函数
) [4 d2 j4 O! L6 H b5 a' G" }2 ? - StmL0xxEpromLock();$ N4 Q3 F2 Q' B
- 7 }7 i# z; @" J1 z0 K h' b* V- Z- F
- return ret;0 n2 g: w2 { R' E7 p
- }
/ U7 M5 ^! e* z1 Z3 T
4 H P2 m" I( e) A) x- //// read a byte at a specified address$ R/ `4 k- c2 R& c# J, y
- //// addr -- specifies the address to be erased.
# ]4 f; J, z/ O) Q" P% C - //// ret :
8 T# h6 F& p% ]$ m5 [1 ]% n - //// OK = 0x00U,0 [" M+ p! |( t5 p K
- //// ERROR = 0x01U,4 b" l! H5 c2 p8 _& S6 Q
- //// BUSY = 0x02U,
X$ @5 A/ \4 Z3 d - //// TIMEOUT = 0x03U
) Q6 D3 H" w0 K1 [' V* q - void StmL0xxEpromSingleByteRead(UNS32 addr, UNS8 *data)
3 N e; O* J. M& q/ K - {9 `# B0 I* h: s" g& P! ^& `( j
- , L$ n0 m# J% `6 D
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
8 R: g+ M# Z; l8 j - {) i! u- ]: y: ~' Q! ~5 y6 F; z7 ]
- return ;9 q/ f* Y7 }8 d; W( Z
- }0 W! N' q# Q0 \: F9 L
-
8 J% A t, b5 z - StmL0xxEpromUnlock();
) |* \) Y7 \% c- A! a9 t. S( Z - *data = *(volatile uint8_t *)(addr);4 y9 l H; t6 F0 T: R1 m
- StmL0xxEpromLock();
' j1 t4 [$ K8 G/ h/ G; } - }
复制代码 测试代码如下:8 J6 E: W* Q$ f& C' x8 i! ^' o
- void EpromTest(void)3 G. i0 r7 D m6 S& C) n: k
- {
; K4 E# h6 W% _' y# c9 X8 J E - UNS8 tmp[8] = {1, 2, 3, 4, 5, 6, 7, 8};
! q$ h' E; d6 ]# I/ r - UNS8 read[8] = {0}, num=0, time=1; t3 u2 k- V( D/ o# y3 H
- ! _ Z4 q3 o% Y4 V4 G d! N ~$ r5 a
- while(5>time)2 _6 {" g& Z' D. g
- {
( \8 C4 C! y2 W - for (num=0; num<8; num++)
: {( P4 h1 T& C \0 o - {
' Z5 x" w. f; K - tmp[num] *= time;
8 s1 K2 g9 S5 V8 n1 b - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_BYTE, EPROM_TEST_ADDR+num, (uint32_t)tmp[num]);9 O; D* m, ]6 q7 c% a }
- }% u2 h+ [+ f1 b" U) ~# d
-
; ]( g1 p& ^( x - for (num=0; num<8; num++)& Q7 g0 K# s* T7 Z
- {- F$ l6 d6 Y# c+ M! Q
- StmL0xxEpromSingleByteRead(EPROM_TEST_ADDR+num, &read[num]);
2 o, D7 I4 Z/ @9 S' \# j) b - if (tmp[num]!=read[num])
0 P2 ~( |7 H3 a' l* b - {! t; o3 E# h: m: C
- time = 10;
( C( A1 e+ V/ e6 Q - }' s6 K* _8 h# O7 o
- }/ z. E. N" ^7 T$ W H2 m9 r9 o. N
-
7 r7 { [$ [/ |# q# h - //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_HALF_WORD, EPROM_TESTEE_ADDR, *(uint16_t *)(&tmp[0])); //// 进入异常中断
8 h7 B* T! K1 ]- n" Y- O7 t" a - //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTEE_ADDR, *(uint32_t *)(&tmp[0]));//// 进入异常中断
7 J( T( }) x k% `0 a4 ~ - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR, *(uint32_t *)(&tmp[0]));
P* G8 k) y6 x - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR+4, *(uint32_t *)(&tmp[4]));4 Q7 |/ l/ t. E! V) o+ \
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+0, (UNS32*)(&read[0]));
0 H0 |) o$ m a. S6 `" v; E, K; V - StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+4, (UNS32*)(&read[4]));' j) k L) |; ?1 \- k' d
- ! _& i. H4 L3 S: [" L
- time ++;
. ~+ {+ l% o- u# S- `$ g1 |- X6 K* C - }7 S0 D+ `( G+ @% G4 N, G6 E0 x
- }
复制代码 | | ! O C& |4 k4 U; V6 G
* R. g! B5 `+ u; i' A
: Q* G5 @( |8 c! B7 C9 G5 O
1 _5 L# r! x* X% G# L! A
/ P' b4 k$ T0 K+ W9 m/ k 3 k! G ~6 s4 t/ r f
| 总结:% n, v8 {0 `0 S6 K+ O
1. 字节操作时,传入任何地址参数都可以,读写操作正常;0 d+ Q- @6 R" I( K7 ?7 N" O7 d
2. 但是当半字操作时,如果地址不是2对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;. Q- Q0 p0 w8 T- G5 ?$ N" _
3. 但是当字操作时,如果地址不是4对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;+ @' [' u! O; V3 o
; g; y1 K( x$ K9 S" C6 p 调试发现调用HAL_FLASHEx_DATAEEPROM_Program函数时进入异常中断。- w7 J. b3 g7 T: H# @
原因是EEPROM在内存结构上实际是以字为单位的:& Q. q4 ]3 l% T5 O+ Y, }* q- c+ @1 b
9 }' ^- \# X2 \( B6 P( v- W' H
虽然可以进行字节、半字的参数,但是必须保证地址的对其方式——半字操作以2对齐,字操作以4对齐,否则会出错。
! F5 r3 [' H/ f* t# R
! Q0 V. x5 f% \' ^' ?9 { !!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!
3 Y {+ J; U7 j; [1 W' Y5 N6 B! N" N! [2 e# n7 i; g9 A9 p
# f' v, K/ B6 s/ ]% s: f |
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html