STM32L0 内部EEPROM写读
6 k5 }( {. O% \5 ]0 A+ Z8 q说明- J) e, l) e# L0 `! ? a0 g
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。
W% S" h9 o* J! k& F
. Z! N b3 S# s) x, E基础写读函数
0 M6 T2 S% P; H1 q2 l2 e定义内部EEPROM的地址空间:
- ]; G! g8 O, t: V- //STM32L031K6T6; V8 L& m$ g6 M* Z4 S$ ?
- #define EEPROM_BASE_ADDR 0x08080000- z$ Z3 i; z3 H9 ~; M
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码
. b" e1 a$ ]8 D; o: S基础字节写函数; f% m: R9 \$ H3 c3 B! a
- //Byte write8 J/ e5 @% `' @& H0 K
- void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)2 i5 \! h+ Q$ }2 _! O
- {
# \0 q- E1 H5 H) A* t! X - uint16_t i;
0 J# ~2 \+ W1 f2 ~: D - HAL_StatusTypeDef status = HAL_OK;2 |- X* _1 x3 O5 l
- + j3 X$ \/ d6 i. U
- HAL_FLASHEx_DATAEEPROM_Unlock();7 M2 s/ l2 D% V, s% m+ _! D
- for(i=0;i<len;i++)( y* W; L# ]( g, q
- {
5 S q6 L% j4 K' \' P3 l2 U4 B - status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);7 x2 G3 a9 `" r3 Y" O! g1 N( _
- Data++;
1 {/ S, E0 @9 e" J0 J% |" t - }
# |* P: c; _* y - HAL_FLASHEx_DATAEEPROM_Lock();
d& S4 `1 W- l$ H! I+ E9 | - }
复制代码 4 P) O# G2 Q) P6 T9 y o
基础字节读函数
5 v. S: E2 F8 X- f: g9 f- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read# b6 K1 h' X6 s( K
- void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)
) L+ }2 }, C/ D - {
* r1 W( I) P4 h) R- j) \7 } - uint8_t *wAddr;8 _2 q2 m/ `; r; b; Q
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);7 U3 S$ I9 y0 O) |' e
- while(Len--)' ~$ t" ]. {7 n/ j
- {, h% q* C8 M+ U: K8 Q
- *Buffer++=*wAddr++;
+ Q0 t/ t1 V' Q5 Y* R& ] - }
& S* V( O: {: D! h& k* N4 T! u5 o - }
复制代码 6 g& T% j& a( X) N0 j
带校验写读函数# U: a- [7 r4 X# l
如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。& K1 A/ y$ Z6 {- j. m% _5 u
对于写过程,需要将写入的数据,读回做比较。
! F$ {9 j- n+ Q. t5 @对于读过程,需要将两次读回的数据,进行比较。5 i1 a! t, U# t+ j8 B& o; \ D
如果比较正确,则操作完成。
/ Y' V4 T- j8 F6 U+ `如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。
. G) }: n; n+ Y! V/ G$ ?. G4 {+ I- Q: M; Y B9 ^4 Q
设定重复校验次数
) K; O. H3 _, L- #include <string.h>* `" F" e# ^- l; A
- #define iEEPROM_CHECK_NUM 2
复制代码
7 ^# a& H5 z2 G4 P; s6 f. u6 k6 o( n9 V4 O: D1 f
带操作校验的写函数
1 T- H6 U L5 i, I7 m- p) E- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
$ r6 v2 i8 g6 n; c - {
0 Y9 E7 K1 |* I8 p, W) D& ]- b - uint8_t buff[len];
8 c0 g/ K6 E7 ]. b# ]7 r - uint16_t i;7 R7 o9 {6 \8 q9 g& z# @/ j
- for (i=0;i<iEEPROM_CHECK_NUM;i++)
: D: Y6 w8 h7 Y - {3 S) |, r1 F- Y, _
- EEPROM_WRITE(BiasAddress, Data, len);" d7 D2 a* V; p* ?4 o: [
- EEPROM_READ(BiasAddress, buff, len);
}5 V& A! [1 E! p! g0 P - if (memcmp(Data, buff, len)==0)
* V7 g/ X W% _2 ` - {
; u" c0 d6 X( k! i" _; A - return HAL_OK;$ M) g5 [2 ~# E9 M( R
- }! Q6 I7 b8 V# x% X" S
- }
5 s/ ^$ Z4 c3 c, X: v& N* d - ! f9 U: e' k3 G! w5 w0 b2 I
- return HAL_ERROR;
# |& L% U4 {0 B4 A; o# Q, b, i6 L/ Z - }
复制代码 / S" u! q2 @9 h9 a! O( t2 `5 f, \
带操作校验的读函数7 R7 j* ~% J2 Y$ l) F |! h
- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
& @- @5 j1 p* o - {
/ J, [1 X6 o, H& Y( O, x - uint8_t buff0[len];9 J- ?; K7 \- x$ f, W* ]
- uint8_t buff1[len];
. q4 A7 X8 a+ A+ a1 S5 Y" W - uint16_t i;
7 H0 C. a3 |" _5 k5 u - for (i=0;i<iEEPROM_CHECK_NUM;i++)
# { {$ W! E, z4 C( h* K# q - {8 {* m }' Z* A1 Q
- EEPROM_READ(BiasAddress, buff0, len);
8 Y$ I; H1 u8 }. [/ u - EEPROM_READ(BiasAddress, buff1, len);' x" ]# D7 L9 Z. X
/ w R1 W& k K+ Y: Y" G/ J6 I$ V- if (memcmp(buff0, buff1, len)==0)
( B" s* E/ t9 a2 _! U% V4 E - {
5 G: ~7 |7 Z8 G: }" ] - memcpy(Data, buff0, len);) V6 v! w0 K5 M p
- return HAL_OK;& N4 Y, }3 F7 R1 H8 g; u/ E
- }
, y) ?: ?8 ? i3 \ i - }
4 l+ {, l: F. u - , Z1 \8 N0 A' e% @, J o
- return HAL_ERROR;
- D% j6 E+ a: R& M - }
复制代码 * F C! b: m+ h/ i# O' h5 g. {
其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。
+ M2 h3 ^# ^& }$ E# i& I' t: E; F9 [# `
需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。
8 F$ _- X2 j! `# G
9 A% z( x* E: }! }1 k& THAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:7 S+ n9 W$ Z# `9 k1 T! F% \1 n- q
1 l5 x/ W6 c' U) q5 T/ t- /**7 F% J( e; e3 y
- * @brief Erase a word in data memory.
( _6 @3 H- L; L - * @param Address specifies the address to be erased.
P3 j- r0 m; T% Y - * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function' w& U' P# b2 d1 f% n, s2 k
- * must be called before.
0 g* @# a {3 z9 T4 d5 c) R8 {2 A! a - * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access* _: r% h Z, R$ w/ \4 b% |: k% W8 o
- * and Flash program erase control register access(recommended to protect
5 k" Q6 P3 h) r! t: ] - * the DATA_EEPROM against possible unwanted operation).
3 p: ]1 a( k) V+ F - * @retval HAL_StatusTypeDef HAL Status" _6 ?5 d! ]4 F( a# B# ^
- */
' L1 ?; O4 i4 b, m - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)2 o1 S' W7 O. B" y
- {4 i* R- h2 z" W$ L* X
- HAL_StatusTypeDef status = HAL_OK;/ n0 o% E) [5 _" V5 B3 o- h9 }- A, I
- % _0 d- P' t" G- d, w2 a
- /* Check the parameters */
& C5 z% @4 T) c% t y9 A+ Z - assert_param(IS_FLASH_DATA_ADDRESS(Address));. p, I! W9 \9 j8 X* L9 X
- ; v/ q4 a6 ^8 t# Z) B
- /* Wait for last operation to be completed */
+ X5 [ G/ ]: i8 o$ @; f" h6 _ - status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);; m3 K8 q. s7 }
- 1 x9 C- |% ~9 W4 ?% B: b
- if(status == HAL_OK)
! P% l, A8 p4 p0 _ - {
: }( H. k' v" A+ T) z1 T" u - /* Clean the error context */$ y- q5 m9 ~* Q+ }* t. i" k
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;4 G" e% ?; C. F" A+ x
9 R* w0 a. K! ?* }4 }- /* Write 00000000h to valid address in the data memory */: Z+ X9 W6 i8 D& U" F: Y
- *(__IO uint32_t *) Address = 0x00000000U;
- n# a9 o$ g: B
# H8 N. H2 k8 P& ]3 i, V9 j- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
& ^$ i. y6 n5 U* b. ? - }
* ]/ L( ]6 A! p# f
8 t: D( S; J, u! b! @ C0 Y3 ~' t- /* Return the erase status */
* o3 R& y5 y3 K9 Z - return status;
; n* w2 y* i( t; e% P5 L& g | - }
复制代码 5 a% ]3 l& g( C4 _4 `
上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。
4 n6 c1 v' N7 A) b& F+ L7 k# ?% {3 v" A5 y. R$ I
* |* G/ x3 n' V, {) S8 T) h% c |