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

STM32CubeMX + STM32F407VET6读写AT24C08的实验

[复制链接]
giveup 发布时间:2016-5-30 19:31
本帖最后由 giveup 于 2016-5-31 08:03 编辑 $ h% W$ J! \* N/ S# J' |' r

2 b( K1 A- Q  C& Y' J' N' i; @采用STM32CubeMX 配置一块STM32F407VET6的核心板,通过I2C1读写AT24C08 EEPROM。可以选择BSP方式,或者到HAL库中挑选BSP驱动,效果一样。因为我的工程已经初始化过了,所以采用后种方式。0 D, C* o6 S9 b  Y9 [
采用默认值配置I2C1,选中NVIC Settings中的 I2C1 event interrupt和 I2C1 error interrupt。生成工程模板。将AT24C98N EEPROM连接到PB6,PB7。器件A0,A1,A2引脚悬空,地址为0。
# a  B7 b( ?$ D& i: S" ^; U在安装库中复制eeprom的BSP驱动,应该都一样。如复制下列4个文件到工程目录下:0 @) R5 h+ Q: O" z- O, D6 x
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.c5 u5 Q8 Y8 E% K7 n( L; g
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval_eeprom.h
# B0 G  [7 d7 t5 N3 Y& LSTM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.c8 U; J# S' O% X) [" J# x% V
STM32Cube/Repository/STM32Cube_FW_F4_V1.12.0/Drivers/BSP/STM324xG_EVAL/stm324xg_eval.h8 R+ s/ z! L# i  W

: h5 Z% n. }; v% A+ Y, C9 Xstm324xg_eval.c和stm324xg_eval.h中保留和EEPROM相关内容即可。" @; b( a; S1 h9 y; |; Z
6 U4 L% ~, }- `0 N1 K
重点的问题是,这个驱动支持的是M24C64 EEPROM,和AT24C08 EEPROM有一定差异,需要修改部分内容才能使用。主要体现在读写页面尺寸、容量和器件地址表示不一致。/ o( v) K3 Q/ N6 y
根据手册,AT24C04~AT24C32的内存地址是分为两部分,除低八位外,高3位占用了器件的地址。如AT24C08,内存大小为1024字节,地址为10位,高2位占用了器件地址A1,A0。M24C64 EEPROM的内存地址为16位,和AT24C32以上的EEPROM保持一致。( E( E4 [7 k6 D, _' ^7 Y
因此,主要修改点为:1 _# L- ~  S) c- A" G& k7 ]5 H, Z
1。修改页面尺寸与地址大小
& u7 R4 `& \( ^9 \  h1 Lstm324xg_eval_eeprom.h中,修改定义:8 F) H7 X) g5 D+ `# Z3 R: e
#define EEPROM_PAGESIZE             16
) M' G  n' P- S, V4 x" [4 d#define EEPROM_MAX_SIZE             0x400  /* 8Kbit */, C( x, x) p+ b, P) u- Z- Y& E
添加定义3 r" d( y# i0 B
#define EEPROM_MEMADD_SIZE         I2C_MEMADD_SIZE_8BIT
) T- S8 Q) H# D#define MEMADD_MSB_MASK     0x3
2 {  P$ k" e$ O# R  }6 b$ a& R2。修改读写函数
% H3 S$ X) O  ]0 P2.1 读操作部分修改逻辑:0 a$ v, H# {0 t4 k/ ]1 l3 _
该部分的逻辑是 BSP_EEPROM_ReadBuffer 经过 EEPROM_IO_ReadData 调用I2Cx_ReadMultiple完成实际读写。% [/ |  ]; L; q( X; [* b
因为读函数采用连续读方式,只要设定了正确的内存起始地址,就能正常完成读操作。因此,修改只涉及到BSP_EEPROM_ReadBuffer和EEPROM_IO_ReadData两个函数。具体修改如下,红色部分是增加和修改的:* n# E/ W# K0 u1 B/ B8 O& q
  1.     uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) {
    2 j+ Z  C% s8 V7 X: O% E+ @
  2.     uint32_t buffersize = *NumByteToRead;
    7 k" k+ {% x3 p3 p! q0 H
  3. 1 k8 T0 Q, a. ^0 C( B; g
  4.     /* Set the pointer to the Number of data to be read. This pointer will be used. g! d6 E2 a. E; a- @+ ?$ ]
  5.      by the DMA Transfer Completer interrupt Handler in order to reset the # k, O: C4 c3 b+ M3 G" k- o" I/ N) ~
  6.      variable to 0. User should check on this variable in order to know if the ! U/ T, }% J: ?
  7.      DMA transfer has been complete or not. */. A. ^  ~8 |3 t% [8 H
  8.     EEPROMDataRead = *NumByteToRead;4 v/ N3 ?" v. @
  9.     <font color="Red">uint16_t A_EEPROMAddress = EEPROMAddress;
    . g6 x- D* p& W9 m
  10.     uint8_t A2A1A0 = (uint8_t) ((ReadAddr >> 8) & MEMADD_MSB_MASK);
    2 u& I8 H) {, P
  11.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
    7 ~( X  q" [, Q. W, Y

  12. + v$ c# e9 C- D4 ~" X  t* |
  13.     if (EEPROM_IO_ReadData(<font color="Red">A_EEPROMAddress</font>, ReadAddr, pBuffer, buffersize) != HAL_OK) {6 m0 c4 P7 {) R/ U8 {" |" U
  14.         BSP_EEPROM_TIMEOUT_UserCallback();
    2 o% {) m% c& G, Q( @4 W" p
  15.         return EEPROM_FAIL;, ?1 a. T: e0 K
  16.     }
    3 X! R" e3 t! q) [/ }" Q
  17.     /* If all operations OK, return EEPROM_OK (0) */7 L) t( M9 b0 s' l; O7 c" A
  18.     return EEPROM_OK;
    % p( H* N/ Z1 A( c: t
  19. }3 b' y  `$ z6 F8 i( \0 e7 S
复制代码

  h6 Y4 w! ^- u2 p& U将I2C_MEMADD_SIZE_16BIT替换为上面新增加的EEPROM_MEMADD_SIZE定义:% u" V: C. |3 W- h" Z5 s) E
  1. HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)* m2 w" T3 m0 `2 O' d5 @
  2. {, p) t% h1 N% k+ z+ I7 C
  3.   return
    - N/ b$ V( \; s! I8 \) O% ^
  4. (I2Cx_ReadMultiple(DevAddress, MemAddress, <font color="Red">EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));9 M5 ~2 v. U4 w  a% n, ^
  5. }
复制代码
: \. B+ v4 f6 q
$ R$ k! t( v1 g6 M8 \8 l% H
2.2写操作部分函数修改逻辑:$ R+ x3 k4 |4 y6 o2 M) G1 z
写操作调用关系是BSP_EEPROM_WriteBuffer负责将写地址分页,并完成页面对齐后,调用BSP_EEPROM_WritePage经过EEPROM_IO_WriteData完成实际写操作。修改部分只涉及到后边两个函数,具体见下面红色部分:5 y# u$ q% @2 }: @& g1 Y0 n3 n; X
  1.     uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) {. e1 r3 j/ ?' e8 [
  2.     uint32_t buffersize = *NumByteToWrite;) i7 v- J- l1 a
  3.     uint32_t status = EEPROM_OK;% d: }0 _2 X' E% s9 w

  4. 5 }( _3 m8 X! U% S- U9 o2 I' r  T
  5.     /* Set the pointer to the Number of data to be written. This pointer will be used5 z9 b: ^' u* `! f0 d8 L
  6.      by the DMA Transfer Completer interrupt Handler in order to reset the
    7 h- x# K* L: E8 H# V7 x) `
  7.      variable to 0. User should check on this variable in order to know if the
    4 P( l6 }) U4 t4 k: A
  8.      DMA transfer has been complete or not. */
    6 H" ]! g: F; X/ m& b# ]
  9.     EEPROMDataWrite = *NumByteToWrite;
    * c. J% \) d7 m  e  j

  10. 7 p# @8 A2 P" \9 O, X
  11. <font color="Red">  uint16_t A_EEPROMAddress = EEPROMAddress;% y% E: ]& l: `1 u6 z. l2 o
  12.     uint8_t A2A1A0 = (uint8_t) ((WriteAddr >> 8) & MEMADD_MSB_MASK);2 m* I4 J& j' z1 Q' ?
  13.     A_EEPROMAddress = A_EEPROMAddress | (A2A1A0<<1);</font>
      \, J& L: u% z) A) ^( D2 H
  14. + i: V3 g5 t2 F9 ~: G8 C# b
  15.     if (EEPROM_IO_WriteData(<font color="Red">A_EEPROMAddress</font>, WriteAddr, pBuffer, buffersize) != HAL_OK) {
    ; W% I& J8 n, A1 |
  16.         BSP_EEPROM_TIMEOUT_UserCallback();9 d" N% a1 t' L0 i3 Y" _
  17.         status = EEPROM_FAIL;9 o% @  K$ j) b& f  u6 Y& N
  18.     }
    4 K" _) v! s4 z" u" D

  19. , V. r' |! E6 L5 E
  20.     if (BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) {* j! J) s: a) c' Y# x) \
  21.         return EEPROM_FAIL;
    2 R  O$ n* ^: f' Y
  22.     }
    - G% z! n9 x, f' {, _0 d
  23.     /* If all operations OK, return EEPROM_OK (0) */# o9 O5 I' k0 J( z4 x5 `: I1 B
  24.     return status;1 \. p; Q# ^/ S+ g9 ~/ K* G" @
  25. }0 r5 T/ {9 R% [
复制代码
0 c/ \2 D9 v  M
具体写操作修改和读操作差不多:5 B/ s( e! J+ A, V+ Z/ b$ ?
  1. HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
    9 P" \4 p% j/ S- v  w
  2. {' @  \; D/ z5 s0 z
  3.   return2 U0 r/ L$ _9 e( m) q1 l3 P
  4. (I2Cx_WriteMultiple(DevAddress, MemAddress,<font color="Red"> EEPROM_MEMADD_SIZE</font>, pBuffer, BufferSize));+ V1 n# j& g! C/ O  u# q0 y0 O) T  y+ t- Z
  5. }
复制代码

0 j. e- w. r# J! }  n& i0 {2 e2 f! ]
3. 初始化及其他操作修改。STM32CubeMX已经正确生成了初始化代码,因此除了下面的两个,大部分BSP的初始化代码都可以删除。
9 N0 C6 d$ d4 d
  1. void EEPROM_IO_Init(void)
    ' [" a: p! |+ b/ z& S7 W$ |  l
  2. {, r: o- q% I5 D5 f: r0 h: K) [# O
  3.   I2Cx_Init();8 B& [* S6 g" S# y& R
  4. }
复制代码
修改为MX的初始化代码; Q3 Q  b# I% n% I" G7 @
  1. void EEPROM_IO_Init(void); J* k: m4 \! k, ]
  2. {( T! S( I9 `. ^: A3 i' w
  3.    MX_I2C1_Init();
    ' T& q# g3 d& V" p
  4. }
    , N+ o9 n- ^5 }. a1 X- g( ^
复制代码

9 d  o, e" Z# V0 P4 ?修改函数,取消一些不必要的调用:
6 f% P2 x& j( k/ A+ X& P$ I
  1. uint32_t BSP_EEPROM_Init(void) {
    / ^2 J8 r) r! P
  2.     /* I2C Initialization */3 t3 S( ^, O# B) }+ ~: Q
  3. <font color="Red">//  EEPROM_IO_Init();</font>, b9 Y( X, _% A3 X6 z
  4.     /* Select the EEPROM address for A01 and check if OK */
    ) ^( m+ V7 z5 I# h2 ^3 Y
  5.     EEPROMAddress = EEPROM_I2C_ADDRESS_A01;1 x4 n; Z/ P+ l  f
  6.     if (EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) {
    - ?2 ?9 c& t( \3 ]' e9 T
  7. //    /* Select the EEPROM address for A02 and check if OK */
    5 a! X  q1 f% h2 [
  8. //    EEPROMAddress = EEPROM_I2C_ADDRESS_A02;
    $ D5 z/ z. ^- k$ k# m
  9. //    if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK); e5 c' t, R  \' t7 O* k
  10. //    {% ~* |- P- _$ e* ~- p! S: X" @! P
  11.         return EEPROM_FAIL;
    . r4 F/ X( P5 y# H* {+ N8 W
  12. //    }4 T0 m# `, |+ A  @
  13.     }
    ) [3 J) ]5 K# k! k4 S  I) N" z
  14.     return EEPROM_OK;
    ' X4 b7 Q. k! K5 `0 j
  15. }% s: S7 U  |$ J8 F) I
复制代码
: B% \7 _, u8 }. Y8 K# w: H4 R
另外,需要将stm324xg_eval.c中的 heval_I2c 变量实例替换为hi2c1。可以用查找替换或者宏定义。" l' Y' h% g, ^$ \8 V  ^( p
4. 使用例子# L# N! u) P& A7 g; z0 Q# q$ p
4.1 初始化
9 i: v' K* b% _1 ]8 R; s在main.c的  , G9 u( e- l  S( s
  1. /* USER CODE BEGIN 2 */) n0 Q& V: L2 Y) _
  2. BSP_EEPROM_Init();, }4 I4 W- i/ m. n! V" V5 z. J
  3.   /* USER CODE END 2 */
复制代码
或者其他适当地方添加初始化设置,完成EEPROM地址的设定。
3 K& A& \9 R# H6 [- a/ T4.2使用可以参考相应代码。如:
# {* m3 y  D3 l8 M, |
  1. #define EEPROM_CFG_ADDRESS       0x120       //和页面对齐
    / U$ |6 x7 i% f7 a* H/ `
  2. __IO uint8_t EEPROMConnected = 1;: n7 M0 j+ a  g8 m, m
  3. typedef struct {/ F( ~6 K" _3 c: [
  4.     uint16_t valide;1 W: m6 C5 |# b* ?
  5.     uint8_t databuf[16];2 o0 {8 E3 _, c; I& |$ T3 I0 e
  6. }CfgData;
    8 S$ b9 X; a( q7 t# y" ?4 V" h" z
  7. CfgData cfg; //全局的一个结构变量
    5 B; s; [! X+ M6 ^
  8. /**( y4 I3 [/ Y# H4 E
  9. * @brief  从EEPROM 中读出参数
    6 a- `" y- ^  r+ q: T
  10. * @param  无1 U: |6 u, e1 e, n1 a& j0 e
  11. * @retval 0成功 其他失败: 1 通信错误  2 无效设置9 c- f" y& [. p+ O! Q* V- Q. b
  12. */
    3 C5 _2 L2 b  V% A/ B
  13. uint8_t read_cfg_eeprom(void) {
    ! P1 B% T6 s+ h2 `$ \
  14.     CfgData cfg_read;6 ]1 Q. x- d7 ^( K% a: _# H0 o
  15.     uint16_t readSize= (uint16_t) sizeof(CfgData);
    % a5 u) ]$ p7 A2 o+ ~
  16. 6 w, M* d% S8 ^& Q4 }0 Y  V7 g
  17.     EEPROMConnected = 1; //超时回调函数设定
    , A6 C+ i' K  q0 \

  18. " Y1 Y4 G# p  Z2 _
  19.     /* Wait for EEPROM standby state */
    4 ~; [7 ^. L* V4 c
  20.     BSP_EEPROM_WaitEepromStandbyState();/ W3 U( G& r4 f: a3 t7 {  w8 q# Z

  21. ; |. f" Q: {/ J
  22.     /* Read old parameter in EEPROM */: o; @* v5 p" c# X6 K
  23.     if (EEPROMConnected == 1) {( L% q+ q2 t* B3 G, M
  24.         /* Set the Number of data to be read */" c0 N  b2 M1 k, G1 [* O! u
  25.         memset((uint8_t*)&cfg_read,0,readSize);
    ' {+ s3 E- `2 s$ N
  26.         /* Read from I2C EEPROM from EEPROM_CFG_ADDRESS */
    * H, t! S- Y, R7 ?+ R
  27.         if (BSP_EEPROM_ReadBuffer((uint8_t*)&cfg_read, EEPROM_CFG_ADDRESS, &readSize) != EEPROM_OK) {
    1 j  J% m* s, t$ b
  28.             return 1;  //通信错误* z) E- y. S9 u& B; K
  29.         }) R  D" Q( ]/ v& F8 O9 ~
  30.         if (cfg_read.valide == 0x55aa) {  //有效的
    * [4 Y2 q1 b( @$ i7 V4 J/ E
  31.             memcpy((void*)&cfg, (void *)&cfg_read, sizeof(CfgData));
    1 c! p9 T8 ?1 A( o! \2 {
  32.             return 0; //正常
    & K+ ^" G+ }" x+ d# `6 \
  33.         }4 y7 ?: A0 B1 z% |0 `( a
  34.     }
    " r& w& R1 @. E/ l8 H" V  ^. Q+ u4 q* ?
  35.     return 2; //无效设置8 F; Y  s6 R( _
  36. }
    ! m  U: z% F4 a. L* Z% T1 R
  37. /**3 `8 B# m" q" b$ l" a
  38. * @brief  保存参数到 EEPROM 中* D' T3 }* i0 N* l
  39. * @param  无5 {" T8 d/ b7 Z6 e8 {& c; s
  40. * @retval 0成功 其他失败
    $ |9 Y& A) B7 ~( }( T
  41. */
    1 V, N9 S, ]; j) g  `
  42. uint8_t save_cfg2eeprom(void) {( O5 T: a; w( P7 x* ]" |7 i2 f% f

  43. ) C6 ?) y" A: Y# u
  44.     EEPROMConnected = 1;+ m0 x, u9 v! m, \) k- l+ D7 B5 I
  45. $ T$ ~* u( k8 l7 U, c4 ^$ R. o) O" T
  46.     /* Wait for EEPROM standby state */
    ! H9 ~( V: ]  B- r
  47.     BSP_EEPROM_WaitEepromStandbyState();9 V: U2 ^, Y; _- g5 B$ r* X# u
  48. 3 d# K  L) }7 _5 W% \$ E
  49.     /* Write new parameter in EEPROM */. k! h8 C2 Q0 _+ N: L- B
  50.     if (EEPROMConnected == 1) {
    8 W! t! U& M* C" v1 f- ?  ~
  51.         /* Write on I2C EEPROM to EEPROM_CFG_ADDRESS */, O& k) O3 n$ g2 }
  52.         if (BSP_EEPROM_WriteBuffer((uint8_t*)&cfg, EEPROM_CFG_ADDRESS, (uint16_t) sizeof(CfgData)) == EEPROM_OK) {( `0 k- h; X/ {8 y/ z/ U) Q
  53.             return 0;
    " e4 Z# J, q3 m9 i
  54.         }1 O( d% S% }  d7 i
  55.     }
    ( R0 w3 M7 |6 F& X$ l; V
  56.     return 1;
    " J- b7 e. r" L
  57. }" b. N7 q7 V, M0 C3 n' @5 h
  58. /**
    & P* i# ~/ K2 n9 r! o
  59. * @brief  Basic management of the timeout situation., @, C' s7 q1 f  h! x. _* R" q  S& ^
  60. * @param  None.  k$ U* g) T3 D
  61. * @retval None
    0 I( g# y( `" u
  62. */  T5 @% Q8 n  j2 \$ r
  63. void BSP_EEPROM_TIMEOUT_UserCallback(void) {
    . s$ I* x9 L" v  ~+ O7 T4 A
  64.     EEPROMConnected = 0;- p9 t$ m; t: F2 r  A0 Z4 v# J" L* M
  65. }1 ^% j, X+ a5 E+ v5 ~
  66. 7 s* ]: ^- [5 s1 P! [' f. ?
复制代码
经过调试并下载到核心板运行,测试结果正常。所用软件环境:
" X# t) ]# B/ X+ `9 }4 k' o# m7 ASTM32CubeMX 4.15.0$ Y5 _8 V+ [. l5 b4 e8 h- k9 u6 B
STM32Cube_FW_F4_V1.12.0
9 a  Z# [) b- [GNU ARM C/C++ for eclipse 2.5.1.201604190915 6 }' K* @- y+ U
eclipse 4.4.2 luna9 M8 g, g& a7 ~  i: J8 c
Debian sid: Linux Debian 4.5.0-2-686-pae #1 SMP Debian 4.5.4-1 (2016-05-16) i686 GNU/Linux
+ o- X- `" N6 ?# {0 ~1 u) y
8 Z  G7 b% l* S8 {) F
- w' n6 \0 d/ M  ?# a- W
收藏 评论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 手机版