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

STM32CubeMX + STM32F407VET6读写AT24C08的实验

[复制链接]
giveup 发布时间:2016-5-30 19:31
本帖最后由 giveup 于 2016-5-31 08:03 编辑 # y8 D  l! Y! F, w& n" `1 S8 G" A

4 [4 t7 J3 N  U  \  |采用STM32CubeMX 配置一块STM32F407VET6的核心板,通过I2C1读写AT24C08 EEPROM。可以选择BSP方式,或者到HAL库中挑选BSP驱动,效果一样。因为我的工程已经初始化过了,所以采用后种方式。/ }0 W" w8 o, Q9 u
采用默认值配置I2C1,选中NVIC Settings中的 I2C1 event interrupt和 I2C1 error interrupt。生成工程模板。将AT24C98N EEPROM连接到PB6,PB7。器件A0,A1,A2引脚悬空,地址为0。. E% r% m. t1 y
在安装库中复制eeprom的BSP驱动,应该都一样。如复制下列4个文件到工程目录下:
/ ^# u) b) K& O) X5 H1 t9 ZSTM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.c
, a. M! j; H' v! M7 ]7 ~# j* a, qSTM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.h
# x( J% _9 Z0 e# U9 P' W$ o, M" ]STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.c' |9 s$ C+ k, }% k- I0 p
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.h  a( Q' j9 o* g( |, G
8 A# G+ f. D4 ~
stm324xg_eval.c和stm324xg_eval.h中保留和EEPROM相关内容即可。2 b) }. L1 {: N0 z
% c" {% R; A" w
重点的问题是,这个驱动支持的是M24C64 EEPROM,和AT24C08 EEPROM有一定差异,需要修改部分内容才能使用。主要体现在读写页面尺寸、容量和器件地址表示不一致。
* z, j  u& t) J) o- L3 a, p6 e4 E6 `根据手册,AT24C04~AT24C32的内存地址是分为两部分,除低八位外,高3位占用了器件的地址。如AT24C08,内存大小为1024字节,地址为10位,高2位占用了器件地址A1,A0。M24C64 EEPROM的内存地址为16位,和AT24C32以上的EEPROM保持一致。
- x& C4 @; e0 T, J& f& H6 j5 U因此,主要修改点为:" N' m+ }1 ~1 M5 H$ v1 o
1。修改页面尺寸与地址大小 & J& x1 d- k! j/ D1 o6 B+ w
stm324xg_eval_eeprom.h中,修改定义:+ H' Y+ Z. I1 D0 h- S+ T% A. N, R2 w
#define EEPROM_PAGESIZE             16' Y6 T5 Q* r+ A7 }* B0 f7 H9 Z, r3 O
#define EEPROM_MAX_SIZE             0x400  /* 8Kbit */
4 j$ ?3 Y* y" O. l% S添加定义
8 G* U$ F/ H1 J  }, u( M#define EEPROM_MEMADD_SIZE         I2C_MEMADD_SIZE_8BIT
: y; C! |7 y$ l; s7 i4 H% B+ [#define MEMADD_MSB_MASK     0x3- m* \1 R7 r1 U. f" }- ^" M3 j
2。修改读写函数* ~; ~) o" D% `5 T
2.1 读操作部分修改逻辑:
: J- A2 d' e$ c5 T7 b该部分的逻辑是 BSP_EEPROM_ReadBuffer 经过 EEPROM_IO_ReadData 调用I2Cx_ReadMultiple完成实际读写。
& D! Q% T: u) N/ B0 h因为读函数采用连续读方式,只要设定了正确的内存起始地址,就能正常完成读操作。因此,修改只涉及到BSP_EEPROM_ReadBuffer和EEPROM_IO_ReadData两个函数。具体修改如下,红色部分是增加和修改的:
/ h" T6 i3 D( M8 {
  1.     uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) {
    ! ~2 d0 g8 E4 Q- P5 m' G! i/ Q
  2.     uint32_t buffersize = *NumByteToRead;
    / k- u& {( }$ D4 P9 K' e
  3. 4 S4 [6 G" M2 p
  4.     /* Set the pointer to the Number of data to be read. This pointer will be used
    % O+ S+ x9 s' m1 H: b' w) T
  5.      by the DMA Transfer Completer interrupt Handler in order to reset the $ ?& ~( U5 t" k5 H
  6.      variable to 0. User should check on this variable in order to know if the
    / h5 A9 v; O2 |: G
  7.      DMA transfer has been complete or not. */
    1 C, C& P1 A: c
  8.     EEPROMDataRead = *NumByteToRead;( Y9 t. N8 g- v3 U
  9.     <font color="Red">uint16_t A_EEPROMAddress = EEPROMAddress;# g: w, }1 y$ E0 A# [4 l! Y
  10.     uint8_t A2A1A0 = (uint8_t) ((ReadAddr >> 8) & MEMADD_MSB_MASK);8 [/ k$ v& O# F% G  o
  11.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>$ y! E, M3 I* y# V1 N' e
  12. . j* {9 r) W; o( U* V
  13.     if (EEPROM_IO_ReadData(<font color="Red">A_EEPROMAddress</font>, ReadAddr, pBuffer, buffersize) != HAL_OK) {
      k  w+ }9 P) }  A6 W6 y+ |" d
  14.         BSP_EEPROM_TIMEOUT_UserCallback();
    $ E' A4 K1 m/ i" P; I) @
  15.         return EEPROM_FAIL;
    1 Z) d$ G/ P7 O) G- r
  16.     }
    / T* E2 ]- u: W3 `' r
  17.     /* If all operations OK, return EEPROM_OK (0) */
    ! ^4 g# {6 M1 j7 z+ C1 v
  18.     return EEPROM_OK;7 d* m! E, l$ F8 m. h8 j% F0 }( q8 g
  19. }- F6 V$ f# G' M
复制代码

: ?, a" f9 L! J$ H, s. M将I2C_MEMADD_SIZE_16BIT替换为上面新增加的EEPROM_MEMADD_SIZE定义:, h" }/ s+ M- F& b0 {
  1. HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)* K9 e% p8 C- [) V0 }$ D7 Q3 ~, r
  2. {
    / Q7 u+ S! U. o$ J% Z% m
  3.   return# D5 N& `5 c$ j
  4. (I2Cx_ReadMultiple(DevAddress, MemAddress, <font color="Red">EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));
    $ [! R, C& r; o
  5. }
复制代码

5 _! M) M1 z9 T( c$ Z+ o9 N% E& r, N0 ~' }! x$ |2 g
2.2写操作部分函数修改逻辑:
; @0 [4 X8 s6 ~# M# S写操作调用关系是BSP_EEPROM_WriteBuffer负责将写地址分页,并完成页面对齐后,调用BSP_EEPROM_WritePage经过EEPROM_IO_WriteData完成实际写操作。修改部分只涉及到后边两个函数,具体见下面红色部分:! _+ s& e5 X, O$ e, {; l( i
  1.     uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) {$ B  x2 Q! n' U
  2.     uint32_t buffersize = *NumByteToWrite;
    $ _% x, H- \" N. H
  3.     uint32_t status = EEPROM_OK;
    ; P5 j9 h2 \' A' r+ y9 b: T

  4. , x. X+ ~5 I' l% S7 g. k
  5.     /* Set the pointer to the Number of data to be written. This pointer will be used* ^$ f8 Y. Y* Y: K7 }6 O
  6.      by the DMA Transfer Completer interrupt Handler in order to reset the
    , P/ O$ Q0 y: n& ?+ ^8 M$ b: `
  7.      variable to 0. User should check on this variable in order to know if the' `, h+ C3 @. j3 O6 @
  8.      DMA transfer has been complete or not. */6 E0 k7 p! C7 C1 x; b8 ~
  9.     EEPROMDataWrite = *NumByteToWrite;
    , p9 S7 [  ?4 H- e% D' F# M
  10. 4 ]1 W# C$ P' j* p) H! s9 a
  11. <font color="Red">  uint16_t A_EEPROMAddress = EEPROMAddress;
    - G0 j! {6 Z4 o. X2 V8 z" ~/ ]
  12.     uint8_t A2A1A0 = (uint8_t) ((WriteAddr >> 8) & MEMADD_MSB_MASK);& g; [, v4 B& K' f7 W, s
  13.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
    % {+ r& A( m5 S/ e9 |; q2 P+ n
  14. 8 ]; {6 I  ]& Z
  15.     if (EEPROM_IO_WriteData(<font color="Red">A_EEPROMAddress</font>, WriteAddr, pBuffer, buffersize) != HAL_OK) {; M/ h6 `$ e& g/ Y* e
  16.         BSP_EEPROM_TIMEOUT_UserCallback();
    2 X' h: @5 m0 z/ R' `5 F2 w' D
  17.         status = EEPROM_FAIL;
    7 D% \& J% H! a8 W
  18.     }4 y7 w) x1 ~4 a2 P$ n

  19. 3 s. q# P- d+ g
  20.     if (BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) {
    ! x$ A5 a. s+ m3 k) T
  21.         return EEPROM_FAIL;
    : Q  j# F1 V5 X* P
  22.     }/ r: b7 ^; c; Z% l0 _& I
  23.     /* If all operations OK, return EEPROM_OK (0) */6 E* U. X( g% Q5 E# e; L
  24.     return status;6 v  k: V6 ]: g8 m  V+ d: J% [6 k
  25. }7 k: {+ |$ J* ]$ o) R
复制代码
. \7 C8 t0 X" B* r
具体写操作修改和读操作差不多:6 l! v; w( a) [. Q9 Z! \
  1. HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
    # K% e  A# t2 x$ k7 U& n
  2. {# C0 l4 S9 G8 {* C2 H. Y
  3.   return% o0 m( n# @$ V3 u7 v
  4. (I2Cx_WriteMultiple(DevAddress, MemAddress,<font color="Red"> EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));
    0 u' n9 h+ ~" b" n9 J- {
  5. }
复制代码
0 n6 g* n' B" w6 c% F4 U: @/ t" J

5 y6 e* s$ y9 Y3 n3. 初始化及其他操作修改。STM32CubeMX已经正确生成了初始化代码,因此除了下面的两个,大部分BSP的初始化代码都可以删除。
6 F4 C" {2 s4 U, z* [8 T: U5 J
  1. void EEPROM_IO_Init(void)
    - r: J3 [1 T% n
  2. {8 l$ w  O% w+ Q! n, t
  3.   I2Cx_Init();
      g. F5 Q3 U4 H5 m6 ^
  4. }
复制代码
修改为MX的初始化代码
% [) a$ b  P! K' B  {1 _: x
  1. void EEPROM_IO_Init(void)
    . `" j3 _4 g, |1 w: T
  2. {& R; l" Q0 W6 q2 u
  3.    MX_I2C1_Init();7 s" u0 G0 U) V2 r2 L3 N
  4. }9 ^4 c& j" P7 d0 [# _4 B$ q. n* V
复制代码
; [% [) ^) b0 k+ U- W# m+ e- b/ N
修改函数,取消一些不必要的调用:
! g- m! \; q. v( D! j
  1. uint32_t BSP_EEPROM_Init(void) {
    / \6 i+ _$ K9 J4 k: m$ ~% G6 Q& `# Y
  2.     /* I2C Initialization */
    9 {+ d7 O9 n" F% c( @/ e% E4 P, D
  3. <font color="Red">//  EEPROM_IO_Init();</font>
    0 {2 i! ^' M# }# |
  4.     /* Select the EEPROM address for A01 and check if OK */
    3 B$ Q2 V: p% p
  5.     EEPROMAddress = EEPROM_I2C_ADDRESS_A01;
    0 L4 b/ x' K, q/ d3 U) q' S5 F
  6.     if (EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) {& N4 S) [, \  W2 y  q$ C
  7. //    /* Select the EEPROM address for A02 and check if OK */; ^4 d# }0 B% ?- T: f
  8. //    EEPROMAddress = EEPROM_I2C_ADDRESS_A02;4 n. _* O9 O+ t' d. S2 p7 D, X  M  p, Q
  9. //    if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK)& T: S' Y) {" z: s  x
  10. //    {4 ^- |* I$ n( w: F' G; \" H7 h. }8 q- ]7 t3 s
  11.         return EEPROM_FAIL;
    / _! b- L! e4 F! @% D! E' c
  12. //    }9 U. N. a6 Y2 p+ M" U6 J
  13.     }
    ! G" j' o& ?, V! m
  14.     return EEPROM_OK;7 w. Y, w& s8 Z. I) U1 D7 F& K
  15. }
    % Z6 y* `- o- o  t! c* _
复制代码
3 `3 @& u* d, S. y) z
另外,需要将stm324xg_eval.c中的 heval_I2c 变量实例替换为hi2c1。可以用查找替换或者宏定义。+ i" u$ ~+ t6 {/ u* D% K
4. 使用例子, F4 |: [: G6 N3 l3 q, `
4.1 初始化
+ N+ m$ R6 u" N1 I. R: j4 @在main.c的  : g( R; {8 x( z) y# d, V. ^9 S
  1. /* USER CODE BEGIN 2 */% T& g# I# B4 S! b8 D$ e0 |$ o5 B
  2. BSP_EEPROM_Init();
    + V3 A3 Q) f( M
  3.   /* USER CODE END 2 */
复制代码
或者其他适当地方添加初始化设置,完成EEPROM地址的设定。  g( }; _; c( L3 v# v( J3 p# g
4.2使用可以参考相应代码。如:
1 [5 g' T4 d5 a
  1. #define EEPROM_CFG_ADDRESS       0x120       //和页面对齐
    6 b) D* Q6 R1 I8 i
  2. __IO uint8_t EEPROMConnected = 1;
    ! _6 [; m$ A- F0 R
  3. typedef struct {
    6 y! g. `7 S5 f$ k/ s! @
  4.     uint16_t valide;, [1 f$ u, x4 O+ ^0 d; a
  5.     uint8_t databuf[16];4 x/ |; |$ d* H- i: E, K) D  }. P( x
  6. }CfgData;' t5 v1 ]4 W9 T7 q  f
  7. CfgData cfg; //全局的一个结构变量
      v% N# l* [5 I1 _, ]# f$ J' Q
  8. /**& a8 x$ A# j/ i' G# {$ |0 p
  9. * @brief  从EEPROM 中读出参数5 b# A" D( s6 I, O
  10. * @param  无1 W$ }' u: i( ^, I
  11. * @retval 0成功 其他失败: 1 通信错误  2 无效设置
    5 o& S9 |' `! B% b; c+ @
  12. */
    $ M/ F/ z0 d3 W6 A3 M! g
  13. uint8_t read_cfg_eeprom(void) {
    " I# W* p5 q! g* k$ Y0 b9 r$ q
  14.     CfgData cfg_read;
    + c! X0 e7 q: E) u! \$ i& G
  15.     uint16_t readSize= (uint16_t) sizeof(CfgData);
    ; P2 \9 F2 C! T; X' L1 o

  16. ! h2 n% V& [5 l4 F6 Z' e: |
  17.     EEPROMConnected = 1; //超时回调函数设定( @" `+ @0 o0 D$ k% h+ W1 d

  18. 9 W2 p1 O: _8 ^! n% k" v
  19.     /* Wait for EEPROM standby state */
    3 R/ R/ N1 j% b0 D) y0 V
  20.     BSP_EEPROM_WaitEepromStandbyState();3 j; B- z+ r* z4 H) S" U$ Y, B( j: c

  21.   e- S3 Z& v; `5 d* X0 u
  22.     /* Read old parameter in EEPROM */
    - B3 L+ s4 {! W- {
  23.     if (EEPROMConnected == 1) {
    7 @; P% v- M0 e) b# h& O! l
  24.         /* Set the Number of data to be read */
    4 R" y" `5 q# Z" x8 H. l# w5 l
  25.         memset((uint8_t*)&cfg_read,0,readSize);
    " v2 w( q1 ~8 I( X% {
  26.         /* Read from I2C EEPROM from EEPROM_CFG_ADDRESS */4 h( T0 {6 A% G+ l9 ^) h
  27.         if (BSP_EEPROM_ReadBuffer((uint8_t*)&cfg_read, EEPROM_CFG_ADDRESS, &readSize) != EEPROM_OK) {9 ?* ^- ^" N: Z
  28.             return 1;  //通信错误
    - Q: m1 a0 e4 ?; o) b: U7 e6 L+ n& S
  29.         }5 j' d! S: q: ?
  30.         if (cfg_read.valide == 0x55aa) {  //有效的, Z: Y9 U" k. @% K! j4 P, b- v
  31.             memcpy((void*)&cfg, (void *)&cfg_read, sizeof(CfgData));/ a1 F& J) C( y# ~7 p* k3 s
  32.             return 0; //正常5 Z% y8 F- S, r- l4 E  k
  33.         }
    6 H5 d6 q( Q7 @* y4 J
  34.     }
    3 B. X% g! e+ |
  35.     return 2; //无效设置5 O, n+ o- T) O" A! G2 c
  36. }
    $ X( }1 x  t8 W# R1 k
  37. /**' ]% s4 _1 Z/ U' b+ P" Z% Q
  38. * @brief  保存参数到 EEPROM 中
    2 R* R( y9 j5 O( F$ }
  39. * @param  无& t( g  W( Z8 U4 X5 a) M4 b
  40. * @retval 0成功 其他失败5 z( J9 R- [6 ~, {5 O
  41. */& w9 o# B% Y9 {# ?' e
  42. uint8_t save_cfg2eeprom(void) {2 ]+ s5 ^. f/ n2 T
  43. 0 r) }4 ]. t5 J. u
  44.     EEPROMConnected = 1;7 w( ^  }  U# I& j% _

  45. " g  Y  i: F  j! M8 v5 x
  46.     /* Wait for EEPROM standby state */
    ! A; X( V' C3 G  g
  47.     BSP_EEPROM_WaitEepromStandbyState();
    , \# u  B+ J. c1 {# n
  48. / [0 H# b+ @+ i  d2 Z
  49.     /* Write new parameter in EEPROM */  G! z) f$ p! L
  50.     if (EEPROMConnected == 1) {% W; `8 @* I& O) f; _
  51.         /* Write on I2C EEPROM to EEPROM_CFG_ADDRESS */+ K" F" J: h- s) M
  52.         if (BSP_EEPROM_WriteBuffer((uint8_t*)&cfg, EEPROM_CFG_ADDRESS, (uint16_t) sizeof(CfgData)) == EEPROM_OK) {
    0 l& C" }# T7 g2 z: z3 Y
  53.             return 0;
    8 v( J- Z' R1 x* m
  54.         }, X. C0 f3 |* d, w" F1 o
  55.     }
    5 p# R8 A$ |& Y. D) t2 w8 L2 N, Q
  56.     return 1;
    7 i4 e' _6 K% _6 A( J
  57. }
    3 R' O/ j( q$ T8 k" V
  58. /**
    6 _8 x1 S. P) {( Z$ Z* i# |
  59. * @brief  Basic management of the timeout situation.' @/ C7 H5 c) Q" z' t
  60. * @param  None.6 z! }" U0 L) x' @
  61. * @retval None
    - B# a  W7 z0 ]  h
  62. */
    4 J3 O& [" n8 }; y; ?
  63. void BSP_EEPROM_TIMEOUT_UserCallback(void) {! f" N7 x3 {% }3 Z
  64.     EEPROMConnected = 0;4 G# F$ S6 [7 M/ \' ~9 Z
  65. }
    % o' Z% T2 o; l6 a& K
  66. + u+ M# h, Z% A8 L# a# q& B
复制代码
经过调试并下载到核心板运行,测试结果正常。所用软件环境:
' _9 P$ W7 N: B  V8 KSTM32CubeMX 4.15.0+ F) L' l- W% L9 U- q. ?
STM32Cube_FW_F4_V1.12.0" O. O' \+ @4 M' E" j
GNU ARM C/C++ for eclipse 2.5.1.201604190915
2 y5 ^4 b4 Q5 z$ Z+ L) M: Aeclipse 4.4.2 luna7 `. R7 l4 F/ e, [" u
Debian sid: Linux Debian 4.5.0-2-686-pae #1 SMP Debian 4.5.4-1 (2016-05-16) i686 GNU/Linux
8 H! R  K8 @3 r$ V7 n! n* u6 r' r* ^1 E  X4 H6 M: A. V" Y. T

/ |6 r% K: p" ~& l9 i" t  L- j  a: e
收藏 评论3 发布时间:2016-5-30 19:31

举报

3个回答
giveup 回答时间:2016-5-31 08:04:02
红色字体显示出现问题。应该能看懂。
anny 回答时间:2016-5-31 08:26:55
谢谢分享
wbaojiang 回答时间:2020-3-23 11:56:38
感谢!
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版