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

STM32CubeMX + STM32F407VET6读写AT24C08的实验

[复制链接]
giveup 发布时间:2016-5-30 19:31
本帖最后由 giveup 于 2016-5-31 08:03 编辑
0 \  {" o  u. M  w9 U: D% z0 f5 s# V% q+ u/ c
采用STM32CubeMX 配置一块STM32F407VET6的核心板,通过I2C1读写AT24C08 EEPROM。可以选择BSP方式,或者到HAL库中挑选BSP驱动,效果一样。因为我的工程已经初始化过了,所以采用后种方式。
* n  l; @- T+ H3 P采用默认值配置I2C1,选中NVIC Settings中的 I2C1 event interrupt和 I2C1 error interrupt。生成工程模板。将AT24C98N EEPROM连接到PB6,PB7。器件A0,A1,A2引脚悬空,地址为0。
# _1 \8 ]8 T$ D7 a2 ~在安装库中复制eeprom的BSP驱动,应该都一样。如复制下列4个文件到工程目录下:
+ d( [% N8 S( b" I% L. qSTM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.c' ~. y' q, b; ~9 S4 D
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.h
# P: ?1 e: A, Y4 ^STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.c! B# A5 H3 H% w: v% ~: ~' b
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.h* `- E1 H3 r& R/ o

/ e7 G5 g; v+ |: C0 @+ `. Tstm324xg_eval.c和stm324xg_eval.h中保留和EEPROM相关内容即可。: `8 `* R7 ^- \0 |1 |; ^

2 \+ `4 O9 l( d" q1 t( c1 D/ x重点的问题是,这个驱动支持的是M24C64 EEPROM,和AT24C08 EEPROM有一定差异,需要修改部分内容才能使用。主要体现在读写页面尺寸、容量和器件地址表示不一致。, A' f* N! z( |) Y) [: i- R4 b
根据手册,AT24C04~AT24C32的内存地址是分为两部分,除低八位外,高3位占用了器件的地址。如AT24C08,内存大小为1024字节,地址为10位,高2位占用了器件地址A1,A0。M24C64 EEPROM的内存地址为16位,和AT24C32以上的EEPROM保持一致。( ^+ a  W! |7 y, q* g8 ~( }
因此,主要修改点为:1 E, p/ E, Y) o1 h3 @
1。修改页面尺寸与地址大小 ) _  y) H2 W% i% V4 C$ }: K
stm324xg_eval_eeprom.h中,修改定义:
9 ]3 t) |* H# [- r0 x4 J0 {0 q" k#define EEPROM_PAGESIZE             16
1 e% G' }( X3 n) u#define EEPROM_MAX_SIZE             0x400  /* 8Kbit */
( b) M: B, o, _" l2 Q7 i6 |/ H5 p' J  O0 x添加定义
$ K3 ^; `. c0 z4 f#define EEPROM_MEMADD_SIZE         I2C_MEMADD_SIZE_8BIT; d! U/ H* U" Q6 g: W# a: Q
#define MEMADD_MSB_MASK     0x3/ m, Y, [" o2 v& L8 g/ X, P
2。修改读写函数: [( _- a' B+ h
2.1 读操作部分修改逻辑:
( y; `) H/ s" i该部分的逻辑是 BSP_EEPROM_ReadBuffer 经过 EEPROM_IO_ReadData 调用I2Cx_ReadMultiple完成实际读写。, X: d* X3 m; M7 h6 P
因为读函数采用连续读方式,只要设定了正确的内存起始地址,就能正常完成读操作。因此,修改只涉及到BSP_EEPROM_ReadBuffer和EEPROM_IO_ReadData两个函数。具体修改如下,红色部分是增加和修改的:
" a) D- V3 ^+ C/ z5 `! Y9 I/ ?
  1.     uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) {8 }8 s: |% F" p
  2.     uint32_t buffersize = *NumByteToRead;, e+ i( i& G: X, r3 j" j' ~+ l/ `# j
  3. : e* a1 T4 T5 w$ t
  4.     /* Set the pointer to the Number of data to be read. This pointer will be used3 A; W! n4 ]" O" @/ d4 M
  5.      by the DMA Transfer Completer interrupt Handler in order to reset the 7 w- s# I$ \5 P9 i
  6.      variable to 0. User should check on this variable in order to know if the 2 d9 D+ ]) R  G2 c
  7.      DMA transfer has been complete or not. */. W0 O: e2 i' Y# O, Q
  8.     EEPROMDataRead = *NumByteToRead;
    7 j( q7 ?, {' d! P3 |& _
  9.     <font color="Red">uint16_t A_EEPROMAddress = EEPROMAddress;
    / P8 n: G5 W" v! ^3 t
  10.     uint8_t A2A1A0 = (uint8_t) ((ReadAddr >> 8) & MEMADD_MSB_MASK);
    ( O# z' i5 Q+ W2 G. }7 T4 f* q6 S
  11.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>1 C+ M# ]8 y; ]1 ~; v! B
  12. * J" Z) m4 B  N- X# V2 O* g
  13.     if (EEPROM_IO_ReadData(<font color="Red">A_EEPROMAddress</font>, ReadAddr, pBuffer, buffersize) != HAL_OK) {
    # u5 ?1 S+ c; t4 h* }
  14.         BSP_EEPROM_TIMEOUT_UserCallback();
    0 @$ L6 D0 l+ u) V- K$ a
  15.         return EEPROM_FAIL;6 b; q. b4 J  ]. C/ J/ j& s
  16.     }3 X9 J6 i6 P* S/ c, M6 f
  17.     /* If all operations OK, return EEPROM_OK (0) */( ?) B7 ]$ `* D9 [) z1 {: t0 F
  18.     return EEPROM_OK;
    . N/ j# [) h# ]3 h
  19. }
    2 l( B* A$ k! e1 ^5 u: N
复制代码
$ Q8 f. H, X; Y& A: R4 w
将I2C_MEMADD_SIZE_16BIT替换为上面新增加的EEPROM_MEMADD_SIZE定义:$ p% E7 A" x1 j2 h. p- f- J8 i
  1. HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
    - N* v+ r2 }- _
  2. {
    ' z! n" Q2 j' j0 d& N1 C- ]( V
  3.   return
    ; W/ _$ u2 ]) I8 Y* u. d5 r0 g0 y
  4. (I2Cx_ReadMultiple(DevAddress, MemAddress, <font color="Red">EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));' K& ?3 P* C1 C9 O- f, v
  5. }
复制代码

. D+ v" ^0 p8 p, F. b/ r
" s$ q  J- B6 t+ _  [" O  f4 |2.2写操作部分函数修改逻辑:' O$ `) c  m( }
写操作调用关系是BSP_EEPROM_WriteBuffer负责将写地址分页,并完成页面对齐后,调用BSP_EEPROM_WritePage经过EEPROM_IO_WriteData完成实际写操作。修改部分只涉及到后边两个函数,具体见下面红色部分:& X; ?! L/ u- P6 j2 S
  1.     uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) {& Y+ i0 H! F% X
  2.     uint32_t buffersize = *NumByteToWrite;
    / s: {! ^5 Q0 U% \5 F
  3.     uint32_t status = EEPROM_OK;
    + h0 |" O% P. `9 ~7 o: X; `9 E' `
  4. 0 A* k$ K8 o4 _  Y/ m- R! ?
  5.     /* Set the pointer to the Number of data to be written. This pointer will be used
    6 h+ D7 Q' ?# W" x1 C: n/ C* l
  6.      by the DMA Transfer Completer interrupt Handler in order to reset the
    & ^, I% a( t2 Z! d2 c
  7.      variable to 0. User should check on this variable in order to know if the
    ! F+ q; D2 r0 O! G2 h1 O0 Q- }
  8.      DMA transfer has been complete or not. */' O8 P% f: N/ _
  9.     EEPROMDataWrite = *NumByteToWrite;
    4 J7 b: S$ v2 j: a
  10. ! A/ e6 S4 g6 p2 S6 O
  11. <font color="Red">  uint16_t A_EEPROMAddress = EEPROMAddress;" l7 ?, x; M( G+ N4 {3 q# q" U$ O3 _* J
  12.     uint8_t A2A1A0 = (uint8_t) ((WriteAddr >> 8) & MEMADD_MSB_MASK);+ ^5 B( g8 @( H; C: _) T
  13.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>+ \: a5 U% H; k5 Y* F
  14. - Q. Y9 P  k0 t9 F5 P, i
  15.     if (EEPROM_IO_WriteData(<font color="Red">A_EEPROMAddress</font>, WriteAddr, pBuffer, buffersize) != HAL_OK) {
    / B4 s4 g6 A0 K, I1 E, E$ W( I
  16.         BSP_EEPROM_TIMEOUT_UserCallback();, [7 e+ H( e3 s) S
  17.         status = EEPROM_FAIL;) P8 U( R; D) \) V' q2 O3 Z5 C" K/ X
  18.     }0 N# U' ]9 U8 m7 [
  19. - d& B& [. W" t% v4 A
  20.     if (BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) {2 I" Z) Y# X3 O3 v
  21.         return EEPROM_FAIL;: B$ M) I$ b- ^! Q
  22.     }
    1 O% K& b0 b" Z: B
  23.     /* If all operations OK, return EEPROM_OK (0) */. O: Q* F5 C9 m$ q' o
  24.     return status;3 v( x$ s6 a; B6 v
  25. }
    ! u# `1 Z* o5 e! e3 v( X
复制代码

8 u8 [* u7 o4 {; ^. m( w具体写操作修改和读操作差不多:
+ N" E$ ~6 ?8 s' z$ G( Z1 B+ j3 i
  1. HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)" b6 ]0 f, B& H5 X
  2. {0 ^9 ^4 G  j5 A$ ]$ u1 l" [1 ~
  3.   return- f  \1 c+ m7 L/ q
  4. (I2Cx_WriteMultiple(DevAddress, MemAddress,<font color="Red"> EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));
    ; Q" q) Q0 S* c9 ~0 r/ j' H
  5. }
复制代码

* @) I/ w! G# v9 G! R6 s  ~6 ^; D5 m9 O& B% B  `0 w
3. 初始化及其他操作修改。STM32CubeMX已经正确生成了初始化代码,因此除了下面的两个,大部分BSP的初始化代码都可以删除。  o8 B) ^1 [: \, x: m0 C
  1. void EEPROM_IO_Init(void)
    ! R0 ~% O9 f; c
  2. {
    , k  q; R  ^8 @( ~
  3.   I2Cx_Init();$ F8 Y& _2 D. a$ r2 s) k% Q
  4. }
复制代码
修改为MX的初始化代码$ ]4 q* g+ R4 \2 W
  1. void EEPROM_IO_Init(void)
    1 z; \* k9 q1 H' O$ L9 ]! \
  2. {
    ! E' _# B8 V( p
  3.    MX_I2C1_Init();* ^) ~  ]* }% r1 g* ^2 K5 s
  4. }
    $ N& a! R, x# n3 `) X2 T  J1 f# s
复制代码
; d! s8 S3 F- P. n
修改函数,取消一些不必要的调用:6 a% {/ O1 O+ w. H
  1. uint32_t BSP_EEPROM_Init(void) {- ]4 _8 p2 I3 V+ Y/ c3 {
  2.     /* I2C Initialization *// e0 h5 P$ C+ F) p; x
  3. <font color="Red">//  EEPROM_IO_Init();</font>1 f" t9 {5 o% i- X, G- K
  4.     /* Select the EEPROM address for A01 and check if OK */+ j" @$ l% y9 f2 T1 S+ f
  5.     EEPROMAddress = EEPROM_I2C_ADDRESS_A01;
    1 `- t  F5 \1 a# [
  6.     if (EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) {3 [$ g/ p+ M% [" L/ K
  7. //    /* Select the EEPROM address for A02 and check if OK */
    9 p( b6 b1 E8 G! E! e
  8. //    EEPROMAddress = EEPROM_I2C_ADDRESS_A02;
    2 y& j' z1 K; h& l* a
  9. //    if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK)
    * O: g( h6 g2 t" P
  10. //    {
    6 N) y9 A( b* _+ @
  11.         return EEPROM_FAIL;/ R) w5 x! K6 `# h- u% y
  12. //    }
      [9 `* S$ W5 d. l! O7 f- R2 w7 S
  13.     }5 B: }0 s+ u+ L) ~
  14.     return EEPROM_OK;
    0 _$ _. U% w/ s* N/ r  N9 P
  15. }4 B6 v, Y$ E, B# b4 L0 {" I
复制代码

' S7 Z9 U7 e5 T另外,需要将stm324xg_eval.c中的 heval_I2c 变量实例替换为hi2c1。可以用查找替换或者宏定义。0 e1 B' E  t8 n
4. 使用例子
/ T5 O) D6 O( r- N' m. W4.1 初始化
- V+ P: D7 S4 X8 j! [$ f4 w) s在main.c的  9 _" I+ k( c) i0 p+ y( V5 P+ ~
  1. /* USER CODE BEGIN 2 *// ^5 n# G3 N: o( \$ h
  2. BSP_EEPROM_Init();
    9 k' O! w& A1 y8 P6 u" G6 I' A
  3.   /* USER CODE END 2 */
复制代码
或者其他适当地方添加初始化设置,完成EEPROM地址的设定。# p1 R& Z( t) O' U
4.2使用可以参考相应代码。如:6 S4 f% r( w# G, |8 ^6 z
  1. #define EEPROM_CFG_ADDRESS       0x120       //和页面对齐
    ; E* S" @5 e' o2 u/ r
  2. __IO uint8_t EEPROMConnected = 1;
    6 }3 @" t+ X7 p( n' D; J
  3. typedef struct {
    1 Y2 ~. g2 d0 T
  4.     uint16_t valide;
    ) P8 a) w1 }$ d8 j0 h9 h
  5.     uint8_t databuf[16];
    ' O3 G# H3 O9 w* h: U) B
  6. }CfgData;
    5 j/ B+ M1 s* J" |9 H9 y2 d2 z. Q
  7. CfgData cfg; //全局的一个结构变量8 M. L' o5 H0 f7 N/ B4 R" C$ s( o
  8. /**
    5 m2 E2 `0 B8 U* @' l" F7 l
  9. * @brief  从EEPROM 中读出参数
    & o+ B* a( ]4 _$ ]" r2 k
  10. * @param  无6 j8 R7 }1 b; V. Y
  11. * @retval 0成功 其他失败: 1 通信错误  2 无效设置
    5 T8 b5 Y$ o1 t
  12. */
    ; G6 x6 ]3 O( q9 _
  13. uint8_t read_cfg_eeprom(void) {
    / N7 A  G% V# w' S0 M/ v
  14.     CfgData cfg_read;
    : ~  O$ o# \% m% I# @
  15.     uint16_t readSize= (uint16_t) sizeof(CfgData);* y+ V  L$ w3 ~4 P+ G) }
  16. 7 G5 u# \" X& F, g0 L
  17.     EEPROMConnected = 1; //超时回调函数设定
      H8 {  T+ Q: J4 P" @0 }$ ]- A
  18. 9 C1 f8 M9 x/ R+ o5 b7 Y1 G/ w
  19.     /* Wait for EEPROM standby state */
    - O, }: Z- B6 M! \% O
  20.     BSP_EEPROM_WaitEepromStandbyState();
    0 d6 ]# f- C" u. R! |! }; U
  21. 7 J8 Y( @" F* o
  22.     /* Read old parameter in EEPROM */- Z0 l5 l0 c) \3 ?2 F6 z, U, C$ V
  23.     if (EEPROMConnected == 1) {
    ( T- g* I" W2 l9 m
  24.         /* Set the Number of data to be read */+ n  m' h- f& V( W
  25.         memset((uint8_t*)&cfg_read,0,readSize);- v6 Z2 ^7 Y' _( {# ^/ c! d
  26.         /* Read from I2C EEPROM from EEPROM_CFG_ADDRESS */( x, n: O) x3 V: m- j- M: o2 x+ r
  27.         if (BSP_EEPROM_ReadBuffer((uint8_t*)&cfg_read, EEPROM_CFG_ADDRESS, &readSize) != EEPROM_OK) {
      T9 M/ m" H. g. Q" s& k4 @$ I# u
  28.             return 1;  //通信错误( v4 A, w6 q- L; x: \& ?) L
  29.         }5 s8 v/ T4 e# l: V. R- V
  30.         if (cfg_read.valide == 0x55aa) {  //有效的
    - ~$ {  b$ I8 D6 n2 Q" i1 a( R7 \8 ]
  31.             memcpy((void*)&cfg, (void *)&cfg_read, sizeof(CfgData));  W* ?" E8 u4 H2 S
  32.             return 0; //正常
    3 d5 |0 ~6 p+ |. A, b/ Q
  33.         }  X$ S7 m" K: y0 N0 S# G
  34.     }1 G' d& k( I( p, l! M
  35.     return 2; //无效设置
    ; h5 T5 B8 e) w3 `
  36. }
    / C1 a- i' }) e  P
  37. /**
    8 f5 m2 l; f' s/ y, _8 p! L
  38. * @brief  保存参数到 EEPROM 中
    2 c2 n- t3 d# E# y9 G5 E0 I
  39. * @param  无3 h' A+ N2 @, @4 W. o  |; U
  40. * @retval 0成功 其他失败
    / z/ Q6 W  @3 p$ c+ K; v5 \" ?
  41. */
    * @$ T' b7 ?7 U  D; d
  42. uint8_t save_cfg2eeprom(void) {
    ' [' x# [* @5 e7 n
  43. 2 D/ e) p( v% q1 N, B* n
  44.     EEPROMConnected = 1;
    . u5 E4 |' m6 T/ C- @! F

  45.   I9 G  B( y0 L- e  W" w4 I$ s
  46.     /* Wait for EEPROM standby state */
    5 x$ N8 I3 M% h7 D+ V
  47.     BSP_EEPROM_WaitEepromStandbyState();
      h7 g' U0 B0 s9 f/ c4 O- t

  48. 9 }- M2 q9 Z( z8 u4 I* v
  49.     /* Write new parameter in EEPROM */
    + @/ X2 I$ v% ^6 \! ?! y. @
  50.     if (EEPROMConnected == 1) {: J: j! }% {# M0 I8 D" `  v0 v
  51.         /* Write on I2C EEPROM to EEPROM_CFG_ADDRESS */. P& _( B1 |7 W! d+ ?3 j: {
  52.         if (BSP_EEPROM_WriteBuffer((uint8_t*)&cfg, EEPROM_CFG_ADDRESS, (uint16_t) sizeof(CfgData)) == EEPROM_OK) {
    2 G) d/ r* M/ }7 `
  53.             return 0;3 ]$ W. B* [7 Q8 G
  54.         }- y. J! K1 Y" U6 M% y: F! c
  55.     }
    $ K; Y$ ?+ O  `% k% e/ x
  56.     return 1;
    ! e: ]* W7 z8 v1 t5 v
  57. }5 {  k( w2 r; ^0 X* Q- ?. n
  58. /**2 h3 t- h/ l* j* ]' E& V( |" K
  59. * @brief  Basic management of the timeout situation.
    " G1 z+ o9 D3 n. q
  60. * @param  None.# X6 M+ y6 g  s. D+ I! D
  61. * @retval None7 s+ X4 U$ ]. M8 R# C9 a2 U
  62. */7 d- f2 V; x4 q/ {  L0 H4 h% K5 ^
  63. void BSP_EEPROM_TIMEOUT_UserCallback(void) {- Y9 T# v4 {5 j. s
  64.     EEPROMConnected = 0;- R, Z  O5 @9 \( p
  65. }9 x7 T% t7 j. E" _8 p2 X! ?
  66. + Z9 X- u$ j7 S4 d% ^; f- i9 E
复制代码
经过调试并下载到核心板运行,测试结果正常。所用软件环境:7 _! M* A6 B- ?, G- M* ]" D: L
STM32CubeMX 4.15.0  n3 p- H8 K) E
STM32Cube_FW_F4_V1.12.0! @0 o5 {. v9 C9 k9 _
GNU ARM C/C++ for eclipse 2.5.1.201604190915
& y+ @$ x9 L7 J5 u8 Heclipse 4.4.2 luna
1 A0 p4 ^$ c6 E; ~& X4 WDebian sid: Linux Debian 4.5.0-2-686-pae #1 SMP Debian 4.5.4-1 (2016-05-16) i686 GNU/Linux" q& ^$ p+ {8 h5 X  g
, Y: |1 n; X3 z6 S1 N. ~

" Q, t! Q5 A6 l* C9 C6 W+ V
赞 收藏 评论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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版