STM32L0 内部EEPROM写读9 E" ]2 S/ O& \1 p
说明 p z0 u: B% s# s, a/ u. q
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。
2 j, E3 X& _& j/ v/ S. Y0 v! w0 Q8 `6 U/ z3 \5 ]/ l
基础写读函数
( t7 \1 {: D# a3 ^9 X定义内部EEPROM的地址空间:
. O; W- A7 F) E/ n- //STM32L031K6T6% _- ~# f. U6 |- w
- #define EEPROM_BASE_ADDR 0x08080000
- ]5 j$ W7 c5 x& S& X3 c1 K- h u - #define EEPROM_BYTE_SIZE 0x03FF
复制代码
+ J% m, h1 i3 u1 k5 D" _( \基础字节写函数
& `7 f5 p3 M4 d+ l- v- //Byte write% M9 J, k5 \! ]3 B
- void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)7 D0 U8 l8 G1 O
- {4 m- m3 H3 Q. ` l" D
- uint16_t i;" P/ J! @0 X- t1 N2 D6 ~: g
- HAL_StatusTypeDef status = HAL_OK;
- w4 a# Q) r# o! K( s2 p
. A2 `3 ?% t" |; u- HAL_FLASHEx_DATAEEPROM_Unlock();9 H! N& t9 Y2 Q. V
- for(i=0;i<len;i++)4 `% r/ p9 @4 F0 i/ |; b2 }
- {* t; n4 U8 U' v0 X3 X; ?' ^
- status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);
, Q' h) } k2 z* Y: `" v h7 f - Data++; e& d' C- x5 X# _# W
- }/ b; \) G& x7 ^' U P
- HAL_FLASHEx_DATAEEPROM_Lock();
& b/ X% b# \! L, n3 B" ]; j% W& z - }
复制代码 - y7 S) N$ I- E2 e3 i8 }; Z
基础字节读函数/ o) n \ o; h4 ]8 C4 N' k
- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read
9 `: t7 I3 z2 F& [7 } - void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)5 J8 n/ S( s& P3 i* A
- {: [7 B( t" Q0 }* t A
- uint8_t *wAddr;+ {, I5 {, ]2 k0 b
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);
0 t/ i( h0 A( a2 M& W - while(Len--)# ]7 t: L4 I( L" ~
- {
5 R! z1 _2 j) W& H8 a7 ~4 F - *Buffer++=*wAddr++;
) ]/ I7 R) G" g; M+ P: t$ n. k& _ - }1 Q# o6 F+ a6 Q
- }
复制代码 0 a. x! L8 |7 ^4 A. U! l( y; b
带校验写读函数
/ i+ q, U/ I. j. K7 Y, x如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。
- S7 i- {1 T4 w" } t: E2 E J! n对于写过程,需要将写入的数据,读回做比较。) q2 T- e- x! @: ?, R9 P% I
对于读过程,需要将两次读回的数据,进行比较。7 d: a& e& v) \1 z0 L
如果比较正确,则操作完成。9 Z7 U! W3 j7 r* n! v* a6 _& R
如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。
! n; H( T M6 R
4 X$ C4 C. L6 _6 X设定重复校验次数
6 v6 M6 \9 b- W7 N0 a- #include <string.h>
( F- W$ y9 b2 ~0 m6 S3 p9 ] - #define iEEPROM_CHECK_NUM 2
复制代码 ( F3 c* w( F2 y6 g( O* ^
+ L9 V2 A b( Z5 `/ W带操作校验的写函数
' }0 d( e3 S9 a2 C* _- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
( e5 {- i' f& Q4 M/ E' P; S- k! X - {
( T8 L% U1 W( h3 Q% O2 y - uint8_t buff[len];
5 m1 F) m# o( t: i. |; I - uint16_t i;
q6 p; ^ r7 X; t3 u - for (i=0;i<iEEPROM_CHECK_NUM;i++)+ }: u3 W% o9 T
- {! p5 E: g; F3 [ z0 t
- EEPROM_WRITE(BiasAddress, Data, len);3 M7 p/ B# L1 s' V/ I0 K4 S7 [. W& i
- EEPROM_READ(BiasAddress, buff, len);4 p1 f* [! g& t
- if (memcmp(Data, buff, len)==0)
" u5 C5 p" I- n8 \: ~ O& _ - {9 Z8 y' V& t5 ^' ?% W5 G8 S
- return HAL_OK;
9 M; N' t- ?0 A2 O) Z - }' ]# `7 m% O0 P* n# A& d/ U3 ?
- }
; G0 |: ^+ A- }
3 h/ p6 g) i% Q& Z1 P# [3 i- return HAL_ERROR;0 |7 J; Y; U! W( b8 i
- }
复制代码 / t: T7 ~/ D: n9 f
带操作校验的读函数! h2 }* |: m6 n
- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
, d9 P6 ?, Q6 w8 ] - {
0 o7 e9 [: }. {* J" o/ V - uint8_t buff0[len];
9 O3 M' X' F: H8 V2 ^+ _ e c - uint8_t buff1[len];/ a$ ^7 y( g$ C! [! _; J+ r
- uint16_t i;
" Q0 g$ I5 i1 ?9 W - for (i=0;i<iEEPROM_CHECK_NUM;i++)
/ [: Y6 G N/ _) H - {4 W0 ^% m( R( Q0 A
- EEPROM_READ(BiasAddress, buff0, len);2 R: S9 d; g A* a
- EEPROM_READ(BiasAddress, buff1, len);) @& P7 k4 ~0 D" M5 K
- 4 o: _2 a% d5 ^' J
- if (memcmp(buff0, buff1, len)==0) w; `! u; W+ T6 \! O3 B' Y2 B0 W8 D1 \
- {! y, r# v. j# M
- memcpy(Data, buff0, len);0 u7 R: j9 Z2 e/ x' _* V! r N
- return HAL_OK;
8 q* T5 w* Y" h( }0 }% d - }
9 Z/ X; `5 d1 U" h7 A/ l( E8 h/ j. z$ P - }
, T/ F; z) f2 @! j( v
$ ~! [* ~5 E/ W+ I$ y; {- return HAL_ERROR;
D& V- l& [5 W/ C2 u" B+ } - }
复制代码 $ P' h+ N; h b) G; j r* K
其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。
0 A+ c F. i' } l0 _7 k% G* d- l' [ i; H% p# A0 ]
需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。7 X1 ^" u3 M- |! ]* n7 y
- `& a# o4 Y1 g8 b. u( s* r
HAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:# S$ p& _9 f0 ?; y2 A' d
' a% i& i* V1 G j1 c- /**+ g' c, }) {3 e+ y# R( B
- * @brief Erase a word in data memory.
9 i: l2 j) k' l) q4 ? - * @param Address specifies the address to be erased.% S% j1 a. W; r. j5 ?6 Z
- * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function4 |. b* N& c0 Z7 z8 ^
- * must be called before.
9 E! e1 K5 X7 _4 [ - * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access
9 j4 U2 c% i2 h. u! S - * and Flash program erase control register access(recommended to protect ) c/ Q; z, C6 W! q$ w: v
- * the DATA_EEPROM against possible unwanted operation).
/ G/ D4 N/ m4 V: o' V" {* E- s$ t1 [ - * @retval HAL_StatusTypeDef HAL Status2 D$ b- F) Z+ v, H' J ^2 o! E
- */
8 i4 a/ o' _2 z( R: j* i - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)2 S: u* w m% t$ Y7 e
- {, }7 Y& ^# q* x& o% V Z
- HAL_StatusTypeDef status = HAL_OK;, C5 _' v5 \' X7 d: I5 c( c" a
5 D7 ^& q0 S8 s3 o- /* Check the parameters */! _! O. [* h0 l' ~, p+ z- R
- assert_param(IS_FLASH_DATA_ADDRESS(Address));
7 A* \3 L3 I4 ~4 ~5 z/ ~5 c
3 x' `) A" H( m- /* Wait for last operation to be completed */+ [: H6 z' M% z: _4 e6 D. Z1 B
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
4 u! s9 z( N$ p! {+ y& ^. ]
# @$ x/ \' M ?* T2 O- if(status == HAL_OK)- U$ y, V* F: C! Z. K7 d' @
- {9 t+ Q( x. J9 U+ [$ D, ~" y) t& V
- /* Clean the error context */3 r1 E6 V; u, W4 o/ E% V
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;/ m# I& w$ i8 d& Z
- $ I. J, F( v; c. \
- /* Write 00000000h to valid address in the data memory */
) G' j+ ^2 b+ r) P, F - *(__IO uint32_t *) Address = 0x00000000U;
' Z# [$ C( ?9 b4 d$ c; u - $ e$ [& N& g3 e4 \, D
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
/ `. Q( r; H& {. p$ f- P0 C; q - }
# y+ |- A5 c: D3 N. w; w) O# r" Z8 g - 3 }, S/ ~0 l3 ^# L
- /* Return the erase status */! i) a5 x0 B1 u8 r6 B1 }$ b
- return status;
, d" ]1 t9 Q% M: Y& y7 [' s( T - }
复制代码 " ~/ s i p9 `1 Z1 P8 D
上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。0 r0 r. t3 {2 H% [- b+ }" p
5 X# H3 I, P8 W! A, V: u) e7 v! ]- M5 y& X. h% X5 I
|