本帖最后由 creep 于 2018-1-9 16:18 编辑
8 E" s# h6 J/ `; v3 n! ~: u7 l& z
STM32L的EEPROM支持字、半字和字节的读写操作。写操作之前自动擦除,如果写的数据为0,则只执行擦除操作。
0 R& a, O3 }# p% I% C1 S: {
+ ?& P( ?3 K+ {" d v" d 使用STM32Cube库对自带的EEPROM进行操作,代码如下:
# p9 r! k8 J$ }4 ]2 V- 3 B [; i* ~( `. ~2 @' P
- #define EPROM_WR_TYPE_BYTE ((UNS8)0x00)
9 _( ]! ?5 v7 Z+ j/ p9 [7 G - #define EPROM_WR_TYPE_HALF_WORD ((UNS8)0x01)+ L) ]7 V+ w: g3 z2 T/ I% [
- #define EPROM_WR_TYPE_WORD ((UNS8)0x02)
9 l) v; F0 x* Z6 K. e - 7 s! C! Q: r R( Q; `
- #define EPROM_TEST_ADDR (STM_EPROM_ADDR_BASE + 12)) p. f X- x p
- #define EPROM_TESTE_ADDR (STM_EPROM_ADDR_BASE + 32)
* S# i$ s& \8 J5 g - #define EPROM_TESTEE_ADDR (STM_EPROM_ADDR_BASE + 61)
* P1 g2 P& K- o- a i
: n; L0 I' q" E, c4 a6 q- //// Unlocks the data memory and FLASH_PECR register access1 |4 Q: L) P/ F+ L" J4 ]
- //// ret :& y3 L2 f6 _+ ~4 N4 X
- //// OK = 0x00U,
& f/ ? z0 T( r3 }4 }, ^ - //// ERROR = 0x01U,
" b3 w" Y6 W0 @+ Y7 R - //// BUSY = 0x02U,- D7 k0 T$ @1 N) s) T+ e
- //// TIMEOUT = 0x03U
% L2 o6 Z% V0 y" [9 A - UNS8 StmL0xxEpromUnlock(void)
0 C3 }' R" J7 M - {2 V: S G9 ?! {* r
- UNS8 ret=0;
; V- p- ?* s- K3 k5 K - 3 E$ [; s& H/ F5 @! n% z
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Unlock();5 I8 t8 O$ O3 J/ I1 P5 }$ D$ p
- . u8 a' k, C" R; R5 x2 F4 o I: q
- return ret;7 I4 V8 s4 ~, o$ y% a9 @6 U; P+ u9 w
- }
) X2 V G6 [4 P* ~
4 ?! \/ Z4 w4 V4 N) V$ g R- //// Locks the Data memory and FLASH_PECR register access! ^/ Z9 j9 u; ]7 _: O. Z# S. Z( f
- //// ret :. p: _$ A3 s( _! M
- //// OK = 0x00U,+ d7 y M" r0 p5 q5 K# ]
- //// ERROR = 0x01U,' u& l+ G9 M8 W8 A6 G2 e
- //// BUSY = 0x02U,/ K# p' }" K6 H/ m
- //// TIMEOUT = 0x03U5 r+ H5 q% Q6 j ]' B
- UNS8 StmL0xxEpromLock(void)
% f7 O" W/ \% C: v, y1 C% Q - {
# L) Q5 R: V0 j N' q2 ~3 q - UNS8 ret=0;
; t7 J6 c; l8 u# k -
$ m% A/ B, i$ i4 _4 I - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Lock();! b( m! M; D7 X) Q- H2 j
-
% x0 \; r# I) t - return ret;6 ?: h$ I' }& u7 Q: |$ p+ _
- }
6 W" y7 F" r6 b1 B, k" D4 T* q5 W - 3 N. M _" {/ `1 H# E, D3 p
- //// Erase a word in data memory.
& n0 \# j5 o4 I. z' E" g# l - //// To correctly run this function, the @ref StmL0xxEpromUnlock() function* C2 t- B% f V: @
- //// must be called before.
" T2 s% d: n3 B' W' P - //// addr -- specifies the address to be erased.
- ~# R4 j# Y' S q5 g - //// ret :
1 O- D+ A5 P" f - //// OK = 0x00U,# a9 g, A& L/ m7 p3 v# J
- //// ERROR = 0x01U,
. n& @0 D2 t! Y+ N' v* L1 v - //// BUSY = 0x02U,
4 Y0 F w0 X! S1 C - //// TIMEOUT = 0x03U7 w3 G$ j# {, a [/ C" y
- UNS8 StmL0xxEpromWordErase(UNS32 addr)
: J% i0 @+ Z% i4 ? - {! W, w8 F% u5 w' ^1 j
- UNS8 ret=0;
3 {( Q i) V9 k% |9 C4 [" N {7 v -
0 K2 z4 D$ n& z4 H - if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
9 F& K' a; F7 ~+ f) g9 u - {: ?( B. {+ x; Z9 Q
- return ret;# F9 `1 b5 w% h) B s
- }. p, l! w) U4 c m
- , f8 D1 P: }. V; s* q, w
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Erase(addr);: M, h9 Q/ W# M# Y" Z8 E
-
; n4 n2 X! r/ D& o8 W - return ret;
3 `- v/ W$ ^) O7 D - }
, O ]" O; \: z" C+ u - $ a- ^! O5 n# n, M4 W: n! l
- //// Program data at a specified address# H2 d' Y9 B8 [+ Z' V" T, I
- //// type :
+ u8 G: G& x! W% |- ]- H0 k - //// Byte -- 0x00
4 U7 \* K8 u! q- m( I4 b - //// HalfWord -- 0x010 n9 U$ ^+ q! F$ G0 {% ]
- //// Word -- 0x020 T1 x. z! U7 a7 H8 M. C
- //// addr -- specifies the address to be erased.
" S; V& M5 t- m& `2 |1 N! W5 ` - //// ret :
2 R* k6 |0 ~! H6 |9 H* _ - //// OK = 0x00U,; D1 R! S! a$ ?, x- f0 s8 G
- //// ERROR = 0x01U,0 M. f% ~- `" c' T3 v
- //// BUSY = 0x02U,7 h5 Y% w8 l# l% _
- //// TIMEOUT = 0x03U
- o( Q. `# m! ? C2 M - UNS8 StmL0xxEpromSingleWrite(UNS8 type, UNS32 addr, UNS32 data)1 E' ~" N' R! l4 G( B( V9 o0 F0 [
- {/ W2 _- B, m; t& K0 S
- UNS8 ret=0;
2 ?0 ?( Q4 {- Z% {. @9 x5 V+ ?1 W& t - ! P. v& E6 k% r
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )" ]! y5 s) E O
- {* n5 i3 v! [0 g
- return ret;
h( Y; T9 ]$ H6 @5 C2 j - }
3 j3 [6 N: e( L% R' d4 ] - 6 d- l$ \$ t6 K3 h3 _
- StmL0xxEpromUnlock();! ?$ `& o7 W/ b
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Program((UNS32)type, addr, data); //// 库函数
- W% z/ k* Z7 [4 ` - StmL0xxEpromLock();3 U& I0 b9 R# e# C: E& S. j t
- % y+ w. j/ R; B) y3 c. Y
- return ret;' e7 `& U1 O* @# E( |
- }
+ F8 I/ s+ V! @* ?1 X, ?
3 P9 Q1 b v% w/ Z# W) Q- //// read a byte at a specified address
6 C x" p' j R" z' l% a0 l0 g - //// addr -- specifies the address to be erased.6 _" H6 ^" E% W- Y2 g' u
- //// ret :
9 c, u. O, Z% a. c! o - //// OK = 0x00U,4 S: F3 |9 m) T' _- X
- //// ERROR = 0x01U,
7 z s+ Z' S) }' W+ c+ i - //// BUSY = 0x02U,2 Z+ T- j. A/ g$ Y% T0 ~
- //// TIMEOUT = 0x03U
/ r% i% A9 |& L+ l( ^; O% N - void StmL0xxEpromSingleByteRead(UNS32 addr, UNS8 *data)
8 {# l2 g/ {. R- A+ B/ r - {
* h" M6 [- ]' d, P' q7 Q* F0 p( | - . P) `6 {5 P/ R, _$ V
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )4 l$ _: I: ?# u3 T1 W! R* e
- {- S: Y$ T% U H
- return ;/ o, o9 r+ A) ~. L
- }' I6 J' g; @0 j5 X5 L7 Z; O
- 2 R' ?, l; J( x; A7 q2 T5 q; Z2 N
- StmL0xxEpromUnlock();
D, t! Q2 i6 S# @ - *data = *(volatile uint8_t *)(addr);1 E4 Y: y! ?4 A& g: N! ?" V- m
- StmL0xxEpromLock();
8 g- D1 ~* z! l3 H$ S- G5 Y - }
复制代码 测试代码如下:
3 A L. ]+ y* ]- void EpromTest(void)
+ x4 S: l. z1 e: R - {
: g \+ @% J* ?) v p" c - UNS8 tmp[8] = {1, 2, 3, 4, 5, 6, 7, 8};
3 y8 O0 o; v' X* q! i- l1 D+ p - UNS8 read[8] = {0}, num=0, time=1;' A$ Y0 g, W1 F8 v" Z7 D
-
" h9 k! l# N" P. k - while(5>time)
4 |5 k1 `2 G" L9 d. }9 ^: Y - {
1 R- J5 X3 e/ ?( r# _* L4 B - for (num=0; num<8; num++)# c; N" `0 C" I% B2 I
- {/ l& e, N. |& a. j) \7 G) b
- tmp[num] *= time;
4 G1 ^! Y: s, I. N; A3 B/ { - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_BYTE, EPROM_TEST_ADDR+num, (uint32_t)tmp[num]);. H- \/ W5 k# W% w6 l
- }. A4 d) Z7 x" v, B3 T/ l
-
6 c4 i2 Y, V* x3 Q. p$ ` - for (num=0; num<8; num++)3 X1 L3 g! ~: C+ O9 T* O
- {2 o' C. |- u; y, N- |
- StmL0xxEpromSingleByteRead(EPROM_TEST_ADDR+num, &read[num]); A6 |- q. ?! v
- if (tmp[num]!=read[num])+ _$ Z8 ^3 F. a3 b
- {
9 P' Z1 z, p3 z# d6 q( A - time = 10;
9 D) o+ ~! G3 Q3 S* ^5 v. Q - }8 \5 ?4 S5 u J% ^! l
- }, c! o' R9 H/ R% K. l0 K
- - ^1 M6 C# u5 Z, Q! r8 ~5 G
- //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_HALF_WORD, EPROM_TESTEE_ADDR, *(uint16_t *)(&tmp[0])); //// 进入异常中断1 {" d2 T0 l+ ~5 p9 U
- //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTEE_ADDR, *(uint32_t *)(&tmp[0]));//// 进入异常中断
/ Q& ~7 f& i3 B9 H - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR, *(uint32_t *)(&tmp[0]));
/ o- P# u+ o W. C N# H - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR+4, *(uint32_t *)(&tmp[4]));) ~8 L( |) Q/ v/ {
- StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+0, (UNS32*)(&read[0]));
- ~3 N! s% B- I8 ]6 H9 [, M* C - StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+4, (UNS32*)(&read[4]));" P3 Y v% [5 g& X7 R8 U! a6 S0 }
- 6 b' `" R! v# h3 u' R. [
- time ++;7 O0 o6 z: G) X3 E8 Q4 Y' @
- }
" F# L. v/ I& f) z9 q9 O- I0 K7 Z - }
复制代码 | | |
, i+ h& v& B3 P4 |* ~
( C* b, ^6 c* \8 I# p3 A
4 L7 i& m2 l3 }% u; d/ e+ x# ] k/ B, c
7 k9 a3 e% i- J2 v7 R) F1 V d% x, O( @0 W" T% [
| 总结:% i1 ?: J' Z- N* z3 n
1. 字节操作时,传入任何地址参数都可以,读写操作正常;2 u$ ~; W' L: ?; x. V3 Q
2. 但是当半字操作时,如果地址不是2对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
/ p+ A# B' q5 c: V 3. 但是当字操作时,如果地址不是4对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
* Z+ }* S$ C( n) J : k- A M5 X/ v$ t
调试发现调用HAL_FLASHEx_DATAEEPROM_Program函数时进入异常中断。5 ?: A0 D8 X* a* s1 R! q
原因是EEPROM在内存结构上实际是以字为单位的:
# S" k, s4 B- v i0 E$ Z
w9 @" G( E/ j4 d
虽然可以进行字节、半字的参数,但是必须保证地址的对其方式——半字操作以2对齐,字操作以4对齐,否则会出错。0 [7 {5 R, I9 D, n3 c( U
# L! Z# e& [7 w+ o: U. w0 }0 c+ m !!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!
+ v; N2 W/ Z) S* Y) L
; c: C7 F! M: f% K. ~3 C N1 y
|
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html