STM32L0 内部EEPROM写读# w' S0 ]8 x" M" a; t% c
说明8 Z+ P; |+ }8 W8 ~' y) S1 F* m2 R; c
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。" l* c/ J: h# W2 V1 Z( }
' t& |( b' i# O# H# x5 Z% l
基础写读函数
" j/ Q& I& b7 I定义内部EEPROM的地址空间:8 I+ D6 j8 W4 e! v. A' z
- //STM32L031K6T6
- o+ p% Y) o7 V - #define EEPROM_BASE_ADDR 0x08080000- z% h1 B- A: H/ B% p
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码 " S/ L g( i6 m& L3 v
基础字节写函数
+ S" G# A, i3 t- u0 V& ?- //Byte write3 X5 A+ h/ [. l$ U
- void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
0 \7 |8 d! G5 ]$ ~0 y% P - {
% O6 G, Y. q+ z F - uint16_t i;
' Q9 | t5 p9 y$ e, ]) p! C. g - HAL_StatusTypeDef status = HAL_OK;9 X6 n* |; f+ {" E
5 ^: _# u% j% w2 u- HAL_FLASHEx_DATAEEPROM_Unlock();
0 {1 X! n: T. | - for(i=0;i<len;i++)- |" t; r6 u8 i, }4 }- e s
- {2 t. }! h+ l. O& p( n* r
- status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);! P) _1 F1 K9 T. `: h7 Q3 ]% w9 V
- Data++;! x1 ~& `! e/ p1 X0 G+ G
- }
0 B% H1 _+ t& J. g0 t - HAL_FLASHEx_DATAEEPROM_Lock();2 H% O* R! f, d9 h' a' A& J
- }
复制代码
+ _0 P% P7 i$ R5 S: B基础字节读函数6 ?8 J8 ~. |4 u1 s1 O! g
- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read, L; F& {( y+ X% ]8 ^8 i3 E7 p2 t/ u
- void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)' Q. X& |% Y% p. x4 j7 n4 d
- {: E$ u4 v: M; O2 T
- uint8_t *wAddr;) G4 m6 D% {- [/ {8 e; U! u
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);
4 |, z, d6 ?! H1 x7 U. L8 c- O+ r - while(Len--)
& i$ w+ T' O, F' L - {5 l, u8 V) m, w+ C: Q' s
- *Buffer++=*wAddr++;" `% D D6 I5 }- K$ Q" K8 s) d, K
- }
& R' P* J5 I. b# `: y$ ~ - }
复制代码
, Y+ h+ H7 V+ y3 L, A9 T f带校验写读函数4 K. S) h* V# x9 i: o2 M+ G: r: i
如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。, r2 s0 E+ s0 b0 l3 X7 b
对于写过程,需要将写入的数据,读回做比较。0 h( Y: K% R" K3 j# ]* Q
对于读过程,需要将两次读回的数据,进行比较。
3 u+ R5 u. Z7 S, J6 h如果比较正确,则操作完成。
# S( V2 \8 k8 Q: D如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。
. X' D3 B1 }7 g% f- i- X: \0 N5 p' ]# O$ ^: r7 g7 `
设定重复校验次数
. \! B9 ~2 q0 S6 C+ S) l- j- M- #include <string.h>7 o: ]3 ^- ?& D! j6 q6 W
- #define iEEPROM_CHECK_NUM 2
复制代码
2 f; S. ?- T8 ^4 Y/ o( X! M- j8 Y% D1 c% H i; E3 {& b P, |
带操作校验的写函数) J" x5 {0 c% Q6 r' [8 f/ _! T
- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
) _/ i8 l" \. x2 I' n' M - {
. G ?: e8 y( ~0 a4 D7 ? - uint8_t buff[len];
; w7 R" J3 S3 X$ A) } - uint16_t i;, a. M/ W' i. z' v" h
- for (i=0;i<iEEPROM_CHECK_NUM;i++) E0 N) V* o( P8 f+ d( O
- {
3 |9 G8 ], k# Y# n( C - EEPROM_WRITE(BiasAddress, Data, len);
/ B; l8 [1 a5 J8 r) }: A) @: t - EEPROM_READ(BiasAddress, buff, len);
5 J) H5 l/ r; a- \6 Q; a$ R5 Z+ t* G1 { - if (memcmp(Data, buff, len)==0)
; N; n! N6 `/ S' h7 k, N) c3 d# p- Q - {
! N( g% g5 M0 d% ] - return HAL_OK;$ r @( i* N* ^9 |* Q, Y
- }
! O; V/ t) x+ v0 N - }
9 P# m- |, |- ] - 7 _2 _! Y& r/ }! k' `
- return HAL_ERROR;) {& p% O; J: z- W
- }
复制代码 0 \9 `- N! }$ C& Y9 |8 u i% W
带操作校验的读函数
. G+ J+ Y5 _4 x4 T1 Z( I3 C- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
) y7 x' \0 ]1 T) s- E' V# |$ x4 F' A# h - {
; `4 ^) l5 F1 L$ k' y - uint8_t buff0[len];8 v/ L9 a/ Q8 Q) R
- uint8_t buff1[len];
3 c e" A, S4 t: w, j6 Q j - uint16_t i;
; R! Z$ F, g, O" A+ y5 T - for (i=0;i<iEEPROM_CHECK_NUM;i++): q% Q x. s1 B# ~) ]
- {9 W o2 K, W9 r; [7 w- s7 w0 U
- EEPROM_READ(BiasAddress, buff0, len);
- j7 u: ~2 {8 m6 ?; P - EEPROM_READ(BiasAddress, buff1, len);
. z& Z% f+ o. j$ r9 s, e
/ `6 e" D4 H" l- if (memcmp(buff0, buff1, len)==0)
" ^/ ^% M/ r) b3 P( }' \; g8 e, R - {; E( i7 M, w3 Y$ s+ F/ h0 t
- memcpy(Data, buff0, len);- T$ i8 K, o1 ^9 e* ]
- return HAL_OK;
: w r) V: R: [4 l; ?3 c - }
) [0 v$ ?3 |3 H; ^ - }/ [' \$ V3 G5 z) H# |6 \ y
4 w, V0 Z9 v' m2 v1 Z* `" S: }8 V: {- return HAL_ERROR;1 T$ `. X6 a) x0 l, R/ |, b
- }
复制代码 . d4 T# B& ?) Z& t( y/ E
其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。
- U- U7 e& O9 S8 B0 M6 S+ l5 @
* C8 Y8 B" B9 Q2 L. ^需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。
9 J4 S& S) w I1 C5 R6 ]2 [8 L8 j
HAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:
0 _8 b5 b" y& q# I3 e0 ^4 ?. \" J5 B, y
- /**$ l: K5 K/ H- T5 s$ C
- * @brief Erase a word in data memory.
( G$ _0 D6 O( m. o+ t# I& } - * @param Address specifies the address to be erased.
% z0 G* w! h- J* P - * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function
1 h% K+ C& b6 P, \$ h t - * must be called before.
5 @3 ^! O& z3 i( ? - * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access
2 x+ }2 @, C3 d) t! K4 @6 U - * and Flash program erase control register access(recommended to protect @, z" O7 f4 p+ z2 k
- * the DATA_EEPROM against possible unwanted operation).
1 w( P" \3 i" K - * @retval HAL_StatusTypeDef HAL Status. I8 n4 c$ q# N7 Z* D' Z- R/ x
- */
9 ?/ m. f* w5 I/ S& q1 D" }1 e; Q - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)6 [% S. Q$ @# y$ |2 F; C
- {1 { J2 b* ~( m _
- HAL_StatusTypeDef status = HAL_OK;
7 w3 S. k$ W- Y+ @% z. S3 {8 R - / {9 j d3 V3 `; `$ }) A
- /* Check the parameters */
) \) s. _2 q( U( X" d - assert_param(IS_FLASH_DATA_ADDRESS(Address));% ?- d6 W' ^. a7 V9 w: E
- ) A5 t) L7 S$ }: A4 H
- /* Wait for last operation to be completed */$ Z# M+ A8 y3 P. Q7 `: O6 `
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);. i# O* q9 x5 O: l, O2 `
" m. w2 u0 o% G+ A- if(status == HAL_OK)
- M k/ W; M* D0 G3 A. [' ?6 O. r( t - {, L2 C2 z( c5 }5 d: z2 t" M
- /* Clean the error context */
" @8 L y. H0 \$ \0 [/ L - pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
; H3 R' C7 W) X- B n6 ~; c g - 4 F- t, H9 p* N. x
- /* Write 00000000h to valid address in the data memory */& M8 F7 x$ ^. T6 L8 F
- *(__IO uint32_t *) Address = 0x00000000U;
1 ^1 z( K+ d$ ~& @. y9 C) H* `
: z( g+ d q/ i+ p9 i4 E6 Y- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
# T7 C7 F n; R& G9 w$ C# u, N& E- u - }
: M" t8 j) m7 x) z
' h" g; Z* Y+ q& [2 `) v- /* Return the erase status */ e. h% W o& Q7 k# l Y
- return status;
! w* E2 L2 T8 `0 V. Y - }
复制代码 5 Z' B- O! M1 X8 h) ^6 S
上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。
; i" T; k& u( N! i' f& @/ }5 ^3 S' d/ |" v( e# h
# \& X2 I4 L+ U% C |