STM32L0 内部EEPROM写读9 @8 a) o! U+ F6 m: Q* u
说明& K. {" i* ^8 f* b
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。
% m) {. \9 ?7 O4 {1 X
' P9 d( Y% v2 \) ^- Z. d' {基础写读函数9 M- c% ~$ F9 H
定义内部EEPROM的地址空间:
( C( x- j; D1 {" g. G( l; z2 K- //STM32L031K6T6
* {8 t* B9 N/ p" F- ]& U - #define EEPROM_BASE_ADDR 0x08080000; r# ~* H+ w# B$ g0 z* B" D- z
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码
0 A/ y/ U( T8 e( a+ P6 `基础字节写函数
# K9 ?1 h0 G' H3 l) t9 Y- //Byte write
: ], }( K! S5 u" B - void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)4 `6 N5 F7 z1 u* y
- {1 f/ a0 v+ A# v8 m2 v- H. a' t/ L6 K
- uint16_t i;
4 z9 S8 R( k% y5 y) {' ` - HAL_StatusTypeDef status = HAL_OK;$ x" i4 {+ E2 f
- 9 I, m+ q+ ~! W2 ?9 K: P
- HAL_FLASHEx_DATAEEPROM_Unlock();
% V& Z" i# H: d$ U! H/ o5 A' ^ - for(i=0;i<len;i++)
9 x, H( o1 W. g1 C/ Q+ }2 B - {
: H# _) { Y5 t4 D7 s! N6 R. a( x - status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);
+ B% q# Y9 W& Z& B% t: n& P2 y- l - Data++;
) ?4 Y$ o8 @- E0 W3 n. d - }- i+ l6 f" n' u1 h
- HAL_FLASHEx_DATAEEPROM_Lock();
4 v! L, i! O- A$ ]6 A - }
复制代码
/ s6 M1 E2 V4 Y0 M. X8 V基础字节读函数3 L6 Q8 K5 [4 x- j
- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read
' ^5 a2 `8 C/ X; y* ~, J& z - void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)' D( }2 `: ~" F) Q6 a$ I
- {- `; s7 T0 f- P+ p1 P7 B8 \ u# q* W
- uint8_t *wAddr;
8 j: Z: s( ]* W$ O" |* ?- d& p) p' l - wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);3 Z" p- S# D. ]/ K
- while(Len--)
* G' u$ v {* j; N - {
# s( ~$ n( `2 V) S+ s0 Q4 g - *Buffer++=*wAddr++;
( {" G4 ^+ c% `3 Q4 i8 c - }: }6 H& O) S! A6 L
- }
复制代码 / d5 j* p: s0 Q1 i: v0 R
带校验写读函数2 k( G( O' p. X
如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。
- {3 o6 b' |4 M) x5 X6 p对于写过程,需要将写入的数据,读回做比较。
/ b$ c" D- B7 C! S) `对于读过程,需要将两次读回的数据,进行比较。( X& f( \# U \9 K+ e
如果比较正确,则操作完成。
: \1 Q7 \- ]' [如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。 m$ P7 r, P, {) Z5 v
& ]6 u: L6 w1 Z+ w4 [设定重复校验次数6 a% D% ^1 z' O/ [+ n7 q/ B4 Z. V
- #include <string.h># U+ t, d9 h, o; I- }
- #define iEEPROM_CHECK_NUM 2
复制代码 + ]6 C6 E% u3 ]) x
8 t% I( N3 [9 z' e! d带操作校验的写函数
, x1 Q' l+ ^; m! g$ K) {- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
3 D D$ }* `4 V2 J; ? - {8 u% d0 p! ^+ p# g4 {/ @ C9 W
- uint8_t buff[len];6 U: I8 t/ L1 B. }
- uint16_t i;9 v9 t- ] K" E+ [" D
- for (i=0;i<iEEPROM_CHECK_NUM;i++)0 S) d' S3 J: t* R! k, X+ q# |: N
- {
X& b& B$ u# c+ U/ n- d! t, s - EEPROM_WRITE(BiasAddress, Data, len);% ^7 @0 O5 |5 [3 y, {1 q8 K
- EEPROM_READ(BiasAddress, buff, len);% C. ]1 z6 @+ R) b
- if (memcmp(Data, buff, len)==0)8 }! I. h2 v9 I8 o6 j6 B# b
- {
* b: r1 Y1 ]5 c* { - return HAL_OK;
- f: I/ g2 B/ o+ o4 i3 ]# @; e% `6 J - }% `% `" m/ V' V
- }+ z+ Y9 u* M2 M8 o i
1 C5 b" I4 o# K- B- return HAL_ERROR;1 \1 _+ i$ G; H, p1 v; `( C' e
- }
复制代码
+ e/ j) Z% p/ L" g带操作校验的读函数
) g- ~! B! S4 Y- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
9 I2 p& e6 C/ H! c! ?+ F2 i7 H# S* b - {
1 L5 l& [: _1 Y7 v/ T - uint8_t buff0[len];
8 S. e- {' A; c. N - uint8_t buff1[len];
3 ?1 Y8 n" a* E2 q% V. d- U, W - uint16_t i;! z [0 B: d$ y9 [* [3 V
- for (i=0;i<iEEPROM_CHECK_NUM;i++)! C: D7 |7 s* s
- {/ T2 D) q) z/ C
- EEPROM_READ(BiasAddress, buff0, len);
3 T* |7 G$ c0 J s$ n& p6 x" n - EEPROM_READ(BiasAddress, buff1, len);, M3 u* z$ E% L# `7 D
- ' j0 d" s: X* _1 ?& Z
- if (memcmp(buff0, buff1, len)==0)1 U+ A! `4 W3 ~ V" @
- {
7 q" ?) [% U9 ]" d! v - memcpy(Data, buff0, len);
( w' G1 |$ i4 N- O3 Z - return HAL_OK;
0 n- b/ }' N& ?3 o' r( ~ - }, g1 x. C4 z7 m8 N
- }
! X% G" r3 N7 V/ n7 i - , {) x$ I' x6 |7 `, s2 a, x
- return HAL_ERROR;2 z$ |) X8 r& t! P1 T
- }
复制代码 3 L# A( c- h- |. @8 i2 I
其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。" q! _9 N7 ^) w, \3 R2 h
! ^" d5 H- P/ c; Q& U需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。
% R2 @" i9 u. a3 g w
8 O: |1 l' h) @HAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:
8 [9 w& c* h2 R* E8 P! P1 c7 b8 V* f" G! b
- /**
) h9 y# c$ m/ E& p- T: L K - * @brief Erase a word in data memory.0 q9 c) p2 f a6 i7 v
- * @param Address specifies the address to be erased.7 I1 J( }0 C4 n9 L8 ?+ l3 p7 O
- * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function {8 F( @( B4 d+ a6 [9 A3 s8 l
- * must be called before. n7 M; x) u, P& a+ {: h( g4 P% T* }- D
- * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access
: d- k' t/ Y: H2 Z, w8 K - * and Flash program erase control register access(recommended to protect
/ |2 T& ]+ W) k4 N - * the DATA_EEPROM against possible unwanted operation).
/ G! s- w, M' C$ h - * @retval HAL_StatusTypeDef HAL Status
/ u" i2 {( q* ^% p, Y4 `* T - */3 g" G8 J( }. Z7 i
- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)
- B1 v ?, o+ T - {& m# M. ?" ^4 S$ i. f
- HAL_StatusTypeDef status = HAL_OK;
! ?$ ^/ P5 @ u; x9 H
. v! r! U8 X1 e- /* Check the parameters */
2 n; _) g( r5 n - assert_param(IS_FLASH_DATA_ADDRESS(Address));
3 ? q/ o8 I! L7 O. y - ; d) [7 u( S. Q! s: m- i
- /* Wait for last operation to be completed */7 [% S! l& c+ `6 A5 X& l7 [
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);+ e: ^5 w, c" b; ?$ ?7 U
6 {: ^; d# n4 m) J- if(status == HAL_OK)
9 |* |* E* `) d+ i- _8 F - {
/ _, s2 K) g/ |; D0 G - /* Clean the error context */
- P& B+ ^& a, c - pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;7 \4 S# @% p+ q+ w }4 {: N
- ! V8 u$ d9 U( m# z2 g. U/ w& q
- /* Write 00000000h to valid address in the data memory */
; h+ W# q- S( U - *(__IO uint32_t *) Address = 0x00000000U;
! y- e+ K; k) t7 c4 l7 s - ! p4 L" _; s' o: [
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
+ }; C! @' _4 x# l6 U7 U - }" Q/ k2 H& Y# [* C+ N
- 4 U' v! }$ r' [$ h0 C+ e. @
- /* Return the erase status */
2 W. z! A4 j& `7 }( }- I, z - return status;* M9 t- I$ L8 P/ j+ L0 E! s
- }
复制代码
1 C6 n- _- l" S3 q上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。. z- o- x/ N5 Y
$ q" P; u. Z. V a
6 X" S" E9 l5 T9 @0 a |