本帖最后由 creep 于 2018-1-9 16:18 编辑 2 e1 F( J8 A1 Y, V
% J$ M W7 w& {3 M/ D' X( E STM32L的EEPROM支持字、半字和字节的读写操作。写操作之前自动擦除,如果写的数据为0,则只执行擦除操作。
9 d, w1 _# M( s' z! ^
! m' u3 D- \; x( V4 R2 ^ 使用STM32Cube库对自带的EEPROM进行操作,代码如下:0 N5 y/ U. X; E( R' M9 B4 Y
* y" t, P+ Z g2 \+ P# b, a' ?: }- #define EPROM_WR_TYPE_BYTE ((UNS8)0x00)
$ }7 A8 T* }8 d6 N1 O. n+ Q3 R - #define EPROM_WR_TYPE_HALF_WORD ((UNS8)0x01)
, V4 D( U6 W+ `6 P - #define EPROM_WR_TYPE_WORD ((UNS8)0x02)( @0 A. ?4 s% n4 ]' N) _
! Q! W8 C# C' d! x& N- e& E6 y- #define EPROM_TEST_ADDR (STM_EPROM_ADDR_BASE + 12)
; M; G0 Y8 `) L7 r7 W' J - #define EPROM_TESTE_ADDR (STM_EPROM_ADDR_BASE + 32)
3 f# y$ T( S( o: m' O$ J - #define EPROM_TESTEE_ADDR (STM_EPROM_ADDR_BASE + 61)
' A5 E+ l: \; N
9 k. j# J5 O% ^3 r( Q! ?# q- //// Unlocks the data memory and FLASH_PECR register access
3 W0 ~% f8 T! y/ \1 Z" q% c - //// ret :' e6 e/ F( H$ g7 W# ~+ n
- //// OK = 0x00U,
' z% A! u& M2 w# P, h - //// ERROR = 0x01U,
, x7 w' s9 X9 ^3 f$ Y" \' e0 z, J. H5 |& @ - //// BUSY = 0x02U,
! Q+ U1 w; A6 R0 u! x! J' D - //// TIMEOUT = 0x03U
: u8 X I! A) ?3 R. r3 E. F3 l& j - UNS8 StmL0xxEpromUnlock(void)
; P( w& v; Q# N+ L. [ - {
- g6 J* J& n- w9 K# z* x - UNS8 ret=0;
( _2 W. ~; Y7 H0 ~9 ~8 W. S - ( R( P. O9 E. n4 {1 B
- ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Unlock();5 C9 I- J/ `) o/ F( e9 G4 x
- & {& r5 G+ X" w
- return ret;' Z/ \6 J: [: f
- }
" t$ P# u. C0 e f. A7 b
5 w8 ?5 T9 H8 {6 z- //// Locks the Data memory and FLASH_PECR register access
4 j- G0 t9 g& D1 E; g - //// ret :7 Z @- a4 j7 C& V: B
- //// OK = 0x00U,
/ }. ^. N1 u, X - //// ERROR = 0x01U,( b5 A6 t2 l7 S) J) y' w- F0 Z
- //// BUSY = 0x02U,
4 i/ \2 k# C1 x$ I, h* b - //// TIMEOUT = 0x03U
' g9 `% t4 j6 f0 V4 v, S- s - UNS8 StmL0xxEpromLock(void)# v, A0 {. \$ ^4 x- a
- {
% Y: X8 M7 W: m - UNS8 ret=0;
2 j7 c1 }- B; t* v: \ -
9 Z" y% j) P! G - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Lock();
# X& G# s. [" z7 k) D, B - 1 g. \9 E/ R4 B+ ]4 ~' t' a
- return ret;: d& W; i2 {3 N$ c! c, a/ T( Y5 o
- }
7 m8 s4 O ]6 R/ J. Q9 D, o
0 G3 J G: s7 V* q5 w- //// Erase a word in data memory.% T$ w! E' m) _5 M4 g' f
- //// To correctly run this function, the @ref StmL0xxEpromUnlock() function
; W) {; A- h1 E; V: X: i- r - //// must be called before.
* b$ U S) i1 C' C7 N! K4 l* w2 c" X - //// addr -- specifies the address to be erased.! c" m5 m& k6 Y6 w, s) |# T
- //// ret :8 n$ l9 @4 m* Q# d
- //// OK = 0x00U,/ i8 g4 H k/ D1 J$ x
- //// ERROR = 0x01U,# V" m5 Z* b& p7 r
- //// BUSY = 0x02U,# X& y, o1 M7 H1 h! i
- //// TIMEOUT = 0x03U: q+ Y6 h3 ?1 D3 e# e% ^8 l/ q
- UNS8 StmL0xxEpromWordErase(UNS32 addr)" r4 K3 v8 [$ e. Z, a
- {+ V8 T! W1 g( v4 h2 O) K
- UNS8 ret=0;
: D' @) x- K+ ?4 k# ]# |7 x - ; w# f' @/ Z( H+ u
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )- f4 ~6 Y0 O' G/ z9 S' h0 k$ c
- {
, C) p$ q& s1 ^7 |1 f! Q( B' S* ? - return ret;
6 W8 A) ]( Q% m5 }& ^0 u8 M% ~# z/ Z8 h, C - }) Z' a/ P i6 h) r! ^4 @' I- l
-
: H! |5 F( W& l/ \! s" o8 [ - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Erase(addr);
4 ~/ s* E1 A6 S% Y -
5 l: j9 E) Q/ l# r1 ~! e2 ~ - return ret;8 y6 h$ G# o3 f' B% P; m; d' D3 t q
- }8 p! h3 f$ {& M0 L: b
* ?( T; n' V, g: U5 t8 n- t. r: H( m- //// Program data at a specified address7 T. T! t+ J" X2 U: S: L
- //// type :* a# H) K! F) W( z3 _
- //// Byte -- 0x00* x6 u# t7 L6 V
- //// HalfWord -- 0x01
. L# D6 W) x% I$ `" x! x# N5 ] - //// Word -- 0x02# p* m+ l- C- }* i; z# s
- //// addr -- specifies the address to be erased.
4 F" W+ Y# B& c$ U6 A# V - //// ret :: o \" Q8 w9 Y" S, V
- //// OK = 0x00U,
* x% S# l7 u$ s/ a Y M' ^ - //// ERROR = 0x01U,
) l, ^9 F3 O. M - //// BUSY = 0x02U,
3 \1 `! _) Q! U g - //// TIMEOUT = 0x03U
7 F D! u9 }" f( L1 ] - UNS8 StmL0xxEpromSingleWrite(UNS8 type, UNS32 addr, UNS32 data)
* q% l7 d$ U) j! O0 O - {
: I* Q4 M4 o5 o4 w0 f' Y - UNS8 ret=0;; B& T* J2 L' f' D
-
* w7 X+ d- z8 Z8 M - if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )6 `- e- ]# J/ x1 `$ r' ]( d
- {$ t8 Y# { }8 m2 ]4 M
- return ret;9 p' k, p5 \1 ^3 a L
- }! A9 c/ Y; ? n6 a% o( K
- - P5 p. L$ W8 j. r$ R4 |2 C0 `
- StmL0xxEpromUnlock();
8 P) m* i' d) o' B0 }" S - ret = (UNS8)HAL_FLASHEx_DATAEEPROM_Program((UNS32)type, addr, data); //// 库函数
3 T0 r$ Z$ N& P( r- d/ q$ f - StmL0xxEpromLock();
% J% I q/ s6 `, w$ ^ -
" ?6 l0 w/ z/ U9 o( w' ]* L - return ret; V5 _) r7 U0 T5 i% c$ w |
- }
! v# x. k" t9 V, A7 W: e" R
9 B1 {. Y9 N( l( h, Y- //// read a byte at a specified address
( Y |5 o5 h% h9 | - //// addr -- specifies the address to be erased.- v3 a' I& q; K5 B* A
- //// ret :
0 B) z2 S: T7 G! ^ - //// OK = 0x00U,
' T" W2 l: n8 h% B - //// ERROR = 0x01U,- I$ }: N7 v1 ?7 P8 H2 K( h
- //// BUSY = 0x02U,
6 k4 Y: L1 ]3 S2 Z - //// TIMEOUT = 0x03U
$ I+ S, p% _ e2 B$ z3 q. O5 l8 t - void StmL0xxEpromSingleByteRead(UNS32 addr, UNS8 *data)
3 k. y" b4 B4 @; Q" y - {
5 S) {; z4 j- U I* i - # y% ?$ a" j6 f! Q& c f
- if ( (STM_EPROM_ADDR_BASE>addr) || (STM_EPROM_ADDR_END<addr) )
3 w" q5 P: Q6 { - {1 ^7 g. B( O9 d0 B9 u" e" R2 v7 J6 [
- return ;2 z) k h \4 s h" J1 i
- }+ K. n. t+ u. ^+ S7 {7 y5 J" o: d* P
- % |5 |" }$ b& \$ E& x1 K% u
- StmL0xxEpromUnlock();. _2 A- \ \8 j" ^: G
- *data = *(volatile uint8_t *)(addr);
& d( F6 v* n6 F - StmL0xxEpromLock();
! y$ U# A! D3 t, K7 @ - }
复制代码 测试代码如下:. t7 z) U5 G j
- void EpromTest(void)
1 X5 \% @! r. x3 ^ - {! {1 X& C; y; {/ W# F3 O: u
- UNS8 tmp[8] = {1, 2, 3, 4, 5, 6, 7, 8};( d0 L9 u9 Y% Y. z" e$ b
- UNS8 read[8] = {0}, num=0, time=1;
* m9 y* a r& t- k' { - * K% e h+ T/ o* J
- while(5>time)6 f6 m) Q& o0 x h. H, k
- {
' P* A5 ]/ X" u; E2 ]" S: r - for (num=0; num<8; num++)
: k: c; E5 A4 P! T7 a - {
+ T! x& x' |8 I0 H! z, l) U" m+ ~ - tmp[num] *= time;# D, d2 M2 I6 @/ r7 p0 {1 q
- StmL0xxEpromSingleWrite(EPROM_WR_TYPE_BYTE, EPROM_TEST_ADDR+num, (uint32_t)tmp[num]);
/ N1 Q4 q* R. C& [7 ]4 C - }
5 W# n5 O9 m5 Y! d7 X - 3 v& z4 v2 ~( S( X1 l4 ~4 Q7 i" H& Z
- for (num=0; num<8; num++) n: o& \+ i Z. V3 Y' t t
- {( g4 s; b+ H1 t% Y# J4 Y7 p q( H3 |% E
- StmL0xxEpromSingleByteRead(EPROM_TEST_ADDR+num, &read[num]);8 s! T% E3 K! |; t5 r0 d" f
- if (tmp[num]!=read[num])
8 \0 i& i/ e7 a, R" Y$ {9 ?: }" c - {2 a4 ^% ?& F" g$ S! d
- time = 10;
1 e) Y" g! P( P% B l ?1 o0 e - }1 C' s. }1 t: z, z* S) g! l
- }
: ] W; M. s8 N7 u0 j" v - - b* O( v' {* y, `* }2 ^; ~+ e3 @; V& R3 ^
- //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_HALF_WORD, EPROM_TESTEE_ADDR, *(uint16_t *)(&tmp[0])); //// 进入异常中断
$ x9 L# Q6 A) B+ |$ G. R - //// StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTEE_ADDR, *(uint32_t *)(&tmp[0]));//// 进入异常中断
9 r( u; c- J9 [) V& O6 P" b - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR, *(uint32_t *)(&tmp[0]));
" Y9 [5 A5 A8 ?8 `( T/ L - StmL0xxEpromSingleWrite(EPROM_WR_TYPE_WORD, EPROM_TESTE_ADDR+4, *(uint32_t *)(&tmp[4]));
/ d5 |( |1 N2 ]/ L - StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+0, (UNS32*)(&read[0]));
* M% b! p0 `# M& p: p - StmL0xxEpromSingleByteRead(EPROM_TESTE_ADDR+4, (UNS32*)(&read[4]));
' J; |/ Z: \) n- h2 H; s5 N0 x# d) }) J -
d' ?8 D" S7 R; D - time ++;/ W" X/ }$ p$ K2 ]2 q7 h
- }
. m( W9 M" y+ d: y5 F; z9 X: o - }
复制代码 | | | 2 z% R0 L# O- L0 f1 y: C4 b; O
$ t1 |8 }6 E1 Y% l/ ^: u( `$ g1 U! }
6 `, D( p* _; w1 t4 f7 u* {7 ?; F2 G H* A
; V7 N2 A8 y. M, p' H4 X | 总结:
# _ x3 d: f3 u" i9 N 1. 字节操作时,传入任何地址参数都可以,读写操作正常;
" p7 ~0 f. j I6 H 2. 但是当半字操作时,如果地址不是2对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
/ G3 `8 _! w6 U; O+ L 3. 但是当字操作时,如果地址不是4对齐的,则调用函数StmL0xxEpromSingleWrite时进入HardFault中断;
7 I7 z% [. P9 n! z: v1 _
) c! }1 | X) S 调试发现调用HAL_FLASHEx_DATAEEPROM_Program函数时进入异常中断。: s" V0 D3 U- m" f- }$ P" e) ?: x
原因是EEPROM在内存结构上实际是以字为单位的:
! `7 \4 Y9 h v o
( {! I) g U5 U8 j; T0 W
虽然可以进行字节、半字的参数,但是必须保证地址的对其方式——半字操作以2对齐,字操作以4对齐,否则会出错。
' @3 ]) H7 p2 r' k9 S& ]" Z% R
7 Y7 S/ N8 H. J3 v& y# z !!!!这个代码的对其方式怎么跟贴代码之前不一样呢,完全左对齐了!!!7 m9 b4 X4 N0 I0 V2 F
' q7 Z! l3 y# h- M& b3 }8 {: Y) ^ G* Z3 t; w" C& V
|
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html