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

【NUCLEO-L476RG开发】硬件I2C 精华  

[复制链接]
netlhx 发布时间:2015-11-8 20:18
本帖最后由 netlhx 于 2015-11-8 20:35 编辑
$ ]8 d- `5 H' d
, o3 t0 A2 O( ]" ~  O* UNUCLEO-L476RG到手一段时间了,今天来测试一下硬件I2C的操作,听说很多BUG,试一试看如何。
% c4 N* l+ w9 D- b/ j9 V9 k7 h" g. ^: \/ Y& V
准备用I2C来访问AT24C02 EEPROM,将数据写入到EEPROM中,然后再读取出来,验证读写操作的正确性。! l( T6 F6 ]! ]/ w. l% Y5 d( F
; G  V& p6 i& N; C* F
硬件平台如下
2 l4 O2 p7 X, A" }0 a& [% B& c) l( V  u9 q9 K" E6 H; {
2 A8 i! ^# T: L: }- D" Q
NUCLEO-L476RG
6 k8 K5 W0 Q7 n) p) O/ I: C- c$ m# P4 \" {8 d0 N& S
nucleo-l476.png % l1 m$ i, B8 n3 F

- m- N6 {5 o/ R" P" x" M/ n前段时间FSL的KL02Z套装,上面的MINIDOCK扩展板上恰好有AT24C02,所以借过来用一下,FSL不要生气啊
5 m" i* }( k. H0 H+ M; u5 J! J; Z& m& Q
minidock.png
6 C% H  _! Y, S
# `# g/ X/ y4 Q( C, u/ m3 D( _0 ?0 i) E标准的ARDUINO接口,放到哪都行。合体照。' Y0 P' k+ e+ y. T3 J* [7 o/ p
/ Y8 j2 g" C0 m
test.png
) |7 ^4 ^5 F/ \
7 w3 m9 ?4 q/ `- o6 c1 j; o6 [2 V硬件连接及原理图' p) s! W' K# }& s$ f
! G* w; Q4 i6 Z3 B9 s
MINI DOCI上的AT24C02连接
; B) V- [+ X5 B
) N' v9 w0 h! L' e& V QQ截图20151108162714.png 5 p/ g0 n, {9 H/ c" Y' P$ D+ o

! V! s' E, |/ a' ]' O. pARDUINO接口:SCL及SDA$ V* o# v. P" N' m

7 Q0 U9 D/ p* e QQ截图20151108162724.png
. `* Z* \& r" ?  g& I: M7 G
  H+ Q4 _. d3 Z) G4 x+ ENUCLEO-L476RG上对应的接口# f! ]& }# ^: l+ m

5 T* a& r* g$ m( c1 a nucleo-l476rg-review-16.jpg 7 Q2 Q9 X0 r# y0 \' V7 h) w

5 \, o. _6 i0 {' E0 v% A% p, z% ~/ v+ K
写程序之前,要了解硬件的基本特性,首先是STM32L476RG上I2C接口支持的特性;其次是AT24C02的特性。$ G* P- p; _2 s( W$ e8 U7 [6 O) Q/ j% S
* z4 B$ Y2 {5 w0 h' ^
STM32L476RG的I2C功能框图如下" n, o' s2 B4 C/ @/ [$ d- [9 u$ K

) l" V/ `" m/ C3 L QQ截图20151108154725.png & t1 q7 \) w+ n) l/ X

  h# x0 ?- N4 C/ H! G- ~值得一提的是,L4的I2C有自己独立的内核时钟,可以在SYSCLK、PCLK及HSI中任选一种做为I2C的内核时钟。另外L4的I2C支持三种不同的通信速率:100KHZ, 400KHZ,1MHZ。由于AT24C02只支持最高400KHZ,所以这里就选择400KHZ做为内核时钟。
7 Z* C0 I5 w6 }3 e$ T& B$ w- h8 _( N, S; o
创建I2C测试工程,建立过程略。几点要注意的地方。4 q$ s9 [1 h  o& h) }2 K
* I* P! L" p* C: |9 c; Z
首先,本例程中使用的是I2C1,对应的SCL及SDA引脚为PB8及PB9,时钟配置后SYSCLK为80MHZ。
! Q! g9 K9 @' J; ~( a8 ]6 ^. [9 q
* L; U% }1 f2 M7 @; M/ d  YI2C硬件配置参数如图
, t5 ^0 o' F3 {% v
; H% X6 M$ V5 V( Y7 S- A8 v" c QQ截图20151108172523.png   u* E1 L' m: U& r7 J- {2 l, x" p
) G0 Z' Q1 c2 q5 y1 _
速度有三种可选:标准,快速,快速加。另外针对不同的特定应用,可以选择设置上升和下降沿的时间,以纳秒为单位,范围为0-120纳秒之间。注意这个TIMING参数,是灰色的,CUBEMX自动计算并设置该值,不像以前的F0和F3系列,需要一个专门的工具来设置TIMING的值,够麻烦的。
: Y0 G3 n7 B! W5 F* G! O6 Q+ p0 j5 D; a) \- K3 f0 w9 n
下面是使用HAL库与EEPROM通信的主要代码。  N  v: C6 x2 F. B, |3 o
6 B9 p5 _1 x  I6 w" @
% u2 D. {1 H9 D5 ?" G8 f
  1. /* USER CODE BEGIN PV */
    . w7 C" j9 ]  f8 K: t$ P6 D
  2. /* Private variables ---------------------------------------------------------*/# _$ ~" m* R. h6 v0 q" i  L
  3. #define EEPROM_ADDRESS        0xA0
    3 o$ q3 B/ |3 l; k2 R
  4. #define EEPROM_PAGESIZE        0x11' C6 d3 f6 M; \: L
  5. #define EEPROM_TIMEOUT        1000
    8 y) w# C. Y/ P6 z, `

  6. + ~4 A1 i. I/ s' n( o/ g! ^. s
  7. extern I2C_HandleTypeDef hi2c1;3 i2 f: g0 S5 ]) S0 z- d

  8. # w( i3 G# T+ O$ F
  9. char msg[] = "This is a test!\r\n";' R9 a! J; k7 S" a; g4 i+ @& ]$ H

  10. % Y- F$ Y6 m" _
  11. char buf[40];9 a0 @7 x9 @0 m  S1 g1 f+ h6 X. `

  12. 8 i4 H. }, Z# a* `, k
  13. int16_t Remaining_Bytes;3 r: }! }8 l/ U8 G( f& ]1 ?" e9 a' Q8 O
  14. uint16_t Memory_Address;
    , T/ q+ V" v0 E& c( n+ w( T

  15. # F. o# |5 [+ a- X7 {
  16. uint16_t len;; |5 H$ c: q- r4 C+ c# o2 ?

  17. # U- f; s$ _& c0 F0 Q( s1 G
  18. ......
    8 H- |2 R+ Z. a
  19. ; Z4 P# \# r) h6 s
  20. //write msg to eeprom# N% u$ T$ M7 ~
  21. Remaining_Bytes = strlen(msg);
    ! H1 Y% \/ S3 A( [
  22. Memory_Address = 0;4 A3 L. v1 D; A. N% M- e
  23.         4 r3 m  `4 F8 \; J4 v- V) y
  24. while(Remaining_Bytes > 0)
    6 Z$ s5 n8 p0 {7 G" O* F
  25. {3 N# O! z1 Y% s8 ^' E
  26.       if(HAL_I2C_Mem_Write_DMA(&hi2c1, EEPROM_ADDRESS, Memory_Address, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(msg + Memory_Address), EEPROM_PAGESIZE) != HAL_OK)" I% _2 t4 o. U; I  \/ ^
  27.       {
    9 r" m& n7 [# B; ?9 f( G+ \0 [
  28.               Error_Handler();. M/ G7 Z* W; }! ^6 k0 a
  29.                         ' y) R9 F' _9 Y4 C) @
  30.        }$ y7 {. Y2 {+ R) H. A
  31.                 2 G2 ?% ?. [9 V1 a/ D5 `' r
  32.        while(HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)& q1 ^$ W" ]  J; F+ J
  33.        {
    6 Z* h! p; `# [$ M7 H2 N- |
  34.        }
    & o" w2 r# [0 }& D
  35.                 2 _1 G% v! n7 C# J( r
  36.        while (HAL_I2C_IsDeviceReady(&hi2c1, EEPROM_ADDRESS, 10, 300) == HAL_TIMEOUT);
    9 R: M' Z6 s4 [; E9 J/ N% i: o+ W
  37.                
    4 D& W8 q2 X5 h9 n
  38.        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    6 }& }6 a& s9 i" N
  39.         {: }6 U2 X% z0 c5 A
  40.         }& n0 @0 q* {6 U4 U" Q7 F$ O5 D5 P
  41.                
    " U# z! H6 s( p! m
  42.          Remaining_Bytes -= EEPROM_PAGESIZE;5 {1 }4 F' c, ~' P3 o* S3 ?
  43.                
    / v& k: A2 q8 x6 e. F
  44.          Memory_Address += EEPROM_PAGESIZE;
    % x/ _3 t$ X# G
  45.         }
    / m4 \  d/ u7 Q
  46.         " J$ ^4 M# d0 w! ~
  47. //read msg to buff
    ( W( j1 h4 n1 ?# V# G6 \

  48. / l( w% M; m/ `7 H
  49.   if(HAL_I2C_Mem_Read_DMA(&hi2c1 , EEPROM_ADDRESS, 0, I2C_MEMADD_SIZE_8BIT, (uint8_t*)buf, strlen(msg))!= HAL_OK)+ g. q" e  Q- C
  50.   {; o$ S7 z- C' Z( ^" y- e& V
  51.     /* Reading process Error */6 f0 t) I0 Q( ]! e8 ^% N
  52.     Error_Handler();        ! ^/ ?+ Z5 J7 Y1 ?- Z1 ^% }/ h
  53.   }9 C9 r' o' |5 l, Y) P
  54.   
    3 ?4 z* ?( [. ~* @7 N& H8 u3 b& m! @
  55.   /* Wait for the end of the transfer */    u$ d( G8 M  Q
  56.   while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    " B1 _' V+ B# v4 Q, m9 H; q' T6 d
  57.   {0 \3 V, ^3 {3 x: d: s
  58.   }
    1 d8 `) F4 _$ V* C, Z* T; g* g
  59.         
复制代码

$ H, {/ ?7 ?8 i: A根据STD库中用户的反馈,I2C出错的原因主要由几方面造成,一是ST设计的I2C接口,通信过程中一些状态变量及标志位的设置非常严格,如果程序逻辑考虑不周全,会导致I2C停止工作,需要软复位后才能继续;另一方面,I2C接口在处理单个,双字节及多字节传输过程中要分开考虑,进一步将问题复杂化了;还有就是结合具体的I2C设备,不同的时序要求,进一步复杂化了通信过程。3 w: q* _% `; p0 A4 e
( E: Y2 E! _8 U7 G
这些问题在HAL库中都得到了很好的解决,为此,HAL库中设计了几种不同类型的API函数供调用。一类是通用的接收和发送函数,这类API函数将I2C接口视为类似于“流对象”,通信时从流对象中接收或发送数据;另一类则是类似于EEPROM之类的特殊存储对象,从这些存储对象中接收或发送数据时,都需要提供一个地址,以便准确定位。使用EEPROM来实验时,我们使用的是第二类API函数。两个主要的API函数原型及参数如下。
+ I: g+ x+ p. I) q) K- k, Q0 S* W6 ^) ~# w3 P7 ~) w8 G
  1. /**- T) J2 k0 V' m" U
  2.   * @brief  Transmit in master mode an amount of data in non-blocking mode with DMA
    ( H% u0 H7 ~' r  D2 k' j
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains6 _- y( ?9 Q, Z: l, x$ z0 U, V
  4.   *                the configuration information for the specified I2C.
    " S4 g" P6 m- ]" @2 {
  5.   * @param  DevAddress: Target device address3 O4 I. i3 K) `' q
  6.   * @param  pData: Pointer to data buffer) |. T) a1 X( f% ?* B
  7.   * @param  Size: Amount of data to be sent
    ( S7 h! e. l# p2 k& X1 G2 p
  8.   * @retval HAL status1 y3 i) _# G# g
  9.   */
    * T: Z* e% t# Y9 n) h, p
  10. HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size)
复制代码
  1. /**
    ! R- v, |* I5 |; q; U% U2 `7 e- {0 Z
  2.   * @brief  Reads an amount of data in non-blocking mode with DMA from a specific memory address.9 ]6 B6 T+ E: D% F( H
  3.   * @param  hi2c : Pointer to a I2C_HandleTypeDef structure that contains
    & M# {2 [7 q( t+ D
  4.   *                the configuration information for the specified I2C./ W+ A/ N: ?4 S
  5.   * @param  DevAddress: Target device address
    , |6 ^  o: {( W/ m7 v
  6.   * @param  MemAddress: Internal memory address
    , g: w) s' h7 A) s, j) y) L
  7.   * @param  MemAddSize: Size of internal memory address
    ) e; `, @' r5 c& |8 Z
  8.   * @param  pData: Pointer to data buffer5 m! a+ M; W& E* N' q
  9.   * @param  Size: Amount of data to be read
    2 K. }, j% O4 L) N& {- L8 K
  10.   * @retval HAL status, s/ i6 x' S) E$ L8 U
  11.   */
    % W' n% O9 Q. m! k- P
  12. HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
复制代码

- [  M" r/ D" Y0 [关于这两个函数的更详细的调用方法及说明,请参考API文档。
) B5 f, B" ]. f# ?2 D$ V( E# d7 [7 e5 Q* W0 r
注意在具体操作EEPROM的时候,还要注意,EEPROM分字节读写及页面读写两种类型,对HAL API的调用还要进行适当的修改。
) b! I0 p, V; W: N1 E  m. ]* m- P. z' V# j& [/ }% ^3 L
由于ST HAL API做了大量的后台工作,上面的代码看起来过于简单了。但实际上API函数在后台做了大量的工作,这不正是我们期待的么!
% }* m; I! F; y+ r" y* T2 V# j' Q! t) b9 `1 g) n- S* q
最后来看看运行结果。
1 K+ u9 q/ k3 j2 C( r* _$ K  V7 f! m  Q; K5 o! ~
UART打印的写入及读取取结果# S5 V0 P  A9 ^$ R) v% ]
. S, E- Z( [( \# v5 }' C$ j
QQ截图20151108200641.png $ ~( g/ J! m) U' s. K2 y6 W9 O
& `4 t: h  U% _- [9 R" d: b4 `" c
逻辑分析仪LA
/ ^$ P+ B( j) Y$ s+ M( s1 ?
0 O# @3 W; D5 Y& H; M2 m 无标题.png
, p. D3 a# S) P/ e" S% p+ T! D9 ~# v$ D. J7 j3 {: Z; D
I2C通信全程,LA分析结果
3 x. E! f& E, e, P4 M
* c' O! C3 ~% V6 h QQ截图20151108200233.png
6 I3 `) D+ w# G9 _' q9 l( V& ]3 v- }7 ~' n  \7 y' T+ W
开始通信,顺序依次是开始信号,地址,EEPROM写入地址,第一个数据字节9 q. Q2 f; G; r( c8 x9 j. u
; ^! \2 A0 s$ ?% X; b# N
QQ截图20151108200331.png " B2 C0 I3 p( Q' q# {$ g
/ q$ w( l( r6 [
字符0x0D, 0x0A, 结束信号。
0 V! P- K$ t3 \. O3 h7 I8 _
0 r9 B7 i% a; P) Z QQ截图20151108200410.png
. G8 J4 s  d7 W
0 j9 p3 r! N1 |接收开始,顺序依次是开始信号,地址,EEPROM读取地址,第一个数据字节
. A. S, n  y. M; |* F
8 v5 H. ?- S& w; \) E9 i QQ截图20151108200439.png
4 Q8 I4 j/ K7 q, Q+ b( N8 r( P# K3 B8 D% q& E- ~
读取结束# ^7 ^- J" A  }

6 \. s1 j* x  u7 [' ?0 P; ^ QQ截图20151108200502.png
6 ?. U  J8 X" g8 ~+ I9 i  C
% P; {2 \5 A& ~2 w0 @* m4 @: X% w! Z9 R4 X  u/ K( I* L0 M- T# B
+ _" D9 Y' P- o' c; n" u( K1 E
附工程
+ R2 P0 m" Z+ l& S; w6 S* y4 V. l% m9 f6 b  ?8 H. m
eeprom.zip (3.17 MB, 下载次数: 203)
赞 收藏 5 评论20 发布时间:2015-11-8 20:18

举报

20个回答
lulongqin 回答时间:2016-5-8 23:06:50
楼主,您好,我利用您的代码测试失败,串口只发送了“Write to EEPROM:和This is a test!”,经测试,程序在运行        这部分是发生错误:        if(HAL_I2C_Mem_Write_DMA(&hi2c1, EEPROM_ADDRESS, Memory_Address, I2C_MEMADD_SIZE_8BIT, (uint8_t *)(msg + Memory_Address), EEPROM_PAGESIZE) != HAL_OK)
$ R4 u/ V+ M" E) m                {
& ~& \, d7 L6 q' m9 E  A                        Error_Handler();
; c$ U: j: h; Z  W        };程序直接进入Error_Handler()函数,请问是什么原因呢?我检查了很多地方,还是不行,求指教,非常感谢!(测试环境stm32l476rg+at24c02,后来用了at24c16测试还是失败)
Inc_brza 回答时间:2015-11-9 00:43:23
对比过硬件IIC和模拟IIC,硬件的IIC直接被模拟IIC给打爆!
" p% j! y5 U$ q9 ^. R1、移植,直接秒杀不用多说
) p6 o* ]4 T; B* P8 \% d0 q2、效率,IIC的硬件通讯过程中用了太多的访问标志位,实际效率不会增加,一样是让CPU在耗,& I* P/ f! M& E- Q' `+ Z+ q* y
              所以,效率反而没有模拟IIC高,因为GPIO的反转速率轻松满足IIC的通信速率,所以& O2 J: ?$ o: i) t' \0 o) i4 i
              模拟IIC照样更胜1筹。
0 Q% x0 s! @6 c8 ]$ m3、复杂性,ST的通病,反而模拟IIC更加把协议变得很直观。, b8 H0 u2 v" J5 b. E4 L* e
纵上所述,感觉这个硬件IIC就是个鸡肋。
埃斯提爱慕 回答时间:2015-11-9 21:27:00
提示: 作者被禁止或删除 内容自动屏蔽
陈金华 回答时间:2015-11-8 20:26:37
沙发                     
netlhx 回答时间:2015-11-8 20:28:17
地板
qianfan 回答时间:2015-11-8 20:42:46
这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。
Paderboy 回答时间:2015-11-8 20:57:26
多谢分享啊。。。。
2958155267 回答时间:2015-11-8 21:06:47
Hal库把底层都写好了,所以硬件i2c还是较简单的
kingsings 回答时间:2015-11-8 22:56:32
楼主好牛,两个板子都有了。而且还有逻辑分析仪
alvin_ 回答时间:2015-11-9 08:41:14
逻辑分析仪自己买的吗大神总是一鸣惊人啊
黄小狼 回答时间:2015-11-9 08:51:37
前来学习观战中。。。
奋斗逼 回答时间:2015-11-9 09:01:57
强大
戏如人生 回答时间:2015-11-9 09:05:51
逻辑分析仪都用上了啊??多少钱啊
watershade 回答时间:2015-11-9 15:24:45
楼主的逻辑分析仪花了多少钱?便宜的话推荐一下吧
aabird 回答时间:2015-11-9 16:52:41
这个厉害,虽然IIC很多人都觉得不好用
netlhx 回答时间:2015-11-9 18:40:19
QianFan 发表于 2015-11-8 20:42- }. G9 O5 @7 ~4 d' ~
这个逻辑分析仪是啥牌子的?多少M?那个打标线不错。。。

& y( d% c3 r$ N% n; h! J梦源的牌子吧,100M
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版