STM32L0 内部EEPROM写读' \+ e" m9 \) \* B* j
说明) A* N2 L! t* |
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。* {& S" K H' H8 T) p7 E
( ^% t+ u9 }& q3 A% g# g基础写读函数
0 |4 _# E4 \5 c' Q/ X定义内部EEPROM的地址空间:
7 W% b8 e* S% W, m- //STM32L031K6T6
/ Z. ?' G" R$ j* \1 F1 P( X - #define EEPROM_BASE_ADDR 0x080800008 u3 _8 r* D) k3 _
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码
6 G8 i8 D6 m9 J8 a6 l# x基础字节写函数6 G' _& K! P. `
- //Byte write
2 ^6 w7 r3 A. H9 R+ I - void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
% y0 f* \, M+ X. K/ O0 x4 F - {0 m) v$ N( ?2 B' b+ i/ O d
- uint16_t i;
5 y+ s' y8 c1 d% g - HAL_StatusTypeDef status = HAL_OK;2 k0 b, Z# \# j0 n: k/ M( c* W
- 7 p+ l. a: j' k0 ]% S& ]
- HAL_FLASHEx_DATAEEPROM_Unlock();( [2 m6 T5 [# b0 U; E0 p
- for(i=0;i<len;i++)) u; b0 _8 n+ X
- {
1 r# }( ]) B: ^! W5 b - status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);* p* R7 D% @% x
- Data++;7 `! F: \& z9 e1 [- Q' L8 p3 C, ~
- }' S0 ^. M( w. G
- HAL_FLASHEx_DATAEEPROM_Lock();5 C. l+ V" w% w) {( k+ D0 q' a
- }
复制代码 o+ x; S1 H% a( u
基础字节读函数7 |3 `. L+ ^. Q, e5 ~+ P
- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read
. |; I6 {- q* V8 G- e( T- j - void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)
5 g+ X+ l3 z' M* z9 V/ R - {
7 f- {8 {7 K" d$ c! C" A2 X - uint8_t *wAddr;& N8 N! A# i* q. W( m! H. @
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);
5 W7 x" ?# v* o. O' u$ \ - while(Len--)# {% E0 C% s0 w+ r- q
- {# ^# D8 u0 {. R I* a) ^% U
- *Buffer++=*wAddr++;
: H4 q. R; D- x! P1 N1 k. Z - }7 h- S* _0 o0 F \# f" j& H4 v2 y
- }
复制代码 - S, ^3 ?' Q5 d# N, O9 g$ _
带校验写读函数
; e( L+ o; y0 B' \如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。2 O1 a; Q* S' `& x6 |+ S D! \
对于写过程,需要将写入的数据,读回做比较。
1 N8 K' Y& ] ~3 U对于读过程,需要将两次读回的数据,进行比较。! A( Q# j8 x: w* \0 W1 y
如果比较正确,则操作完成。+ g- P7 |% H/ U( _
如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。
' |2 K0 O! n. O0 q8 K3 D! R
6 E1 ]$ l) t$ O. {* @设定重复校验次数/ R1 z0 }4 N: W _, E6 n
- #include <string.h>$ I' I4 Y! a; m F8 C
- #define iEEPROM_CHECK_NUM 2
复制代码 K" F( q% e( K# X% G
0 y+ E# q# r( C( ^ o
带操作校验的写函数
7 L& m* }" G# ?- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)& _7 E. ]9 t) ]1 ^6 Y2 M
- {
: F+ ~- t- R6 G) J% w - uint8_t buff[len];
% y( \: X, t3 c& n9 n* `( U - uint16_t i;$ E# Z3 c& H3 v. T2 X; B; U
- for (i=0;i<iEEPROM_CHECK_NUM;i++)4 @% Y" E/ ^- d6 p
- {3 L$ M6 `6 B! }" x& q+ p' n: h+ o
- EEPROM_WRITE(BiasAddress, Data, len);
) n- L4 I, f4 O* ~ R5 U, K2 F - EEPROM_READ(BiasAddress, buff, len);
3 q( ~% | J! X [: v - if (memcmp(Data, buff, len)==0) X! g7 m; O8 s! b& B; b
- {0 E% U. _& F; B" m1 y2 ]% r8 D" K
- return HAL_OK;
5 Q' h A2 `: s/ L - }9 U( ]# ^' k+ e$ d
- }( Z5 @9 }6 f1 c
- 5 s. ?0 z4 ^! ?
- return HAL_ERROR;0 R1 E; \5 }7 R& H( @- G7 Y
- }
复制代码 8 R2 B1 C0 s- Z2 p1 ^( i/ v) W5 D1 `
带操作校验的读函数
- a$ @' o, Z5 b% [) J- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
2 w1 ? O9 b% |; d! p8 P - {3 Q$ _2 I3 O8 U7 c
- uint8_t buff0[len];
* Y3 a, `4 z+ R' ^1 ?' U! i; g* U - uint8_t buff1[len];
" r8 a. U" a" D5 G! U% H7 Y, E - uint16_t i;
7 x+ B- _7 {4 k X: I) S - for (i=0;i<iEEPROM_CHECK_NUM;i++)7 A% Y I% i% l
- {
6 t0 _6 [8 F3 L5 o' X. f, I1 O - EEPROM_READ(BiasAddress, buff0, len);
3 l6 j* z* y8 g% E) ~7 c - EEPROM_READ(BiasAddress, buff1, len);
8 a2 F: V$ ^- F8 f" r
1 B9 s o: C8 c1 G, H- if (memcmp(buff0, buff1, len)==0); Z {- U4 U' o$ c7 c1 \' N
- {0 }1 [7 A" y, _" b4 | J
- memcpy(Data, buff0, len);
. o6 F$ I: s% A- ^1 T' g1 { - return HAL_OK;
' [# e: T9 M/ A, P - }
9 I. ]0 f8 ^7 S$ T: _5 q, K, J. J - }* d+ k1 S+ u1 I( m& D5 o5 H
5 q2 c7 M, g3 q* t$ x- return HAL_ERROR;7 T6 }( ~5 b" M; E
- }
复制代码
1 s+ _. y8 t0 }/ L" w其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。6 }' v, O) k! f" X- V
0 V5 H2 C, x4 D6 F4 R; V" ^需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。7 U: N2 m6 n" L1 c
8 x) g8 K& X9 V/ d2 t) L
HAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:% h! t1 O9 X) p, k( T
& Z( K6 w8 H9 V9 ~
- /**
2 g5 {" a2 n' E( h' L - * @brief Erase a word in data memory.
& A. \" M: N/ W7 o" `! m i& K - * @param Address specifies the address to be erased.( z# ]0 ]$ X2 K: Y( t
- * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function
; u8 c* _- h+ b, T* ^ - * must be called before.+ d% E; X+ \! s f% P& Z! z3 Y# Z
- * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access% T) q0 w7 ?7 z( f
- * and Flash program erase control register access(recommended to protect
( v: v3 G6 o/ M# s - * the DATA_EEPROM against possible unwanted operation).4 Q O& c& F3 h; r( T: S+ l
- * @retval HAL_StatusTypeDef HAL Status
, A/ a h2 F8 U. ?* ] [3 P - */$ [/ i7 O4 V& W9 C9 N
- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)) m9 Y4 t4 l- `& P! w* J. S( Z
- {
. Y+ L6 ~, U' } - HAL_StatusTypeDef status = HAL_OK;
/ j4 E3 Q2 `: R9 G
$ v7 ?% L' X @$ t- /* Check the parameters */
5 i+ ~( b5 P" s( Z - assert_param(IS_FLASH_DATA_ADDRESS(Address));7 t# V w) v- E+ t8 w3 l
1 l6 V% v5 A7 p, X" t, Y- /* Wait for last operation to be completed */1 k& w- }' b3 ?
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);& a! h/ u0 O* u
! g. G4 r2 K A- if(status == HAL_OK)
; Z! ?% _* T6 W3 U - {
( d: ?% k D( @4 W; C - /* Clean the error context */; D/ E; t3 i$ K( L; M# n* e/ y0 [
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE; Z- {# p1 F9 J3 @% ^* e% Q% H
- * r) Q7 ]# K" i1 y. ]) {
- /* Write 00000000h to valid address in the data memory */
( w N% @ c3 {. A6 d5 l& X6 L - *(__IO uint32_t *) Address = 0x00000000U;8 J/ `6 w6 p% I0 h
- . M8 i9 W- U9 p
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
$ {$ L$ K2 M$ k9 H, u: E2 b2 T8 P - }
5 ]5 e- Q0 w8 c& r$ c
4 e. D' K3 C+ l( D: E- /* Return the erase status */1 j: ]8 C1 j/ r) [6 @: l( X
- return status;$ w1 [' `" U1 g! K3 l- W. Z" O
- }
复制代码
. H9 G) T8 R# h7 G, C上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。3 U8 m4 n; [. O5 g
2 q/ [7 Y; a9 L5 l( {: L* ]* S
. F, o* _: m; @' ^" \9 a
|