你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L系列内部EEPROM读写说明

[复制链接]
yuxin-366840 发布时间:2016-6-30 10:16

    STM32L系列单片机内部提供了EEPROM存储区域,但实质上,其FLASH也是EEPROM类型,只不过有一块区域被开放出来专门用作EEPROM操作而已。STM32L的EEPROMSTM32L使用寿命设计为100000次擦写以上,容量为2K-4K,这对于一般设备的参数存储来说是非常理想的。但从EEPROM使用方式看,其不适用于被反复修改的数据存储使用,一般作为配置参数,其修改次数往往是比较少量的。

    STM32L的EEPROM和FLASH是统一编址,操作共用同一个读写电路,所以在EEPROM读写的时候STM32L核对于FLASH的一切访问和操作都将暂停,只有当EEPROM的操作完成后,才继续执行后续代码,在这期间只有EEPROM的读写电路工作,CPU处于挂起状态。

    读操作,和FLASH以及内存一样,EEPROM的数据读取直接用总线读周期读出即可,不需要进行额外操作和设置。

  1. #define EEPROM_BASE_ADDR    0x08080000   
    6 t8 m+ g& f, O; I) u; x1 L
  2. #define EEPROM_BYTE_SIZE    0x0FFF
复制代码
    以上定义EEPROM区的起始位置和大小,给定偏移量之后,可以按字节/半字/字/双字方式读出,但要注意的是最好偏移地址都按四字节对齐,以免产生总线访问错误或是取不正确:
  1. /*------------------------------------------------------------
    ; @! ^1 o9 h# K. {
  2. Func: EEPROM数据按字节读出
    % y# u1 t2 o% m( d
  3. Note: $ k% A9 d( y% a3 |4 d- j2 N! H
  4. -------------------------------------------------------------*/  
    8 L) x# S1 _4 ?
  5. void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  : M! f* t, S1 f- O4 h/ b- C
  6. {  
    $ t7 F) \, t+ V) i' l$ t' |* ]
  7.     uint8 *wAddr;  / E+ |8 @) J9 x+ q
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
    : f$ |5 c# f4 T
  9.     while(Length--){  9 U$ P* Q( s4 ~9 _0 w7 I# R
  10.         *Buffer++=*wAddr++;  
    ( g+ c& [( u( L; Q6 U$ Z
  11.     }     ; Y1 X8 f; _6 i% D& A
  12. }  
复制代码
  1. /*------------------------------------------------------------
    ) ]3 L9 e4 S7 z) o
  2. Func: EEPROM数据读出% q' `5 Q. y4 ~; O, N0 ^2 P' u  r
  3. Note:1 ~* X  N- Z! d6 d4 f% [; o
  4. -------------------------------------------------------------*/  : ?) a6 o% R: G* t+ i1 g
  5. void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)  : ?1 z8 g* r/ j$ O- p; t/ k7 l
  6. {  4 w" `1 Q) ]6 _3 B& c5 R
  7.     uint32 *wAddr;  2 Z$ t& V9 K0 O  _- Y7 x
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  9 q4 o. J9 x- t9 b; Z  S+ S1 K
  9.     while(Length--){  % X8 t7 E" M2 S1 A3 U+ \
  10.         *Buffer++=*wAddr++;  
    ' J+ W; v1 h. O$ P
  11.     }     
    . ~! v2 j+ s5 Y, [  S" V7 E
  12. }
复制代码
    以上方法使用字节和字方式读出,在后面方法中,在一个字的存储空间内只使用了16个位,另16位不用,这样以避免产生对齐问题。

    EEPROM的编程比读操作要复杂的多,本质上来说,擦除操作和写入操作是一样的,擦除只是在相应的地方写入0x00000000,但在STM32L的实现上,根据其手册说明貌似把这种擦除和写入区分开了,当写入0x00或0x0000或0x00000000时,自动执行一次擦除操作,在值为非0时,才执行一次所谓的写入操作。数据的写入过程先要对EEPROM进行解锁,这通过对特殊寄存器写入特殊序列实现,然后在写入之前进行擦除操作,其擦除是按字/ 双字/页进行的,推荐使用页擦除方式进行,先把参数读到内存,并修改,再进行页擦除,最后将参数写回,这种方式比较通用,否则很容易出现地址对齐或长度问题。在数据擦除完成之后,即可进行写入,每写一字节/半字/双字,都需要判断其是否写入完成,这和内部高压擦写电路有关,只有在上次操作完成之后再进行其它操作才有意义。最后,对EEPROM进行加锁,以保护数据。

    下是手册给出的解锁命令码:

  1. #define PEKEY1  0x89ABCDEF      //FLASH_PEKEYR  
    - x& Y1 g  B3 i: d2 p
  2. #define PEKEY2  0x02030405      //FLASH_PEKEYR
复制代码
    以下分别实现按字节和字方式写入:   
  1. /*------------------------------------------------------------
    4 t) E# K. d! M) A4 J" E
  2. Func: EEPROM数据按字节写入& d" B6 {9 p4 {5 T! b( F: w
  3. Note:: @7 N- u+ j( ~) U* x$ J* i
  4. -------------------------------------------------------------*/  
    0 b( |( X. {8 H$ A9 k8 s$ l
  5. void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  
    6 F7 I: F4 g1 k+ N
  6. {  
    " z8 @+ _% }2 x8 {! y$ l1 c9 o
  7.     uint8 *wAddr;  
    0 b$ r# q2 G  e% P! K( j
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
    6 m: a- ~, v# L* ?$ j
  9.     DIS_INT  
    ( D1 z% W0 e( i% p. F$ B
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
    7 k! S9 b- N6 Y4 [% V0 A
  11.     FLASH->PEKEYR=PEKEY2;    _' U$ M- a( A5 X1 q7 v. ]& s
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    : m- s' g3 @' \* x, l% A, T
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  " F, Y+ I8 k$ _" j3 \
  14.     while(Length--){  . }# {3 `- b5 Z3 `3 ?% O
  15.         *wAddr++=*Buffer++;  
    ( ?6 t+ u+ e% I
  16.         while(FLASH->SR&FLASH_SR_BSY);  / ]$ h2 h1 @3 ?3 l& E
  17.     }  ! d3 _; W5 ~' a& a
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  ; ^5 F4 b0 {7 R% [+ b/ N
  19.     EN_INT  
    & a* t* Y/ r9 C" S) _" k3 f% ^
  20. }
复制代码
  1. /*------------------------------------------------------------3 i+ O7 H$ o, Y! n+ F% E
  2. Func: EEPROM数据按字写入
    4 W$ ]& d+ E* F. @8 K
  3. Note: 字当半字用
    8 ?3 a2 W. @; z# o* z+ z5 a
  4. -------------------------------------------------------------*/  
    9 [' B1 X4 _, ]# ]
  5. void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)  - n1 W& b, D) @4 b; X
  6. {  * \5 I9 f) ]% z4 g0 {2 ?
  7.     uint32 *wAddr;  
    - [- x: j. _, l
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
    8 X' K0 L$ }2 C3 A5 T( B' f: w3 |
  9.     DIS_INT  3 B5 W2 C9 g: R; k  V- i' \7 b
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
    ) I. x$ \" g2 x0 S( T
  11.     FLASH->PEKEYR=PEKEY2;  
    9 t9 |7 y0 u; x* A+ \. W0 A# H5 g
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    2 j; c) Z0 I1 G5 S, |1 G
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
    - S% z2 P. _9 P3 v$ z
  14.     while(Length--){  
    - c6 e" d/ ^" q; u, q* K0 Z. J& _
  15.         *wAddr++=*Buffer++;  & R" e- N  t3 `
  16.         while(FLASH->SR&FLASH_SR_BSY);  ' c5 i( `- G! Y6 n: s0 c' Z, A! {
  17.     }  6 w* I& ]+ H+ D$ H4 \6 ]6 S
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  
    ; q( S1 W% S+ W
  19.     EN_INT  3 ^" d: v& X6 i& l# A" b
  20. }
复制代码

: p# \6 Z( Q- C; A0 v    以上代码中,在写入数据之前先关闭系统中断DIS_INT,写入完成之后打开系统中断EN_INT,这样避免在执行写操作的过程中被中断过程所打断,引起CPU异常或锁死,在在使用中一定要注意。在MDK环境中,两个可以这样定义:% n9 ^- o+ |" g
  1. #define EN_INT          __enable_irq();     //系统开全局中断  
    4 R6 I7 z+ [# Z, s3 H# g
  2. #define DIS_INT         __disable_irq();    //系统关全局中断
复制代码
/ X, x. p# ~+ M2 b! L# c3 U
收藏 3 评论3 发布时间:2016-6-30 10:16

举报

3个回答
stary666 回答时间:2016-6-30 14:22:05
王浩然 回答时间:2016-6-30 16:40:33
谢谢分享
myfocus-2048857 回答时间:2018-5-29 09:01:29
好贴,收藏            

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版