本帖最后由 creep 于 2018-1-9 16:18 编辑 ' J# ~, W% C8 c* f" z* D- I
9 f9 o% n2 e* z# L
STM32L的EEPROM支持字、半字和字节的读写操作。写操作之前自动擦除,如果写的数据为0,则只执行擦除操作。
6 z& ^( Y# |6 {$ O. p- i: [) B
, \0 P- e, H8 c7 V! n, f4 C6 p 使用STM32Cube库对自带的EEPROM进行操作,代码如下:
5 x3 D' a2 C1 a; _9 l2 C- / J& _, [) k; o& Q
- #define EPROM_WR_TYPE_BYTE ((UNS8)0x00)
2 s" `; }% |2 Z5 B - #define EPROM_WR_TYPE_HALF_WORD ((UNS8)0x01)! w( {- L$ R5 d" |: j' P0 k
- #define EPROM_WR_TYPE_WORD ((UNS8)0x02)* w; k1 @) E( `8 `
% t' F" O1 x4 E) f1 m. ~) W V- #define EPROM_TEST_ADDR (STM_EPROM_ADDR_BASE + 12)2 n) E2 o/ f5 u1 l' J
- #define EPROM_TESTE_ADDR (STM_EPROM_ADDR_BASE + 32)- n0 O! u6 R7 ]; W [5 f
- #define EPROM_TESTEE_ADDR (STM_EPROM_ADDR_BASE + 61)0 O. ]6 t% j- x! f3 {
- , w9 j& C* k; J
- //// Unlocks the data memory and FLASH_PECR register access
$ X2 {! q0 Y) _, h3 T/ {+ v# B0 G - //// ret :
& A6 V/ m( q& Q0 b8 L) h - //// OK = 0x00U,! x( U* i6 m1 |$ U& l8 ?9 \2 B
- //// ERROR = 0x01U,1 |/ E( J" Z; c5 `* n/ V0 p/ Q
- //// BUSY = 0x02U,
; m4 _! ^5 t; q) w/ G* a - //// TIMEOUT = 0x03U1 s l, p" s' f0 H5 X4 N
- UNS8 StmL0xxEpromUnlock(void). g* C+ v2 q, h) X7 E+ J5 p
- {2 H& ?( F3 `8 m
- UNS8 ret=0;
9 v# k5 L, Y3 r4 r -
4 F; |+ _( T6 b* o& y% p ~: I - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Unlock();9 g7 H7 f/ `4 I" f) I- E
- 7 C5 [% x4 N2 ?6 u' S3 V# E% z, J
- return ret;
. l9 a1 H/ q2 e3 g9 { - }
9 ^/ N9 n" o3 {5 h: w - 1 @ m/ L" U* h
- //// Locks the Data memory and FLASH_PECR register access
$ i$ y1 l& t6 e3 i - //// ret :
. O5 q% _' o- Z3 o8 ~ - //// OK = 0x00U,) M( e7 K: z$ C. K9 K: p# Q3 \. R
- //// ERROR = 0x01U,
, G8 c. D2 Z3 c N1 ?' K. \$ R0 \' E - //// BUSY = 0x02U,
# a% h/ i: k5 c/ A; r4 @- d - //// TIMEOUT = 0x03U
) D9 C( B: h1 W# P - UNS8 StmL0xxEpromLock(void)
8 g3 B" P5 t# ] - {! U* P( D* E( X, T. _6 L; {
- UNS8 ret=0;
- _+ ~4 S3 r! j* H; j -
3 p. z \% m1 H - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Lock();% v ?. C& h% s9 }9 E* K
-
8 n; D( F7 v* c m - return ret;/ A& Z# M4 y' r
- }9 O" d7 }8 a' q( j
- 0 o! }, \ [6 { C8 q
- //// Erase a word in data memory.- S! M8 i$ ~4 Q- N
- //// To correctly run this function, the @ref StmL0xxEpromUnlock() function
2 B: P+ j' ?5 f/ E. F6 l - //// must be called before.
& e$ ]9 n! r7 u: T8 e% Q! @4 r! ` - //// addr -- specifies the address to be erased.
. x# X# c$ K0 z) g - //// ret :
' ]8 a. u' Q/ J- ?3 m- v - //// OK = 0x00U,
+ h! r$ B( D$ \% v7 q' R - //// ERROR = 0x01U,% i2 A G: h) J
- //// BUSY = 0x02U,
. ^. o; B5 D5 `' p& w( ?+ }7 h; k - //// TIMEOUT = 0x03U
; [8 m+ G0 q" G- I7 ^0 c% x - UNS8 StmL0xxEpromWordErase(UNS32 addr)
5 m8 S2 s; K( |+ U - {
/ n: O) |) F; I6 _ - UNS8 ret=0;+ |. F% c5 w3 H% A2 y
- 4 K6 r' v; T! F& Z
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
7 F$ [# h, G5 A. o' c - {
$ ?. q" H1 L! G7 ?* n5 f. b$ s - return ret;
" O" U8 C" C! B) ] [/ ] - }0 {! Q; l; R1 i5 Z! K3 x
- & ~9 i) G5 l b3 ?' N
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Erase(addr);
- m- q, q; [9 o4 X6 l - * @! l7 Z# y3 b6 M9 U+ @5 M+ E
- return ret;" Z1 W9 q1 a& B$ r/ ]/ e
- }
1 Q ? ~/ X1 i. ^! N9 h - ; p" \8 m+ H6 D& I
- //// Program data at a specified address. f0 Z# Q6 e9 V) j
- //// type :
+ X' T8 g& B8 @ - //// Byte -- 0x00
5 Z2 e; i; q& N - //// HalfWord -- 0x01
! e S* I: \" Q, |9 z - //// Word -- 0x02; C3 l: Q1 e. g2 \, u( \ k& U
- //// addr -- specifies the address to be erased.
3 j$ b4 a {; ], X - //// ret :" z8 m/ {& u# M; D* s$ w
- //// OK = 0x00U,
7 N) M9 z5 k8 b! u/ W - //// ERROR = 0x01U,' S r' `. J3 C7 e9 o7 c3 d1 ?
- //// BUSY = 0x02U,
_3 k# ]2 F9 r6 ^- o - //// TIMEOUT = 0x03U
, r2 N S2 G+ v3 n5 ^9 w - UNS8 StmL0xxEpromSingleWrite(UNS8 type, UNS32 addr, UNS32 data); _/ j4 I( ]: g0 x* G6 D
- {$ U) a& U5 p" D( l) P8 B
- UNS8 ret=0;
. C3 @3 N& b+ K9 t( T) e' ]$ o) @7 y - , ~; J9 a5 k3 k6 |( l
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
6 W& X9 r7 p& H5 X. w2 ? - {/ d1 p5 r! w- C& j- a" W& M
- return ret;
- Y% E# v3 x, q$ ?1 a* w. a, J - }. l" x% f* m, P' o, E, n! E$ d
-
j* A; H6 z; q6 U+ Y - StmL0xxEpromUnlock();" j4 k' o, J: d- h7 t f" Q$ I
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Program((UNS32)type, addr, data); //// 库函数5 s( w8 u. ~, M" q
- StmL0xxEpromLock();
0 m r- n* C1 R. n& N) F -
3 k/ u. F3 E4 V- b - return ret;: \) [% c5 Q7 s
- }& T$ H% a W* I- V% z
# C }6 k! F' ], E- //// read a byte at a specified address6 V' W9 y% R2 |9 U2 `
- //// addr -- specifies the address to be erased.
. Y; @4 [0 u: d1 K/ d0 R& K - //// ret :, U! W+ f9 ^+ P+ v. ?1 ~
- //// OK = 0x00U,
2 {/ P3 O* a% `! ~ - //// ERROR = 0x01U,
! L0 }3 B& E6 T: k( C# x& ^ - //// BUSY = 0x02U,1 |0 l* X" _: \5 h
- //// TIMEOUT = 0x03U
) A j- C; ?( ~; w' d) H% e - void StmL0xxEpromSingleByteRead(UNS32 addr, UNS8 *data)% q1 {; O+ Z$ @
- {
5 _1 j- J* k ^ -
5 ~% h) L; t% }- J# N - if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
9 n" H: k: \1 K- P - {; t ?1 ~6 z% o. Q8 b/ q
- return ;4 \( ^( _+ s2 ]; @" a2 \' _
- }4 k i1 w6 v2 H) [/ L/ Z
-
& i' G3 y& u1 [* a - StmL0xxEpromUnlock();4 D; B# o/ W' v- R, _$ W
- *data = *(volatile uint8_t *)(addr);% }# l; G$ a* c( {! K) x
- StmL0xxEpromLock();
* l& P+ N/ n9 U* e - }
复制代码 测试代码如下:
0 k% j3 W7 h @6 O. L, h Z- void EpromTest(void): v. k1 N- I, J+ K
- {
, g* l3 @; L, |7 h - UNS8 tmp[8] = {1, 2, 3, 4, 5, 6, 7, 8};2 b8 `9 g( B' S
- UNS8 read[8] = {0}, num=0, time=1;
2 u2 v: A8 {3 {( v - 2 I. p/ t8 i! M4 M
- while(5>time)9 T$ i# d0 S: Q9 M
- {
7 v2 u4 e. V% y# [ - for (num=0; num<8; num++)( r9 N! K" y/ z+ @3 y
- {
5 P; k& \$ o! z! [ - tmp[num] *= time;
. v+ B( O d5 L - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_BYTE, EPROM_TEST_ADDR+num, (uint32_t)tmp[num]);* N( Q/ z) W/ j' L, a5 M2 f
- }- m4 ~! H' L6 `! P0 D3 `$ _' e# N
- % K5 l) t8 l4 ?2 `. m
- for (num=0; num<8; num++)2 Y8 s* P4 L- D2 y# J, T- O2 q
- {9 Z) z* L# v, _
- StmL0xxEpromSingleByteRead(EPROM_TEST_ADDR+num, &read[num]);
3 V% D( T+ D5 ~. y8 X& `& F- X - if (tmp[num]!=read[num])$ v) `8 G2 N9 N6 F
- {
$ T1 j5 p$ Q( U; ]' i& E. K - time = 10;
* R* e$ W" V8 V" E0 r0 K3 s1 h' ` - }% H, p# g2 n! Q. N: z/ Z
- }
* H& c" j: c! G j -
5 c! c7 \& T B9 J+ g - //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_HALF_WORD, EPROM_TESTEE_ADDR, *(uint16_t *)(&tmp[0])); //// 进入异常中断
% }9 k3 U2 S2 q9 V* n- ?5 U - //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTEE_ADDR, *(uint32_t *)(&tmp[0]));//// 进入异常中断# O m+ v0 h d
- StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR, *(uint32_t *)(&tmp[0]));
: ?2 a7 B# ~7 t% h8 P8 ^2 I/ v- V - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR+4, *(uint32_t *)(&tmp[4]));1 k! m% [ o/ f& b) a; l% W/ d/ j( R
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+0, (UNS32*)(&read[0]));. P& e" I% B; F
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+4, (UNS32*)(&read[4]));
8 v2 m. d: O7 L+ A# A - y) k5 I( Y4 t4 A
- time ++;
, \. G6 z5 A; [0 s1 [ - }
7 V6 v% H! x$ X - }
复制代码 | | ! W! X0 [! z# B) F
$ J2 A d: p; W* {4 t
2 f! l( U* G: R3 d2 U5 n \: z a2 X# E' e
2 ^3 F2 g H8 C* i ! N! k$ ~" [" H6 G8 M, M9 W* y. x
| 总结:" I C6 M9 W$ k7 N7 w5 H; r" N
1. 字节操作时,传入任何地址参数都可以,读写操作正常;& Y! a; c0 Z. `. a( W& l6 G
2. 但是当半字操作时,如果地址不是2对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
" n- X+ L: B* l7 x, s 3. 但是当字操作时,如果地址不是4对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;' z. } s+ z* T
8 j* W: X3 s0 d1 z% ^7 ~3 k- ? 调试发现调用HAL_FLASHEx_DATAEEPROM_Program函数时进入异常中断。
5 g$ M' c6 s& A0 V2 e/ ~ 原因是EEPROM在内存结构上实际是以字为单位的:# M4 d. ~1 ?1 u: D8 C f
, I' w* F" i; w: z. _
虽然可以进行字节、半字的参数,但是必须保证地址的对其方式——半字操作以2对齐,字操作以4对齐,否则会出错。) n, J7 ?0 i2 ~- ]4 U
. X) L9 y' B+ f/ v1 e% f9 v& _. E5 P4 r
!!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!* k9 N1 `- o) A# T" S( T7 S2 B; E" M3 ^3 B
; X) F+ H4 N O
6 L2 h5 ]! P9 [ N, m |
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html