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

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   
    ; x- C9 B' A' \* R
  2. #define EEPROM_BYTE_SIZE    0x0FFF
复制代码
    以上定义EEPROM区的起始位置和大小,给定偏移量之后,可以按字节/半字/字/双字方式读出,但要注意的是最好偏移地址都按四字节对齐,以免产生总线访问错误或是取不正确:
  1. /*------------------------------------------------------------ 0 r. S4 V& x& H  `+ u" u8 j# w
  2. Func: EEPROM数据按字节读出
    $ J8 x# b- Z$ b0 `% k7 r$ r
  3. Note: : ^2 f; A! D- @2 _" k% I
  4. -------------------------------------------------------------*/  - q: @; G% j9 B5 W& z
  5. void EEPROM_ReadBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  ; K# b* A; M9 W3 y3 }
  6. {  ; |8 a0 q( t" d
  7.     uint8 *wAddr;  , {% H5 G' c) ?! Z
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
    ! B( G' }! k5 G( o# ~8 j
  9.     while(Length--){  
    3 Q, l9 j+ Q2 e: c# a
  10.         *Buffer++=*wAddr++;  . P0 a; G+ A3 A, [9 N
  11.     }     : M5 q- C: X3 @7 D1 j3 `9 k
  12. }  
复制代码
  1. /*------------------------------------------------------------
    , K: `0 e" K* y! b" @  k
  2. Func: EEPROM数据读出5 o- E4 G0 H. F  |% Z, Y; q: N6 [
  3. Note:$ ?, ]4 a7 D' O0 g
  4. -------------------------------------------------------------*/  7 e/ d1 @( A6 \. w8 I$ ]
  5. void EEPROM_ReadWords(uint16 Addr,uint16 *Buffer,uint16 Length)  7 G, c# J  ]: F1 R) T6 p, t/ x( T
  6. {  5 y- V" Q2 U5 F: |$ b) ?: N
  7.     uint32 *wAddr;  8 Z& q- Y' \. e3 o+ G! s0 _5 ^
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  8 l# }( g. C  Z% X
  9.     while(Length--){  
    % }+ f2 {4 l0 p' l
  10.         *Buffer++=*wAddr++;  2 h/ E" |7 Z- W8 O
  11.     }     
    3 m; {* x& E  t- P, f$ b2 c  l
  12. }
复制代码
    以上方法使用字节和字方式读出,在后面方法中,在一个字的存储空间内只使用了16个位,另16位不用,这样以避免产生对齐问题。

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

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

  1. #define PEKEY1  0x89ABCDEF      //FLASH_PEKEYR  
    4 q+ V* U+ Y! c& @; S! k
  2. #define PEKEY2  0x02030405      //FLASH_PEKEYR
复制代码
    以下分别实现按字节和字方式写入:   
  1. /*------------------------------------------------------------) _" y5 B: d) U- ~0 W4 g# I
  2. Func: EEPROM数据按字节写入/ R# M- q& u  F- ?  `
  3. Note:
    7 t0 f5 J, r- A: O7 e, W
  4. -------------------------------------------------------------*/  
    2 X  Z* O% Z4 r. `* Q
  5. void EEPROM_WriteBytes(uint16 Addr,uint8 *Buffer,uint16 Length)  
    3 g3 K5 g  [* T/ |' k- p
  6. {  
    2 Y5 f4 F0 f/ ^# ?% S6 _4 H% K
  7.     uint8 *wAddr;  
    1 p6 ~; W! y8 t  T" q$ M
  8.     wAddr=(uint8 *)(EEPROM_BASE_ADDR+Addr);  
    , K5 W5 i, [/ r/ e6 L6 E
  9.     DIS_INT  
    8 O1 S, c0 P9 \1 Y; q; S
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  % N: F# Z8 |3 M
  11.     FLASH->PEKEYR=PEKEY2;  
    4 f7 u- b: n* o1 M# ~% b2 X9 f3 W
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    5 B% w0 e% C! ?% r
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  ' N3 |- u& u1 s) e, _
  14.     while(Length--){  * {  u; A6 w- I2 h' P' G
  15.         *wAddr++=*Buffer++;  
    0 a0 A9 M! q- U$ d. P
  16.         while(FLASH->SR&FLASH_SR_BSY);  - L3 [7 i" I: g8 `2 m! {
  17.     }  
    2 B+ e$ w- {$ G# M" F& D
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  
    6 u% N7 o9 `& \
  19.     EN_INT  
    3 u% P3 T/ |* a
  20. }
复制代码
  1. /*------------------------------------------------------------
    ! [- J, @: A0 p2 l' [/ k7 Y
  2. Func: EEPROM数据按字写入: H/ C# p# I: A* p( A
  3. Note: 字当半字用
    & i) C/ p  ~& D
  4. -------------------------------------------------------------*/  
    ' z$ [: h$ A& g& z' k- I
  5. void EEPROM_WriteWords(uint16 Addr,uint16 *Buffer,uint16 Length)  & }5 K6 c; p( h9 L' x; i
  6. {  
    ( B" u7 G8 P8 I# f
  7.     uint32 *wAddr;  ) ]8 G( {  K0 G% |: P! ~
  8.     wAddr=(uint32 *)(EEPROM_BASE_ADDR+Addr);  
    + G7 e" C+ }3 [$ k5 ^5 x
  9.     DIS_INT  
    % o5 j, p' j. Y5 [
  10.     FLASH->PEKEYR=PEKEY1;                //unlock  6 N6 _' y  d- {+ |, y
  11.     FLASH->PEKEYR=PEKEY2;  4 ~$ S8 G- A  M8 m( ^& |
  12.     while(FLASH->PECR&FLASH_PECR_PELOCK);  
    1 t9 t9 g$ E9 M
  13.     FLASH->PECR|=FLASH_PECR_FTDW;        //not fast write  
    % b/ f3 z8 E+ s# \
  14.     while(Length--){  
    ; {5 s5 o* X5 j
  15.         *wAddr++=*Buffer++;  
    ! j' e( ~( J8 N) f
  16.         while(FLASH->SR&FLASH_SR_BSY);  
    9 }. Q1 P  g8 f! R7 D: ?: P
  17.     }  
    ' i7 m5 R8 Y" }$ V9 @/ c
  18.     FLASH->PECR|=FLASH_PECR_PELOCK;  ( f; d% z0 n: _
  19.     EN_INT  # V! _2 N9 }; l1 p& C* y
  20. }
复制代码
7 e; S& w" o7 _: j6 d( Y
    以上代码中,在写入数据之前先关闭系统中断DIS_INT,写入完成之后打开系统中断EN_INT,这样避免在执行写操作的过程中被中断过程所打断,引起CPU异常或锁死,在在使用中一定要注意。在MDK环境中,两个可以这样定义:5 u- Y$ _7 }# ~. @$ B0 A
  1. #define EN_INT          __enable_irq();     //系统开全局中断  . ^1 D9 n! v. F+ x
  2. #define DIS_INT         __disable_irq();    //系统关全局中断
复制代码

9 L4 B8 f6 S" S  L" h6 j9 d/ I
收藏 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 手机版