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

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   
    1 C8 ^1 X+ g( e3 x: P
  2. #define EEPROM_BYTE_SIZE    0x0FFF
复制代码
    以上定义EEPROM区的起始位置和大小,给定偏移量之后,可以按字节/半字/字/双字方式读出,但要注意的是最好偏移地址都按四字节对齐,以免产生总线访问错误或是取不正确:
  1. /*------------------------------------------------------------
    ) p' w* ]5 }3 D. T9 v0 V( j8 [
  2. Func: EEPROM数据按字节读出 0 m: I1 N. z9 R9 H
  3. Note: 4 e; m. d- o7 ~- r( v0 H
  4. -------------------------------------------------------------*/  * ?- b8 }4 V" l- j
  5. void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  $ y0 q3 ?2 O! T' P2 \$ h( r
  6. {  
    1 q. `" j, W- g$ g+ \
  7.     uint8 *wAddr;  2 [5 M6 z0 j$ _2 y( Y* }
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  4 G; R- g# t. {, W
  9.     while(Length--){  % f# B5 [  G, p, F" q
  10.         *Buffer++=*wAddr++;  
    4 K+ X8 a) W# }& m: I) K6 ?
  11.     }     . S. h! Y" s) h& K0 g5 b
  12. }  
复制代码
  1. /*------------------------------------------------------------: e2 g! `% l4 X
  2. Func: EEPROM数据读出, a+ q% g  @0 f* C5 z
  3. Note:% l! I( M- {& V8 a) Y- J$ g+ M+ J
  4. -------------------------------------------------------------*/  
    & r2 _; U- t" Z* k$ G- _
  5. void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)  
    ! `2 I4 L8 k3 O8 S/ W6 ^% _
  6. {  
    0 v) `4 ]; A' G3 P9 x& t
  7.     uint32 *wAddr;  
    ; o) r2 Y; j2 s* B) _
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
    & F, i. b" Y9 e( e6 d. Y1 v0 d" s
  9.     while(Length--){  * @; V$ h- T7 e* y4 D; a
  10.         *Buffer++=*wAddr++;  4 B3 A' a2 \3 ^' {
  11.     }     
    ' J6 v' o9 B$ `
  12. }
复制代码
    以上方法使用字节和字方式读出,在后面方法中,在一个字的存储空间内只使用了16个位,另16位不用,这样以避免产生对齐问题。

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

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

  1. #define PEKEY1  0x89ABCDEF      //FLASH_PEKEYR  / ^) R$ K* O3 L. {1 u
  2. #define PEKEY2  0x02030405      //FLASH_PEKEYR
复制代码
    以下分别实现按字节和字方式写入:   
  1. /*------------------------------------------------------------
    - K% ^- Q+ g& D" D8 h: ^* c( I
  2. Func: EEPROM数据按字节写入
    ; ?6 J- K4 H3 ^1 c$ S8 Q- n8 g3 W
  3. Note:
    - b& D2 K: F7 D: }
  4. -------------------------------------------------------------*/  $ G( l9 o! {  W. ^9 e& k
  5. void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  0 d" k+ e5 w- D* U
  6. {  0 Q( E" u. q$ i8 A" w$ B- k0 g& T& x
  7.     uint8 *wAddr;  
    " R# B7 w8 A3 j
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
    # c0 O  v0 t" j6 d$ Z4 q- R
  9.     DIS_INT  9 z2 Z' E; o1 S0 {$ X6 S0 s$ P, H9 v' A
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  ! n8 ?- o7 M, O3 E% P) K! p
  11.     FLASH->PEKEYR=PEKEY2;  . h3 f2 e: x! C. |- C
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    ! @: f$ L1 P  f  k' l$ P
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
    - s4 v3 A6 A2 v2 m6 c6 U/ a
  14.     while(Length--){  : \/ {5 s# j2 B/ ?1 _3 i
  15.         *wAddr++=*Buffer++;  - d- q6 X- {1 x
  16.         while(FLASH->SR&FLASH_SR_BSY);  8 _4 B0 L! K$ p; }/ n
  17.     }    H  J9 @2 @  s! ^' V% I
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  - `$ A0 B) A. X
  19.     EN_INT  $ }' ^, D3 K+ c, k
  20. }
复制代码
  1. /*------------------------------------------------------------6 p. J# z) Y2 G4 l5 s) F  k: }
  2. Func: EEPROM数据按字写入
    7 R" u$ l: e& E* g. M* G
  3. Note: 字当半字用
    9 e& l: h9 K0 o
  4. -------------------------------------------------------------*/  
    ' `8 N, v' e" V  J: g
  5. void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)  
    2 g! O% F" `* F8 E' j8 {
  6. {  
    ; G- S% G. _( g& D
  7.     uint32 *wAddr;  
    - v6 o) [- b3 y, f. [
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
    ; Y2 R1 D' m0 F5 _- D, [& S- ~& ]
  9.     DIS_INT  ! _2 e4 Y$ P  t' m# r) ?
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  
    5 I0 N5 |& P- u; S2 e3 S
  11.     FLASH->PEKEYR=PEKEY2;  
    " u% d% d( ?* |8 F9 I) @. U( A9 b
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    / x4 R: g6 O2 G" w( d* B
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  * F, X: ]6 I$ F; e+ b! O
  14.     while(Length--){  8 @2 N- `0 V( ]3 `, m+ q
  15.         *wAddr++=*Buffer++;  & h" b5 A  `& C' l5 A0 i5 ~6 G
  16.         while(FLASH->SR&FLASH_SR_BSY);  3 g) f. e2 E6 R- U3 k1 j9 {
  17.     }  
    1 O* Q1 [6 d  l8 m
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  : J9 q+ w, c& Y
  19.     EN_INT  " i( y! e) b  u
  20. }
复制代码

8 T6 P( u; V6 D& g    以上代码中,在写入数据之前先关闭系统中断DIS_INT,写入完成之后打开系统中断EN_INT,这样避免在执行写操作的过程中被中断过程所打断,引起CPU异常或锁死,在在使用中一定要注意。在MDK环境中,两个可以这样定义:. c0 u) y6 `( p( a9 q
  1. #define EN_INT          __enable_irq();     //系统开全局中断  
    : i1 g& L6 n/ f$ M& H: S/ z* O
  2. #define DIS_INT         __disable_irq();    //系统关全局中断
复制代码

0 w5 l) O0 h: i  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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版