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

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 {6 v* f  }  j2 H/ |
  2. #define EEPROM_BYTE_SIZE    0x0FFF
复制代码
    以上定义EEPROM区的起始位置和大小,给定偏移量之后,可以按字节/半字/字/双字方式读出,但要注意的是最好偏移地址都按四字节对齐,以免产生总线访问错误或是取不正确:
  1. /*------------------------------------------------------------
    3 L1 y  ^) p3 |# Y$ H& N& F1 z
  2. Func: EEPROM数据按字节读出 0 u' ?# w! L0 u
  3. Note:
    , m9 b) s9 C2 y/ X6 W
  4. -------------------------------------------------------------*/  ( x2 C, ]9 H: d6 e# E# ^
  5. void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  
    " |* }- T1 k& a5 v# j
  6. {  1 U8 w  J" V9 B- H
  7.     uint8 *wAddr;  
    ' g8 D3 \3 X3 @) ?: G% X5 a
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  6 `+ Z) V8 R' P8 q. j
  9.     while(Length--){  6 \9 i, C# h( K2 c
  10.         *Buffer++=*wAddr++;  + w; o& a4 K2 c' d; R: r9 E! O- t
  11.     }     : P! ]* b' L) y. G: B! n5 G
  12. }  
复制代码
  1. /*------------------------------------------------------------
    ! Y" M/ A0 C  }. t# f
  2. Func: EEPROM数据读出
    7 f) m6 a( f. _8 F/ a
  3. Note:% J, d) W+ Y$ \$ n1 S
  4. -------------------------------------------------------------*/  & u0 \, C, L2 m, V2 s
  5. void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)  
    7 a* {+ G, ~$ V: f8 F! ]
  6. {  
    6 S5 k0 t/ Y( g* U( e0 W# |
  7.     uint32 *wAddr;  
      ^7 Z- c" `+ g) c
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  " g, k0 \) x# M: T7 ]' t! k% p
  9.     while(Length--){  
    9 F0 R. b3 _/ L) d. @! d' a
  10.         *Buffer++=*wAddr++;  9 Z. ~3 e4 T  e% b
  11.     }     
    # V+ ?- F: V* o/ N1 J
  12. }
复制代码
    以上方法使用字节和字方式读出,在后面方法中,在一个字的存储空间内只使用了16个位,另16位不用,这样以避免产生对齐问题。

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

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

  1. #define PEKEY1  0x89ABCDEF      //FLASH_PEKEYR  
    & Z; m0 ~  u& D6 Z& }, W
  2. #define PEKEY2  0x02030405      //FLASH_PEKEYR
复制代码
    以下分别实现按字节和字方式写入:   
  1. /*------------------------------------------------------------
    . ?* E) c6 Q4 P# A4 O$ n
  2. Func: EEPROM数据按字节写入
    # O, I/ [- x8 ~* B0 r1 I! b6 E
  3. Note:
    : L4 ~0 d2 G1 a: q% A0 V0 J& h
  4. -------------------------------------------------------------*/  3 e& o2 N7 P( p( c' [
  5. void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  $ C6 D  q; a$ c0 p2 U+ W
  6. {  ! P3 m8 q( k7 r) j4 ]+ p5 U
  7.     uint8 *wAddr;  : p2 X0 N$ Z, k! `" s
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  3 t* g* i; e" H1 @
  9.     DIS_INT  
    " Y- b" h" n) l/ B7 [/ H" H9 d& t- m
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
    ) K6 X4 {$ \0 J+ C; L& V( z6 e
  11.     FLASH->PEKEYR=PEKEY2;  $ R9 J" |7 h. Z7 B" t
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    & m. Q) \9 u! C: `
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  / D9 c6 c  V. x
  14.     while(Length--){  
    ! Z- N% X% ~  P9 z3 W. M  G& t
  15.         *wAddr++=*Buffer++;  ) R$ |1 J$ n; Z9 ]7 Z0 q. v, B2 [
  16.         while(FLASH->SR&FLASH_SR_BSY);  $ P6 ^9 n7 B. M# i# Z5 x
  17.     }  
    ) v; D' J1 |- E( w7 f5 f1 |
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  ) A) ?# r8 ^+ H* I3 e+ Z7 S
  19.     EN_INT  9 z$ [' |; G' C; X1 w
  20. }
复制代码
  1. /*------------------------------------------------------------' X  J* z9 B2 ^$ ]/ K
  2. Func: EEPROM数据按字写入' |2 e+ t6 X( o0 g: m# n5 N
  3. Note: 字当半字用
    6 v$ e  s+ d9 N  X+ s! f. `
  4. -------------------------------------------------------------*/  
    2 y, U8 v! d) l  y
  5. void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)  $ f* Y* R' V. d6 T% @; r5 ]- X
  6. {  # e2 p. F; s5 Z: W. x9 Q
  7.     uint32 *wAddr;  
    5 f) w. C; a0 U! Y* G; M& v/ o
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
    : d, g9 }, \6 A/ Z
  9.     DIS_INT  " p: `7 A, A7 x! {6 s
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
    - s5 Q- j. L9 b* }$ F" Q! T
  11.     FLASH->PEKEYR=PEKEY2;  
    5 a( a/ p; U9 y  b$ Y5 D  u
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    0 I  N  a$ A" V. m" j) b
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
    $ d: e$ u' p# {, ]  ^  F
  14.     while(Length--){  
    ' Q0 m3 ?% M; n% U- r
  15.         *wAddr++=*Buffer++;  
      k: v6 @5 m: }4 ?/ L! s/ z6 \
  16.         while(FLASH->SR&FLASH_SR_BSY);  
    6 M: C) D: A+ p) y! y1 Y0 K9 p
  17.     }  
    7 y+ q7 @% e: ]4 z
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  
    1 G8 H4 S/ d3 N- A
  19.     EN_INT  
    # G; P( S! i) B6 u" ?
  20. }
复制代码
6 Q; |5 Y9 \; F6 z2 N
    以上代码中,在写入数据之前先关闭系统中断DIS_INT,写入完成之后打开系统中断EN_INT,这样避免在执行写操作的过程中被中断过程所打断,引起CPU异常或锁死,在在使用中一定要注意。在MDK环境中,两个可以这样定义:  p/ @4 \. z* ?2 i
  1. #define EN_INT          __enable_irq();     //系统开全局中断  
    & R5 v% C) V: N2 x# y; B6 Q6 V
  2. #define DIS_INT         __disable_irq();    //系统关全局中断
复制代码

/ ^' s* |3 s7 @5 p
收藏 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管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版