STM32L0 内部EEPROM写读: b6 O& t7 _( p9 J( G6 k6 Y$ I: D8 H4 g
说明1 T; r; P# I% L3 Z
STM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。" m5 p' H# j7 Z
8 }6 Z( T3 }& K& g& n8 z/ B
基础写读函数
; N5 e# R3 D' o ]定义内部EEPROM的地址空间:
" g& q4 j! b# u: n- //STM32L031K6T6
/ v6 W9 U( V/ p; V. N: M' |; _6 C; D - #define EEPROM_BASE_ADDR 0x08080000( H1 \& }0 s$ R9 B! n7 L5 L
- #define EEPROM_BYTE_SIZE 0x03FF
复制代码 ; v* Y% |! R2 }% ]: y
基础字节写函数
- |8 X. U3 @- w# S- //Byte write
* Y! D6 F* ` X/ z8 T/ H+ ~ - void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)* c4 m& U8 c) ^( J
- {- g8 O! S+ m+ S; S; Z
- uint16_t i;
9 @0 J/ ]! U1 s3 T+ n - HAL_StatusTypeDef status = HAL_OK;6 K, S: ? @' G
- 9 _0 @- _5 M5 }( e# L
- HAL_FLASHEx_DATAEEPROM_Unlock();* l' `% R+ l2 `4 Y
- for(i=0;i<len;i++)
: \9 Q) P3 E+ l9 L4 m8 B0 ^ - {' y: E2 h+ a, {
- status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);
9 L- e* ]+ q8 x# s - Data++;
! Q, F0 E( o- f' J - }( ~, d' ]% {; l# Q9 p
- HAL_FLASHEx_DATAEEPROM_Lock();( }+ U( A- ]8 h1 a- X. B" h
- }
复制代码 % {9 g! S) J9 h! [/ l' r7 h) q4 S
基础字节读函数
% O% E. D. a" ~9 S. }: K2 p- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read+ {9 }/ b4 G, I! I
- void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)' ]9 g! @% f+ y% O
- { n& P# W. i+ o5 A# T8 ?/ z
- uint8_t *wAddr;/ V8 W: W9 e2 W l8 F; J
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);
$ l" H( A2 O! v7 v# O - while(Len--)
) C% D7 |1 z- d2 I2 }5 a# u5 A- o, W - {
4 [# H/ W, x# `4 H5 ]' v - *Buffer++=*wAddr++;
; @5 S, Y# K( b1 e, F - }# D. T, t9 @3 s$ \! o
- }
复制代码 . u1 ~* s+ J8 ?6 j$ S+ A8 I
带校验写读函数* ~! L$ {* _; F: E
如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。" J4 V% i( h% C' v
对于写过程,需要将写入的数据,读回做比较。; d( n; L: i- P7 }, `2 a7 d, E& |
对于读过程,需要将两次读回的数据,进行比较。9 O) b/ e4 L5 r' m5 b
如果比较正确,则操作完成。% G# u e' K& ]) ]$ v+ _
如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。% ~& A& V. g% \* S& e T- `
9 z( m( e' I9 |5 f3 C7 | d) x
设定重复校验次数
8 _7 F$ H8 d1 o9 r: t- #include <string.h>
2 K5 i/ _6 V' i& @( D+ g% w- q+ J - #define iEEPROM_CHECK_NUM 2
复制代码
# |4 {" i' O1 x; j3 V, l" h: l1 r7 z6 K9 F
带操作校验的写函数/ p3 Q' B9 W: i4 @ }9 \9 M I: p1 S
- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)4 n' Y" _, N4 X) D7 X+ { w+ L. \
- {
b& N5 ^+ c" | @& B - uint8_t buff[len];
0 j% v6 P6 w# O) \2 Q# f& Q - uint16_t i;
" U% U! q: g) [! D$ j - for (i=0;i<iEEPROM_CHECK_NUM;i++)2 N1 o% c1 j' E: h, b' f
- {7 c& V/ W2 c: S( o% ]
- EEPROM_WRITE(BiasAddress, Data, len);
. l% L% ?8 T8 u: t- R - EEPROM_READ(BiasAddress, buff, len);
6 `6 \! ?% x1 @& b. o - if (memcmp(Data, buff, len)==0)
1 `! c( m8 _, N5 d& N3 H - {! S; S1 k+ e2 R% e2 |2 v- N0 O, s% O
- return HAL_OK;* C9 b2 f n, w
- }- V `4 s2 b& _! E
- }/ T% w* n, j$ z' s( T6 f; [
+ @$ g: e, s7 w& e1 ]. u1 s+ u( P- return HAL_ERROR;
! P( g: S3 N# I6 y8 Z1 S - }
复制代码 $ H* K7 m% d# r- M' S) }) R! Q! @
带操作校验的读函数
3 s; I0 C" R2 g- H* t- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
* X% a5 M+ J, T6 D" p - {
9 c& Q9 ~; s- v: N6 l - uint8_t buff0[len];; X- R* H. X# S+ D! l: o
- uint8_t buff1[len];
7 K# ?$ }$ p3 e0 i - uint16_t i;# W- n: \# d3 Q W
- for (i=0;i<iEEPROM_CHECK_NUM;i++) b ~2 |0 V% a6 |( d6 o. a
- {& [2 x) h% R9 t/ @9 K
- EEPROM_READ(BiasAddress, buff0, len);
4 I+ L1 K5 Y: g& o% x8 y: G - EEPROM_READ(BiasAddress, buff1, len);
6 c3 y& {% h0 V6 o - * \( V! j& N; H" o- `2 |
- if (memcmp(buff0, buff1, len)==0)
# ?4 E2 \! r1 E5 p - {$ Y2 i. h9 D/ d. G& k
- memcpy(Data, buff0, len);4 Q7 o8 P q9 a& f* ]2 p4 |) F: n$ G
- return HAL_OK;
7 k& S% ~' Y% R7 N - }7 A& n* r- @' J1 C; B, w
- }
% }7 I1 i. J3 K. i6 |2 y( I
1 W3 ]' d# Z$ G2 {6 D- return HAL_ERROR;# d* j5 W0 s4 M) V$ S5 u" n
- }
复制代码 ; I$ t% ~* o+ c! }: v1 ?
其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。' D; m3 A$ V' l8 \+ M- I9 Z
+ N9 _+ n8 w$ l+ i8 `, P4 j! w+ O需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。) y. ?7 V0 b5 C1 W% _
1 s; e9 k( U0 k" Y+ b. uHAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:
" U5 d7 v$ D' h7 c: }: J7 ]! b# D0 @2 ], q1 L" M6 _4 a! `
- /**" @& P) {8 Z# F0 u7 I0 k7 A
- * @brief Erase a word in data memory.
9 J/ O5 A* f# J! u% D! |+ W, D - * @param Address specifies the address to be erased.
4 Z/ u9 R1 Z( R3 n" [ - * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function% M. H$ |1 D, r
- * must be called before./ D% V- S( j' g+ Y
- * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access
4 ~8 w% ]2 a- A! F$ N - * and Flash program erase control register access(recommended to protect
3 ]2 w- V# G/ T9 U - * the DATA_EEPROM against possible unwanted operation).
7 L, K, T6 U9 k! V4 A* B: `% b1 d - * @retval HAL_StatusTypeDef HAL Status
, \* m6 N4 w. ^3 H* G i - */
$ x$ Y; M1 k$ ~% h; C0 ~$ X, B2 B - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address)
$ z; n3 g q7 _2 \$ u2 Y - {
7 l' v5 K N& w8 s; V' @/ A - HAL_StatusTypeDef status = HAL_OK;' W: E2 I7 K; |- w. G8 s/ O: h
- 7 w$ t9 S' t7 H' e& @/ l9 V
- /* Check the parameters */
/ M: I$ @7 }* P) d( C - assert_param(IS_FLASH_DATA_ADDRESS(Address));: W) p0 T4 F* u
H) g" M3 [4 q: {7 p- /* Wait for last operation to be completed */
% b& h% o+ _5 x- p - status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
g2 b( I# K* n3 n: r - 5 e3 o* S% W5 N4 \3 F% z
- if(status == HAL_OK)
) k( r% v! [0 e$ c - {
; h @" e5 E4 C1 k& O6 u, d - /* Clean the error context */
$ X8 t# F! ?' e) h! I- ]# N - pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;: l. j! [1 s" q4 Y# E+ V/ T
- # n( o, F b5 q, Z4 j
- /* Write 00000000h to valid address in the data memory */9 T' J4 G W/ u- p
- *(__IO uint32_t *) Address = 0x00000000U;
; E! @7 i1 R) K$ S5 [5 P& D
0 ^, J+ n9 P r* B1 k6 ]% G# V- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);; `( E1 a" i# W, |7 K
- }
$ Z* m, G0 I, \ j2 H - 7 P* E( y6 H; X' \0 n9 W
- /* Return the erase status */
* Y2 d- F0 \) m" T+ M( r" V - return status;8 V# }5 I& G# [. k) n
- }
复制代码
% s# C" ^4 _8 ^1 p: l; M: h9 L上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。
2 x" J$ e0 Z) i, r4 f9 c$ x
/ @! @1 I& I ~: L
8 T, Q J8 Z7 C) w9 m" C |