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

STM32CubeMX + STM32F407VET6读写AT24C08的实验

[复制链接]
giveup 发布时间:2016-5-30 19:31
本帖最后由 giveup 于 2016-5-31 08:03 编辑
+ K4 Y7 A' a5 A. [2 w! H& k
0 y! z0 r' i. f2 x$ M采用STM32CubeMX 配置一块STM32F407VET6的核心板,通过I2C1读写AT24C08 EEPROM。可以选择BSP方式,或者到HAL库中挑选BSP驱动,效果一样。因为我的工程已经初始化过了,所以采用后种方式。
3 y9 t8 x# n, t$ {采用默认值配置I2C1,选中NVIC Settings中的 I2C1 event interrupt和 I2C1 error interrupt。生成工程模板。将AT24C98N EEPROM连接到PB6,PB7。器件A0,A1,A2引脚悬空,地址为0。
7 Y+ q0 b$ _: _5 j4 {& a在安装库中复制eeprom的BSP驱动,应该都一样。如复制下列4个文件到工程目录下:
- |% ~" w$ B; |+ `8 D2 [* @STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.c% A$ y3 N% q& C  I" r: G
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.h7 N2 \7 ?- q, {! P8 j- ?
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.c
! d. F6 g0 F+ @3 K* \STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.h( a/ U9 V( u" ~4 G: @' ?* y

4 h. p+ P4 J- D& b8 [stm324xg_eval.c和stm324xg_eval.h中保留和EEPROM相关内容即可。. z( P+ y* k4 ?3 h/ S: S9 i; t8 [" |

" u: S- w6 E6 x% i; b; V) U2 s重点的问题是,这个驱动支持的是M24C64 EEPROM,和AT24C08 EEPROM有一定差异,需要修改部分内容才能使用。主要体现在读写页面尺寸、容量和器件地址表示不一致。( {. _9 F8 J* ]" q  ~! }& f' ]
根据手册,AT24C04~AT24C32的内存地址是分为两部分,除低八位外,高3位占用了器件的地址。如AT24C08,内存大小为1024字节,地址为10位,高2位占用了器件地址A1,A0。M24C64 EEPROM的内存地址为16位,和AT24C32以上的EEPROM保持一致。9 ^: ^4 k0 }: Q& s" a8 k
因此,主要修改点为:
& Z- n3 Z1 n6 c1。修改页面尺寸与地址大小 + B2 y6 U7 o8 R7 p
stm324xg_eval_eeprom.h中,修改定义:- k% a, s8 @/ m# A
#define EEPROM_PAGESIZE             16
7 K5 ]; i& d$ H' {6 e4 Z# c$ ]' Q& K#define EEPROM_MAX_SIZE             0x400  /* 8Kbit */( j- m4 C2 U) m3 @
添加定义. w/ l; \# j- F  O+ C) P
#define EEPROM_MEMADD_SIZE         I2C_MEMADD_SIZE_8BIT9 ~9 S+ E/ M: l# D( q3 H
#define MEMADD_MSB_MASK     0x3
$ n1 S. U5 u8 b0 V- U- a2。修改读写函数9 N1 Q' L; g( v! ~
2.1 读操作部分修改逻辑:6 e+ U2 y$ c2 J& F
该部分的逻辑是 BSP_EEPROM_ReadBuffer 经过 EEPROM_IO_ReadData 调用I2Cx_ReadMultiple完成实际读写。
) \: ?# A3 y) k" N因为读函数采用连续读方式,只要设定了正确的内存起始地址,就能正常完成读操作。因此,修改只涉及到BSP_EEPROM_ReadBuffer和EEPROM_IO_ReadData两个函数。具体修改如下,红色部分是增加和修改的:
6 r" A, x. h; }$ ]# W
  1.     uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) {
    % V% v7 Z! a7 e. r/ b6 R, l
  2.     uint32_t buffersize = *NumByteToRead;
    / X* Y8 J% J/ B

  3. & ]% `" n3 ]% `
  4.     /* Set the pointer to the Number of data to be read. This pointer will be used) y. w# S/ |) q0 u; M3 S
  5.      by the DMA Transfer Completer interrupt Handler in order to reset the
    + K& o* M; `# w; M
  6.      variable to 0. User should check on this variable in order to know if the
    % r( d4 T7 ^1 [
  7.      DMA transfer has been complete or not. */
    & S. H: j% d- ]( F: ?" r* x5 }9 T; e% K
  8.     EEPROMDataRead = *NumByteToRead;
    . v+ a0 y, ~9 s' M: w
  9.     <font color="Red">uint16_t A_EEPROMAddress = EEPROMAddress;
    6 t. {( |" j- {
  10.     uint8_t A2A1A0 = (uint8_t) ((ReadAddr >> 8) & MEMADD_MSB_MASK);
    + k  U+ X0 ]7 t- c' M9 g
  11.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
    ! r+ U8 [% R/ Z( F  d. O& T
  12. % l4 Z! U* M$ L; Z$ S2 i- |6 J
  13.     if (EEPROM_IO_ReadData(<font color="Red">A_EEPROMAddress</font>, ReadAddr, pBuffer, buffersize) != HAL_OK) {) ~( G1 y/ i5 s' \. ^  K6 C
  14.         BSP_EEPROM_TIMEOUT_UserCallback();. o# r6 A, o4 ?1 E
  15.         return EEPROM_FAIL;1 S% ?+ H5 \. r; D* J4 i
  16.     }- F* A, g- y5 U( A& ^) f9 w7 D) k) k) J
  17.     /* If all operations OK, return EEPROM_OK (0) */  i# S' c$ P" N. C& l
  18.     return EEPROM_OK;; w& `8 n7 Y- Y0 m! h
  19. }/ \% I/ x4 o8 I+ @& }: `8 F8 |$ p
复制代码
, |/ W" \9 G& E4 n# N$ r) o# w
将I2C_MEMADD_SIZE_16BIT替换为上面新增加的EEPROM_MEMADD_SIZE定义:2 x& `2 m% A7 K+ h
  1. HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
    ( s/ y& N9 \) q2 _
  2. {
    6 @% L" g: m# k4 S6 x5 \2 H, q7 y2 I9 u! Q
  3.   return4 q% `1 Y. s) a- e3 c7 p/ q  s; E
  4. (I2Cx_ReadMultiple(DevAddress, MemAddress, <font color="Red">EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));% V9 V4 T8 b9 }6 L' M9 i4 }
  5. }
复制代码
$ p' p, k: z/ u' r3 I. o

. V5 h1 Z( n8 ?4 I2.2写操作部分函数修改逻辑:/ q) j# p2 Y* v, t$ E. \
写操作调用关系是BSP_EEPROM_WriteBuffer负责将写地址分页,并完成页面对齐后,调用BSP_EEPROM_WritePage经过EEPROM_IO_WriteData完成实际写操作。修改部分只涉及到后边两个函数,具体见下面红色部分:
0 @, X! ~. ^7 p/ n5 h! t
  1.     uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) {
    9 B. I3 A: r: N; Q% R" a4 A* D
  2.     uint32_t buffersize = *NumByteToWrite;
    # s) S% k! |2 T. S: b4 o7 L, y
  3.     uint32_t status = EEPROM_OK;: l0 L0 W- O0 o/ a/ a* ]
  4. - |5 x! I  W. L7 b3 f' m3 c
  5.     /* Set the pointer to the Number of data to be written. This pointer will be used
    8 L, W. G4 B& }' q4 |
  6.      by the DMA Transfer Completer interrupt Handler in order to reset the) m: A8 R2 k! J5 a% j9 W# G
  7.      variable to 0. User should check on this variable in order to know if the" R6 R$ D. R$ n, j2 D4 ]
  8.      DMA transfer has been complete or not. */
    ' _* G  o# A4 B7 d
  9.     EEPROMDataWrite = *NumByteToWrite;
    - h) z: _' f( H) m) j; g7 [# I% {
  10. # @  w5 R7 Q; W( G! F5 {; h
  11. <font color="Red">  uint16_t A_EEPROMAddress = EEPROMAddress;/ j& H7 c4 K& C
  12.     uint8_t A2A1A0 = (uint8_t) ((WriteAddr >> 8) & MEMADD_MSB_MASK);" {  a6 v- d7 }' ?
  13.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>  e$ M. P- A* K' k# f- V/ L

  14. % V& r) H( j. m  {
  15.     if (EEPROM_IO_WriteData(<font color="Red">A_EEPROMAddress</font>, WriteAddr, pBuffer, buffersize) != HAL_OK) {
    ( E* k- @4 Q2 t9 |6 X9 [) n6 q" k
  16.         BSP_EEPROM_TIMEOUT_UserCallback();
    3 V; D, R" }7 K7 F* c
  17.         status = EEPROM_FAIL;3 K' m$ j# w3 @
  18.     }) T) B8 L+ r! @+ W) D
  19. 1 m$ I0 A  q' i8 ]# ~4 y  M
  20.     if (BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) {
    2 s3 x& q) c( F7 e
  21.         return EEPROM_FAIL;; [6 U' b2 Q' l9 a6 e
  22.     }3 T  [/ Q6 w; o( l9 H7 Z
  23.     /* If all operations OK, return EEPROM_OK (0) */8 q, W" ~5 l2 m
  24.     return status;8 }% s( p" l* j3 h  b1 G2 d
  25. }" Y3 o; V1 j5 f7 Z' S& Y
复制代码

* M5 w4 y9 A) e+ |5 [0 Y4 C具体写操作修改和读操作差不多:
: T' k: C6 s$ B. x
  1. HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
    3 h" e) N  ^; P! P0 @) O
  2. {
    7 G3 n" g  m& V0 E: |
  3.   return
    * ?9 w" s6 R/ T; C% _$ a% x1 c
  4. (I2Cx_WriteMultiple(DevAddress, MemAddress,<font color="Red"> EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));9 e6 `! G5 K$ M5 p! c, R
  5. }
复制代码
- E3 h0 R) c' i9 m. d7 }! O) g
' p- r8 D6 ?" A9 h; D6 B9 y3 G) J2 g+ w
3. 初始化及其他操作修改。STM32CubeMX已经正确生成了初始化代码,因此除了下面的两个,大部分BSP的初始化代码都可以删除。
6 N$ u% z+ G' y3 \  K' G
  1. void EEPROM_IO_Init(void)8 G# A9 p$ [: E6 P
  2. {
    / c2 Q  X2 N! B9 W
  3.   I2Cx_Init();6 K0 G2 r7 K* Z( z/ N0 J
  4. }
复制代码
修改为MX的初始化代码- n4 K- [# J, f6 W* z
  1. void EEPROM_IO_Init(void)
    ) n7 q2 Y; n4 o1 B0 e& j
  2. {) P* y- A/ c2 F( C5 y  j
  3.    MX_I2C1_Init();
    - I" c. ~. r# `9 {4 g4 r& r2 c
  4. }
    ; J2 R0 q( L( m
复制代码

7 [% u( B' g) |修改函数,取消一些不必要的调用:7 r# u# j+ q7 ]- c0 {- V
  1. uint32_t BSP_EEPROM_Init(void) {
    ! X: A. r( }5 A) N  ?
  2.     /* I2C Initialization */) {1 d: W# Z% H4 m* d6 M5 j
  3. <font color="Red">//  EEPROM_IO_Init();</font>
    * r# f- Z# x+ p
  4.     /* Select the EEPROM address for A01 and check if OK */" R) Q& A' L- ^% I  h3 g
  5.     EEPROMAddress = EEPROM_I2C_ADDRESS_A01;9 t$ X: m. x( {" i- g' v6 C/ v  |
  6.     if (EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) {) `' \+ Q9 P- N$ `, W+ z& h
  7. //    /* Select the EEPROM address for A02 and check if OK */1 j6 c4 V* ~1 |1 |* V* V- Z; e
  8. //    EEPROMAddress = EEPROM_I2C_ADDRESS_A02;
    ) c. _) x$ `2 K" w9 C
  9. //    if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK)0 D; l, z2 b% n. S) |6 g3 p9 E
  10. //    {
    ( J6 e8 s" O0 r
  11.         return EEPROM_FAIL;
    2 t: N* x8 n+ {) U+ E* d
  12. //    }7 Q# e/ N0 }$ I7 \, _) y
  13.     }  \0 S+ M2 V5 C. q) N) H
  14.     return EEPROM_OK;4 n9 j! ~. }1 f. i! m
  15. }# `' ]2 R4 P/ p4 j' C
复制代码
# C* N8 O' u1 e" K; P" }
另外,需要将stm324xg_eval.c中的 heval_I2c 变量实例替换为hi2c1。可以用查找替换或者宏定义。
" X- J' ]5 Q( Z4. 使用例子
& \5 O) h# w1 U/ s9 G' u4.1 初始化( g5 U. h  k' |# ]7 w; l4 \
在main.c的  
, |4 F! k# l8 a, I; [2 R! g0 v  r0 W
  1. /* USER CODE BEGIN 2 */1 V# g# M0 s* k/ y; r3 Y: [
  2. BSP_EEPROM_Init();
    5 E; e* r$ h  M8 B6 X: ?+ Y4 D1 Y
  3.   /* USER CODE END 2 */
复制代码
或者其他适当地方添加初始化设置,完成EEPROM地址的设定。
  Z( ]5 w- z1 h1 ]- @4.2使用可以参考相应代码。如:# t& H1 X  q! A! n) I9 M0 J5 S6 c( p
  1. #define EEPROM_CFG_ADDRESS       0x120       //和页面对齐, w( V( A# ?( W- J$ y5 i
  2. __IO uint8_t EEPROMConnected = 1;. l8 x$ w9 h) y; s+ L
  3. typedef struct {' ^: ~, J' R  _
  4.     uint16_t valide;9 x+ I% W6 e; ?) `1 w# K$ |" X8 a
  5.     uint8_t databuf[16];
    ' J3 v# _8 e7 O7 x0 Q0 p) z$ }# ~" e
  6. }CfgData;
    ) Y1 B: B( Z* Z+ s% V
  7. CfgData cfg; //全局的一个结构变量0 L& [, M0 X* N
  8. /**
    5 e9 o8 m: v" o6 h
  9. * @brief  从EEPROM 中读出参数, Z5 h: R$ e8 B! ?7 n3 ~: v+ I
  10. * @param  无) y; Q- @! A  {
  11. * @retval 0成功 其他失败: 1 通信错误  2 无效设置& M' ^2 X( g' \+ \1 i& K# a: e9 k
  12. */
    1 ?5 k6 w. n  W; H& j1 U" A7 N
  13. uint8_t read_cfg_eeprom(void) {
    & x6 \: X, B2 X$ f
  14.     CfgData cfg_read;! o" a- F6 [7 _2 O2 H2 j- G
  15.     uint16_t readSize= (uint16_t) sizeof(CfgData);
    $ b/ L5 Y9 ~, [' v. m! N# L

  16. + {- U0 s1 M) x
  17.     EEPROMConnected = 1; //超时回调函数设定. j7 _- T3 X2 l. ^! P4 Y0 Z$ V
  18. 6 r6 h! p3 G5 `# Z! w$ i
  19.     /* Wait for EEPROM standby state */
      ~7 E$ l  a' v% ?6 e
  20.     BSP_EEPROM_WaitEepromStandbyState();
    / i, o# d4 ^9 R  l

  21. . Y/ }! v3 t+ Y4 U8 {% K
  22.     /* Read old parameter in EEPROM */8 z7 Y! O4 f3 A- {( s( L
  23.     if (EEPROMConnected == 1) {( [$ h4 v: k9 @0 I" E/ C
  24.         /* Set the Number of data to be read */2 m" S6 s/ `' C$ f" n( m6 Z
  25.         memset((uint8_t*)&cfg_read,0,readSize);6 b# o4 U/ `% P6 l
  26.         /* Read from I2C EEPROM from EEPROM_CFG_ADDRESS */0 |+ a4 a$ n$ J& q: h) C: r
  27.         if (BSP_EEPROM_ReadBuffer((uint8_t*)&cfg_read, EEPROM_CFG_ADDRESS, &readSize) != EEPROM_OK) {
    3 u2 N3 h% l/ |
  28.             return 1;  //通信错误$ @. h% X- w8 r! q
  29.         }' k9 Y" ]. I- F$ k2 q
  30.         if (cfg_read.valide == 0x55aa) {  //有效的1 j1 w8 E+ y% _7 W+ j8 Q- ^. R2 X
  31.             memcpy((void*)&cfg, (void *)&cfg_read, sizeof(CfgData));- p8 W, T' ^% @- L2 K9 V7 h
  32.             return 0; //正常; j5 d1 y  j/ N' B) e& k' M
  33.         }; M& B5 l" h4 J) B4 \" Q7 f$ o
  34.     }
    $ K  y; h2 M# q! X
  35.     return 2; //无效设置) B  Z5 Z' D7 c9 M! Y1 N7 q$ ~! K
  36. }
    ; R# H" [$ b3 s0 _- o
  37. /**
    0 U8 P, O, R* Q' z  i. [
  38. * @brief  保存参数到 EEPROM 中
    6 Y  A& {' r. a5 m
  39. * @param  无
    ( [* D* H2 j# a5 H
  40. * @retval 0成功 其他失败
    1 ?1 F7 O) J* z5 T* @8 T
  41. */
    9 G2 O2 o: n5 ?$ @0 c: L# }
  42. uint8_t save_cfg2eeprom(void) {" L. U% @1 A3 }+ i5 G. a' X

  43. % {7 q0 {6 u$ d4 v
  44.     EEPROMConnected = 1;
    ! y) T; N  @5 n7 ~

  45. 3 c) t; s1 C' G8 R- R
  46.     /* Wait for EEPROM standby state */
    - {$ q' P3 v) B! H2 A
  47.     BSP_EEPROM_WaitEepromStandbyState();
    5 X1 [4 @/ i9 U: w. F6 {" e
  48. 6 E" ^" q+ ^$ b( n8 s% F
  49.     /* Write new parameter in EEPROM */
    % \( [1 i+ ~: T* ]7 A' [0 ^8 T! G
  50.     if (EEPROMConnected == 1) {
    ' G2 h2 P# P  a/ I# v8 `- i
  51.         /* Write on I2C EEPROM to EEPROM_CFG_ADDRESS */+ i: x6 F: \) b9 w  D8 t: N; Y$ A
  52.         if (BSP_EEPROM_WriteBuffer((uint8_t*)&cfg, EEPROM_CFG_ADDRESS, (uint16_t) sizeof(CfgData)) == EEPROM_OK) {9 C$ c- u( A  V# F
  53.             return 0;
    " M: i% H4 `5 F" _$ h4 M; |
  54.         }  p- a/ f# v6 o9 H
  55.     }0 P* q0 V5 |5 x' s5 {8 @, b- t
  56.     return 1;
    6 J4 l7 |1 o; Q2 }) t& W
  57. }1 U5 S- o  l5 c& s
  58. /**8 w) l' c2 m) f* j1 d
  59. * @brief  Basic management of the timeout situation.
    " M8 A) u, m  E0 R. L( b/ N
  60. * @param  None.
    * p: {0 l$ |6 @! l9 h/ W
  61. * @retval None, m  r$ m1 D' E5 D9 D) z+ ^
  62. */
    . P- W4 q0 c9 A- t& k/ n( f/ \
  63. void BSP_EEPROM_TIMEOUT_UserCallback(void) {
    2 P0 x8 S/ S6 k$ _! o
  64.     EEPROMConnected = 0;
    - V5 u# ~$ {7 T% k
  65. }/ a- c3 Q( F/ K9 L( `0 o! V2 D

  66. ; K$ M" E4 Z+ I+ I4 p- h; y
复制代码
经过调试并下载到核心板运行,测试结果正常。所用软件环境:3 q: F# M$ I% t) q; O/ V* s4 k
STM32CubeMX 4.15.0
4 E2 ~& i3 U, @0 ZSTM32Cube_FW_F4_V1.12.0
2 m& f% U! M: q8 k: dGNU ARM C/C++ for eclipse 2.5.1.201604190915
- n. N( w0 n& I8 {" ~, leclipse 4.4.2 luna9 [' X8 E9 ~% B  Y
Debian sid: Linux Debian 4.5.0-2-686-pae #1 SMP Debian 4.5.4-1 (2016-05-16) i686 GNU/Linux
% q- f( b. W: R6 S5 }$ S% {1 R( a* ~. ]; I

& G3 G5 g8 E; O# f9 g
收藏 评论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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版