STM32L0 内部EEPROM写读
/ z$ D! ] E* w说明
8 W5 H6 v' h( Z/ fSTM32L0内部的EEPROM写操作由解锁,写入,加锁过程组成,读过程则无需解锁。至于STM32L0内部的非易失空间区分为FLASH和EEPROM,主要体现在用ST-LINK等工具进行整片擦除时,只擦除FLASH的空间,EEPROM的部分不会被擦除,如同外部EEPROM芯片,MPU的代码升级不影响EEPROM的内容。后面以内部EEPROM的写读作为范例。
& X! k' a& y$ u
6 n. Q+ _, U/ ~9 M基础写读函数
- E3 z7 F; [6 [( R' v! c( x定义内部EEPROM的地址空间:
* b7 X. |2 y/ V$ ?6 k- //STM32L031K6T6
, ]2 c5 M6 }4 \# y Q - #define EEPROM_BASE_ADDR 0x08080000
+ P8 O$ L; b$ b5 C; C3 J- ^ - #define EEPROM_BYTE_SIZE 0x03FF
复制代码
4 P w" s: f% s" j# W# I; ]基础字节写函数) f* y: {, G( @. C5 H
- //Byte write& b% V, ? @" q$ ?2 x1 t
- void EEPROM_WRITE(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
/ U* [ C& G4 Q6 z/ b; M - {
+ i! e$ |+ j* S1 {/ n$ W+ {7 M Z - uint16_t i;
7 ?, h4 P% j' { - HAL_StatusTypeDef status = HAL_OK;: h) d k' z3 G
- / A/ _( S8 u2 E$ [; H j# `
- HAL_FLASHEx_DATAEEPROM_Unlock();
! {" v$ Z6 I+ l - for(i=0;i<len;i++)6 ]9 ~2 m8 L+ I, ~+ ?
- {
8 t- @. r1 r Q( g, D- {7 n+ ~ - status +=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, EEPROM_BASE_ADDR+BiasAddress+i, *Data);
, W2 D8 ~, D' Q' Z! Z9 r; b - Data++;5 q- w( I0 S& c8 S
- }
( r) W/ `8 h0 q4 R - HAL_FLASHEx_DATAEEPROM_Lock();
- k9 A# F d! W0 S - }
复制代码 ( M+ N0 b- y- [; L3 p' M
基础字节读函数6 G6 a, Z q0 \8 d# l8 o
- <span style="background-color: rgb(255, 255, 255);">/</span>/Byte read( X- o9 e' i9 P
- void EEPROM_READ(uint16_t BiasAddress,uint8_t *Buffer,uint16_t Len)
, p5 t' G$ Q" F) k9 d- X+ k - {) x* |1 k# e6 Y1 i, a
- uint8_t *wAddr;& o' x. s( a) k- K1 t5 g
- wAddr=(uint8_t *)(EEPROM_BASE_ADDR+BiasAddress);
- D: l! _. x: C/ F - while(Len--)
. g& y% o/ O. M/ {5 L - {
) a y& D! q5 h9 t$ r - *Buffer++=*wAddr++;
# Y5 b& P: l5 \8 t0 ]6 n* Z) a2 s - }
5 ~: `4 p" ]1 Y; \/ o - }
复制代码 . D3 T( z; t# U. }6 r6 J
带校验写读函数' Z6 n2 U+ `! f9 V1 V
如果考虑到写读过程中,可以出现错误的情况,为了保证操作的正确性,需要采用校验方式进行写读。' E) L$ z, G( t2 j8 U
对于写过程,需要将写入的数据,读回做比较。
; l' w' ~# D) Q1 k& W对于读过程,需要将两次读回的数据,进行比较。# Y4 E) E& ? f$ }7 G: X* [( F. y
如果比较正确,则操作完成。
' ]: i3 Y; c( m3 T如果错误,可重新进行写或读操作,并在设定的重新操作次数范围内,进行重新操作识别,如果正确,则报告正确,如果错误,则报告错误。+ [# e3 b9 g' M3 \/ M5 I5 p" z4 L* ^
& t8 ~- Y- P" l- m设定重复校验次数
6 d: ?6 q! g$ j) w6 p& K6 K, d- #include <string.h> |! v. d( f$ {$ g. H3 U
- #define iEEPROM_CHECK_NUM 2
复制代码 . ~/ s( I$ i# y; a/ p
; A7 n x7 d7 F* M* a. Q& ]0 Z
带操作校验的写函数
' b! ~2 Y$ i O- HAL_StatusTypeDef EEPROM_WRITE_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len)
+ f4 y# P. F7 ~# K; K - {
5 s) q- K2 M* \" _& {: o P3 K - uint8_t buff[len];/ U9 s% I4 m1 t9 o; _. z' Z# S0 B6 Y
- uint16_t i;
$ f# s7 O: P. u" N5 ^ - for (i=0;i<iEEPROM_CHECK_NUM;i++): i- v1 i( t8 m; d
- {& F0 _) l' q; C
- EEPROM_WRITE(BiasAddress, Data, len);
% W. O4 }) C9 p8 J8 t" g) Q& U7 l - EEPROM_READ(BiasAddress, buff, len);3 l+ o& |7 J. X9 j
- if (memcmp(Data, buff, len)==0)" L9 T1 Q7 C- M$ {
- {2 p: e% t0 a# S! W# ?( b7 Q
- return HAL_OK;
3 `" R5 o% c& l/ ], ] - }+ L1 r0 b$ ~6 v! Y" z5 J( ?
- }
( k m$ O+ p/ O7 {- q8 F: U7 h# Q
5 F7 g, n3 u' v; H7 {+ y1 C- return HAL_ERROR;
( P3 e$ g. T8 i* N - }
复制代码
* H- I/ r( C8 X# w; \带操作校验的读函数
+ |) i+ v4 p4 l/ Q- HAL_StatusTypeDef EEPROM_Read_W_CHECK(uint16_t BiasAddress, uint8_t *Data, uint16_t len): u) L5 U5 e8 {
- {$ m1 _) `8 R8 T
- uint8_t buff0[len];
0 O! P2 D! f9 `+ E6 B% @1 z - uint8_t buff1[len];( U; L$ U4 g |! o5 F& j* N
- uint16_t i;& J# U6 [1 `9 T" _% G6 t! ?
- for (i=0;i<iEEPROM_CHECK_NUM;i++)
0 h0 V, Z( D$ p: g% K4 g4 O1 r - {2 }9 {9 `- z, f" |' ~) i
- EEPROM_READ(BiasAddress, buff0, len);& G/ p6 h4 p. X2 ^2 i" X
- EEPROM_READ(BiasAddress, buff1, len);
$ k0 D5 s5 _) t0 y1 [" I
& ~5 c7 C* x, h) e0 {' J! |! M) ]- if (memcmp(buff0, buff1, len)==0)7 ?6 E5 z3 r$ A( ?
- {/ Y. [$ A) I2 B& z
- memcpy(Data, buff0, len);
5 T; B+ m l# \+ |4 z3 f/ h' \ - return HAL_OK;. e7 A% h' j, x( d
- }
5 e7 T% r3 c9 |( B z# S - }* t$ y: [1 \ @1 U
- 0 n( B$ }; C# {- J' U$ R
- return HAL_ERROR;
( b+ R/ G$ X. m4 Z; i - }
复制代码
, c I1 e0 N; ?3 \7 G' O' d其中BiasAddress为0对应内部EEPROM的0地址(EEPROM_BASE_ADDR定义了其基址),Data为数据字节指针,len为操作字节长度。
' T! ^3 q2 \8 ~3 p: ]2 A/ \9 }, ~/ g$ ?) G0 Y% ~
需要注意的是,基于工艺制程和设计,EEPROM的使用也分为两种,其中一种和FRAM相似,可以直接进行写入而不需要提前擦除,STM32内部的EEPROM也是这一种;另外一种和FLASH相似,需要先进行基于Page的擦除后才能正确写入,对于有的EEPROM,支持基于Page最小为Byte单元的擦除。
* i S! ], l+ _, }! F6 _; G# M1 |7 o6 n) `4 W
HAL提供的内部EEPROM擦除函数, 只是进行一个word的擦除,即在某个地址上将数据改写为0x00000000, 和直接调用写函数在该地址写入0x00000000效果一样。HAL的内部EEPROM擦除函数如下:
. `$ K4 K8 r+ d' G0 t }8 J- R* Z! V' p# P. B7 n/ r& Q- F
- /**
6 p* E7 b0 Z4 {) E3 U - * @brief Erase a word in data memory.
8 I& x' ]; C% h - * @param Address specifies the address to be erased.
6 a4 k7 O, i& m+ j$ }5 J2 q - * @note To correctly run this function, the @ref HAL_FLASHEx_DATAEEPROM_Unlock() function
% A( k( g ? m) t - * must be called before.8 c5 z2 d+ {) q! K/ F8 Q& x
- * Call the @ref HAL_FLASHEx_DATAEEPROM_Lock() to the data EEPROM access% o9 p. i# I" ] u
- * and Flash program erase control register access(recommended to protect
* K& J4 G# H( I* y# I - * the DATA_EEPROM against possible unwanted operation)., h7 g/ B+ [$ e+ K& ~
- * @retval HAL_StatusTypeDef HAL Status. R! h- O+ M! [2 a! N" f3 s
- */
+ ?, Z7 H" h3 ]7 Y( ?4 O9 Q - HAL_StatusTypeDef HAL_FLASHEx_DATAEEPROM_Erase(uint32_t Address); D! H2 n3 g+ R, J
- {4 F# H% x% e6 n5 _" Q& S
- HAL_StatusTypeDef status = HAL_OK;
6 l J% \) ^5 f* b b* h/ ^
" I1 q" @6 ?* ]7 U6 o$ i+ l- /* Check the parameters */* m$ F7 f7 D, }+ z) [7 M; G
- assert_param(IS_FLASH_DATA_ADDRESS(Address));
/ O" W8 x" j6 t# @2 ]
; v5 K' @4 y6 V4 A5 j- /* Wait for last operation to be completed */ r6 t3 z$ V& k9 @. T; L
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
" }0 d- ]1 Z: P; v2 ]$ D9 v; h - ' S2 Z N! V0 q1 n% Y/ P& B7 i7 b
- if(status == HAL_OK)
# K: h4 r3 O3 `$ B5 { - {- W! U$ C( P' o0 j: M: C
- /* Clean the error context */
/ @4 A# R- ~( ~1 d - pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
( @5 d0 K1 L2 _7 E8 [# _ - ' |' }5 ~5 |1 a$ W) T
- /* Write 00000000h to valid address in the data memory */
: [" _0 z7 l0 l/ a6 G3 i. U - *(__IO uint32_t *) Address = 0x00000000U;
8 D9 j& h3 \& q% N. X - 2 D6 g& z8 i5 `! O' z: u
- status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
* ]8 B) s4 f7 C6 j - }$ `# n; e t- q3 [
- $ Z/ c" q; o0 }
- /* Return the erase status */
) J8 r. d! Y6 T# P; M/ X4 x - return status;
( {, d7 p: L( a, ?% L - }
复制代码 ' B3 }4 w. }1 d( t9 I, v- y
上述的代码,如果要用于STM32内部FLASH的操作,还需要增加页擦除操作。1 [' K2 O) p. [2 e
! h' r5 Q( ~- t1 Q/ V# P8 j9 ?9 D
|