STM32L0 内部EEPROM写读# c' @. ]1 F, }3 V: D2 J7 u5 f
说明
0 o) h! k: I9 p' _5 fSTM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。) _ ~6 Z% }: `% b
r9 m$ F, j% c) Q% K$ S
基础写读函数- |6 {" M0 u2 a* I2 k* X
定义内部EEPROM的地址空间:' X/ n& i# c y8 c F2 Z
- //STM32L031K6T6
- ^# e4 W2 w3 |0 P4 M$ O - #define EEPROM_BASE_ADDR 0x08080000) ^! y! q8 T; s8 P$ g8 T
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码 . p6 e% P3 z# e
基础字节写函数- ~5 N7 \/ U- s5 l
- //Byte write7 w$ j7 m5 k1 s+ j/ g" l
- void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
6 U1 E/ Y% _( ~/ p5 T - {- H; M4 Q( u: P9 E( C7 f$ Y
- uint16_t i;3 E& I- T5 I4 E, a' F
- HAL_StatusTypeDef status = HAL_OK;
8 Y7 {3 k- O6 v: t' L6 S
5 g: p; r& x4 h3 {- HAL_FLASHEx_DATAEEPROM_Unlock();: L1 r- {; h! s) E
- for(i=0;i<len;i++)
6 \2 A+ y6 W0 G" g - {
6 R/ L/ Z. S) J# c - status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);
D9 c$ B( G, n4 G/ D& @ - Data++;# D% _% B+ q) r& l" `: n
- }
' S7 g( L8 L0 Q - HAL_FLASHEx_DATAEEPROM_Lock();- a9 p) ~2 e4 G; ?4 Q- N
- }
复制代码 # |3 ~. t( A/ p S
基础字节读函数
9 b: Q! u. |. Y) k" }, T- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read1 s* T+ e) @$ q5 v6 b) A9 u" {
- void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)6 o D1 c3 o, d$ Q- @
- {
" p |2 k' o2 _; B# u - uint8_t *wAddr;
$ Y6 V K) i. Z# o$ E* D - wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);; g6 H" X1 i8 k. j5 k4 m7 M
- while(Len--)
* w( c. B) H( k& Z - {
7 }& v5 T5 e O- |2 E% | - *Buffer++=*wAddr++;
3 m7 N' n% J3 [+ d3 d* |2 U8 h - }3 Z* |" `! p( _. [1 Z
- }
复制代码
- K' e4 Y% X0 D' j+ P4 |7 }2 z带校验写读函数
6 y/ ?) q- Y! N如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。8 s+ X, o# e8 @) i9 ^6 Z* H7 G' G
对于写过程,需要将写入的数据,读回做比较。- s3 g+ J+ f {% K$ c0 |; X
对于读过程,需要将两次读回的数据,进行比较。
- Y( i7 c- K% ?+ _" c3 K如果比较正确,则操作完成。
0 V5 ~2 k2 m1 D8 o& l1 l4 x如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。
$ P5 N; L1 f6 H" F0 u7 g; l6 w" K7 j" \! O1 |$ _
设定重复校验次数
) {- N" y0 u0 e( m- #include <string.h>. P1 P! d2 e. W* |2 A% Y/ d" y7 @
- #define iEEPROM_CHECK_NUM 2
复制代码 + M1 b6 I) t/ d0 h- Z: a
- \; Z& [5 M) e6 P7 e8 @带操作校验的写函数
) k% T7 [$ n- v: R. k- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)3 d2 z* W$ @9 |) N
- {
6 M9 j. t4 r9 j" J } G @ - uint8_t buff[len];& @' _* {1 p7 `
- uint16_t i;. T p* a& O+ {* u5 t# ]
- for (i=0;i<iEEPROM_CHECK_NUM;i++)
8 w) V/ K, I$ d3 _ - {
$ i. z( f8 t& E! Z. s0 b( a0 e - EEPROM_WRITE(BiasAddress, Data, len);) ?3 c5 B& _; d9 p
- EEPROM_READ(BiasAddress, buff, len);
% t- x g" d7 f& s0 E$ e; p - if (memcmp(Data, buff, len)==0)" e( l3 p R9 K$ t. Y T0 F
- {
: _9 w$ ?# x R1 W( e9 C) U3 ~ - return HAL_OK;8 r- C$ k, L1 v& J, a" K9 e+ m; s
- }
2 w- D3 r& j; N5 `3 v - }
& ]9 z7 n; V2 e - . x; Y$ O5 a4 L& A4 Q3 {
- return HAL_ERROR;
+ w4 T8 W8 n% R' ?0 g; H+ n - }
复制代码 & X! v5 r( C4 V% L K3 z
带操作校验的读函数
+ r Y; I# W( p. ~ l* C- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
# k# ]7 a* P! U; l: U" Z+ a, ^ - {3 s, w/ Q0 m& O+ {1 U
- uint8_t buff0[len];* g; t0 [: w. y1 z {. O& J1 G
- uint8_t buff1[len];
- d% p7 I, _* A: W9 P$ f - uint16_t i;
# b- ~6 r5 }& ?( t% q# X - for (i=0;i<iEEPROM_CHECK_NUM;i++)
3 t, l5 }5 I5 R$ P - {' I& d% R# D3 a I
- EEPROM_READ(BiasAddress, buff0, len);
$ N+ x8 M7 a5 v& D. J( N - EEPROM_READ(BiasAddress, buff1, len);
+ W) c8 ]9 S% }8 f$ _4 h - - i* f/ ]! `) k$ Q" A# ^
- if (memcmp(buff0, buff1, len)==0)& ^: w9 X% h. n S7 q' h9 Z; i
- {
& k& g5 F1 N& P4 | - memcpy(Data, buff0, len);
, s5 i3 |% u1 V8 U- V" H) @ - return HAL_OK;) C' l4 U$ \4 y }$ H& a! O
- }" P9 [" J% y. |: x
- }0 k( j1 m" `* w9 }8 x
3 z$ i- _7 j5 y" {" u- return HAL_ERROR;. U/ G1 q1 N" g% H; ]' G4 L w
- }
复制代码
4 W9 k: I6 i& h0 n3 l其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。9 g; K) X' v& u$ F. {! N
' e/ P) A k8 O# d i* v
需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。: P# h7 {- O! h& t& M2 h2 h
' y y3 Q4 c% } KHAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:& B4 W6 @8 Z5 d) a5 K
3 s# U7 w7 i! K) @; d
- /**- p1 I+ s; K. c j5 h' h* T
- * @brief Erase a word in data memory.
& c8 q6 V9 o' s' \3 \ - * @param Address specifies the address to be erased.
2 n, ]& f: f. F8 V4 K( s, r - * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function0 k8 ]/ b+ D. C1 x6 Y; h. |$ H
- * must be called before.3 f* m! l) m" q1 H1 s
- * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access8 n: P# ` s: d; \3 u1 K) r
- * and Flash program erase control register access(recommended to protect ; D; Q! _& k* q
- * the DATA_EEPROM against possible unwanted operation).
% c$ l- P; ?0 O: U/ u, t$ U - * @retval HAL_StatusTypeDef HAL Status6 z; |* T% a* @' t% d e# i
- */( }! t$ i$ N/ G$ Z, _7 k* C
- HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)
# j0 l# Q' L. D. h& s7 @8 m - {! j/ I" o# S0 ~6 v- {) G
- HAL_StatusTypeDef status = HAL_OK;
& O- o' w1 U5 j8 e
; z: E0 j9 `" s- /* Check the parameters */+ n4 i# g1 w$ R( j: D" q
- assert_param(IS_FLASH_DATA_ADDRESS(Address));# e" U( h1 ^6 u3 L& @
- $ r9 L# \0 a3 j
- /* Wait for last operation to be completed */
6 I& C$ K' a# s& m% {9 S/ \+ N - status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
( g3 g( N5 i$ u, L8 S7 Z6 X0 B, j
2 ?. a, C8 G8 I( B- if(status == HAL_OK)2 s& q# x4 e5 w
- {# I7 W# [; \( M1 A6 Q% G4 g- L
- /* Clean the error context */0 |" Z# U0 S% m0 T! p
- pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
$ q; E, X) t) o( p8 n4 O% ] - % t- x* a F* `& l9 o; w
- /* Write 00000000h to valid address in the data memory */
& E1 h' Z. |, Q# [) a1 Z - *(__IO uint32_t *) Address = 0x00000000U;. ?4 d4 L; E, f0 ~
9 U/ e# Z" b. l$ y/ p# Y8 F% i5 J% n- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);; I- \' | R1 Y) ?6 f
- }* a5 @% b* S4 D7 Z( Q# `$ `
4 ~# w$ p+ A9 n; l9 i+ Y3 F% S2 {6 p& |- /* Return the erase status */
/ y, l0 Z6 W8 y- h( k3 k: |+ ^ - return status;
" e q! @1 ^9 m; k; r, u) n! L - }
复制代码 - [4 e1 t" @# [" c6 e1 ?3 s
上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。6 K* w' x$ o2 U, Y. ?
& j( ?' \( W; z( `. o' ?$ i
8 ]: ]+ K/ Y& c" r/ E& n3 c( r |