找回密码
 注册
关于网站域名变更的通知
查看: 5175|回复: 6
打印 上一主题 下一主题

I2C七宗罪之第六罪

  [复制链接]
  • TA的每日心情
    开心
    2023-5-19 15:05
  • 签到天数: 339 天

    [LV.8]以坛为家I

    跳转到指定楼层
    1#
    发表于 2019-3-20 14:08 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
    本帖最后由 EDA365_PCB 于 2024-1-22 17:45 编辑 - V1 S6 v% }7 C7 T
    3 }7 F  a7 M, @- M) A! J; |
    I2C七宗罪之第六罪——枯燥的协议
    # L$ e( E* d/ t
    EDA365原创 作者:John
    % W! C9 y& U( G" [% k* U) N
    3 t6 g$ T: m- @& e0 N! X
    9 B, J) W& d7 Q; c. Z' Q2 w0 x$ s( ?
    ' B! v2 p% M" Q2 B! r5 |) J7 \/ T6 U/ v
    * c; Q* K6 n% v9 C: P- B& Z6 f) m/ u. ^9 Q
    越到后面的几宗罪,难度越来越大,请读者要认真仔细的思考,确保学为己用。
    ! j' q( e- o: b9 I8 z6 ?9 K# c1 p- u" O" f: I" f% `) N
    2 P7 `4 U" S2 D  R! d先来讲个有趣的故事,我们在大学里喜欢去图书馆自习的时候抢位置,特别是喜欢抢靠近漂亮女生旁边的位置,可以一边上自习一边欣赏美女,^_^  m6 U8 }- t2 @1 [( t( C7 }! K( {. C* }2 G. }' u! O
    4 _2 l* c9 J' b9 C
      k' F; X, l6 n  [

    & I' t0 B" ?& k9 M2 V当你要临时离开一会儿的时候,方法也比较简单,就是放一本书在椅子上,很多时候当你回来的时候却发现你的书被人拿开了,椅子上坐着的另外一个帅哥和旁边的那位美女在攀谈,恨的牙痒痒啊。0 ]# Z- b  l% P  m% l" R+ V8 a  Y
    8 X; {  D- r1 X& F- ]& w8 b8 W4 R/ p: H0 ]
    你能做的就是等那位帅哥和美女聊完走人,你再回到那个座位上,可是你却沮丧的发现,刚刚旁边那位美女也走了,换了另外一位男的,唉,人生最悲惨的事情不过如此。* w. I" l6 ?- c, V. K% y5 D  H% v
    6 f0 U2 i7 P1 a2 K- u9 W下面给出一张图,大家来看看是否存在问题。这张图是用I2C协议分析仪抓出来的,乍一看也没啥问题,该有的都有,特别是最后在Stop之前的NAK也是有的,但真的是OK的吗?9 r* s, r$ x+ Q0 F6 W+ i+ v& f# Q
    我们再来看一张图。; z, c' c9 r& B: G2 W1 R

    # X. p. f) a* Q1 m0 g2 p
    对比这两张图,我们得出:这是一个读数据的操作。
    - n7 y. {5 ~# p. ~3 ]2 o0 Q' w* _, L5 C$ h, @
    7 A$ K1 i7 q" d- l要找到第一张图的问题其实不难,我们只要仔细核对就可以了。( l0 ~4 ?  u3 Z& d) Y( n; ]
    5 ^6 X4 G: i) [% [& g3 F6 j- Q1 {9 X' r0 b6 B- \1 l
    下面是核对出来的结果,我们发现在第二个Start之前,多了一个Stop。 这样一看,这个错误还是挺明显的。4 z! N/ u3 Z5 S+ u4 U$ _( J8 x, a' f2 b. u2 w; V
    ; c; {- s9 s1 m: G. Q- q# l5 x( l: R0 }
    说说总是很容易,软件工程师在代码里构建这个时序的时候,很自然会认为,前面第一笔的写操作(把Word address写入Slave的指针)已经结束,后面的一笔,读操作开始之前就应该Stop掉。
    为了清洗的说明,我们列一个顺序如下:4 K& j' t: P$ v  n  B" y. D; M# P+ r
    8 K6 Q3 [& d5 Q2 C( j- N: A
    & s2 f/ ?7 r! p  l6 x6 x% c1.Master把要读的数据(或者寄存器)的Address先写入Slave,这里要注意理解好,这里Word Address相当于是一笔数据;
    * Z, u$ U4 d' X2.此时要注意整个读操作刚刚进行了一半,千万不能加Stop;7 ^" _! G1 {7 Y, y  z; \4 V# c
    3.Master在收到前面写操作的ACK后,发一个Start;; |0 i- l- \0 W4 \" X
    2 @6 Q2 P) Y& J; d, n4.Master再发一次Device Address,然后开始接收读的数据;/ M7 M) T; t& \, w7 j' p
    . I8 d$ u7 b" O  S& m& J9 Q& d! k5.Master收到数据发一个NAK, 然后再发一个Stop结束整笔操作。
    % g+ M6 p5 E3 V) V( P" ]
    " g" X, }# u; v3 i* D; i有人问,既然我们在第二个Start前多加了一个Stop,也没有见系统报错,一切正常啊,有时候访问还是成功的,这到底是为什么啊?, g( W  ^+ x6 q
    $ U9 L; s+ ]% F, Z2 ^" |0 V0 J7 d  Y1 C2 r( Z+ N  V
    这里有个原因很重要:因为读操作最后是有Master发出的NAK + Stop来结束掉的,而NAK是SDA-HIGH,所以即便有时候操作不正常,只要不操作SDA(SDA默认的电平时HIGH),也能得到NAK误导对方。' S6 H+ a- M, M& c$ K
    & g% Y6 k8 A1 O. H! t
    我们继续来说一下,如果第二Start前面多了一个Stop会产生什么样的现象?" h# {' S( Z6 Y! ~- |# Z" g
    " t. H3 g, Z: i& b9 G4 I3 F9 p- T) [7 k5 j
    这是发生在ONU光猫上的Issue,现象是:从光模块SFP读回来的数据值总是不对,反复试验发现偶尔也能读对,但是写操作都是准确的。& P" X/ |" |  e9 X; }
    % d  X" F& t  ^: l2 I! e* ]# j2 w3 _; q( s$ {' l- h$ V6 l
    这里一定会有人问,你读操作不正常,怎么知道写的是对的啊? 好问题, 我们通过设置环回和打开/关闭光模块等写寄存器操作,反复确认我们写寄存器的操作是准确的。
    5 B9 `( O2 f. T* u5 x2 g3 Z; }" G0 ?9 D9 B3 i8 y
    6 Z5 t; M! p. U3 u3 k我们来看光模块的I2C读写标准SFF-8431里面的图,可以看到一次读操作和前面叙述的一样,分为两个部分,中间用一个START隔开。% H; e0 o! S$ D4 I8 e/ k6 K
    1.Master写device address =0XA2和写命令" B8 s- B8 J; p3 B
    2.Master发出word address 0X6E! S) I8 `+ }2 s5 o4 v
    3.Master插入第二个Start. b$ E9 H' K! C' J3 q5 F: [8 L& K
    7 u$ g5 L$ ?; E7 _9 }& x4.Master再次发出device address =0XA2和读命令6 K7 f# k0 D$ U! I# {' n& K  G5 x) B7 i6 k, l
    5.Master接收光模块的数据0X82" c; ~# y" N' a4 s' }
    6.Master发NAK8 u8 E1 j7 Z' f2 B- x( u/ L
    $ q8 U2 W# W$ t+ R5 r. E7.Master发Stop结束本次操作
    2 d& {/ x  o4 J" L注意:图中黑色部分是我们在Vendor的平台上用准确的方式读写抓到的波形。* Y& S, P' q, M- _
    9 S( L& E8 y* d" m7 z9 `
    , Q$ @7 W; y6 U! O1 U如果按照上面所说的,我们在中间加了一个Stop会产生什么样的现象呢?
    ' p# U% ~' t4 y1 R' p+ w7 c+ a- D: c, `5 n
    * |8 q( V: O' V4 A3 p0 r( A( C9 z$ ]为啥读数据会不正确,但是I2C总线并没有出错信息吖? 前面我们已经林林总总的叙述了一些,下面给出最终的描述。
    . h& u! u) K. ?
      f# M0 r' D/ p2 r! t4 m; g" J$ g. F看下面这张图,是我们和Samtec的FAE在出问题的板子上一起抓到的波形图,很明显我们看到多了一个Stop,下面我们来进行分析:8 D0 \/ J4 H/ S"
    1.Master写device address =0XA2和写命令& Y2 j% y8 A) X
    2.Master发出word address 0X6E$ B/ h9 Z" Q4 w- Q/ U! D. X  G* J2 g+ m/ r3 i+ Y) C  |1 |
    3.Master多插入了一个Stop+ ^9 p6 ^% \! [& i
    + g7 z3 m/ [. h, N* m' _4.Master插入第二个Start
    8 R% p, w+ C; b' B% H& ?注意:下面被插入了一笔完整的写数据的操作。. H; o8 l% M# K# \2 n7 g
    ' Q' T7 J8 Y4 [7 l; p4 p. B$ d# \* S) k4 `: ?5 r5 H# ^/ z
    5.Master又发出device address =0XA2和写命令$ J. U2 V  {  I3 P1 E3 z# n% r8 W
    6.Master发出word address 0X7F- }" i  i  e4 b+ P0 @4 e
    7 {, Z. v$ l$ n% P3 U! A8 x7.Master发出写的数据0X809 c7 w$ H! B. F( e7 F9 T. ~0 Q
    注意:开始接着上面未完成的读操作继续( r4 v* {" j7 \
    3 ?4 ?: ]  U, q9 C: x$ f
    / K7 M( t# u5 e+ T8 I8.Master又多插入了一个Stop
    ! ?1 S7 l, S5 u8 n9.Master又插入第二个Start* E' \$ G( @* |2 n' [: f  Q" g3 K  n* z" l- t3 D
    10.Master再次发出device address =0XA2和读命令9 L; O% k! B- |+ g
    $ j1 T* U4 ]& q# }* o/ M11.Master接收光模块的数据,我们看到读到的数据是全0,为什么呢?& L6 S5 l1 m/ O4 n) F- P
    / ~1 O7 \- U" P) j/ h12.Master发NAK7 F, c" ?2 K7 v& G' U. s. u3 [0 c) h  x" G3 z1 Y
    13.Master发Stop结束本次操作. R9 I5 V6 h4 Q, P/ w
    : `9 ^) P( O  c* v+ j& b; I$ `9 O, N6 q
    相信很多人已经晕了,这到底是咋回事啊?- B' Y: O6 }4 G; M6 x+ `9 k/ z# _% h4 w
    : i/ j( D- ]0 L* S# a2 D
    ( F$ O0 e6 u* r6 V0 j原来:一笔读操作,由于中间多了一个Stop,所以系统软件进程误以为前面读操作完成了,所以横空插进来一个写的操作,并且这里的写操作准确的完成了。- E9 w; X# u4 `: D4 V" S% W9 g
    7 i. Z9 v. R9 R/ g  a" C5 l. _+ T. G4 h
    在写操作完成了,我们看到Master试图继续完成刚刚被中断掉的读操作,其实这也可以啊,大不了分两次,只要最终数据能准确读出来也行,可我们此时得到的数据却不是刚刚的0X82了,而是0X00,这又是为什么呢?
    我们来结合这张图描述一下发生错误的过程:1 ?" S0 q9 U; |/ i$ T% \' ]# C6 I6 D
    ; o; m, j& ?9 b5 M
    1.Master开始读操作的第一步把0X6E写入Device;
    . E# c! {. R! d. q  q- w- x1 m2.此时被插入另外一个写操作;- j9 u2 ~# a, R/ x+ ~
    * }+ [- a0 E( C( c3.写操作顺利完成并且把Pointer写成了0X7F(注意已经不是原来的0X6E);# S& x' U* t- {: T1 }8 l( W% N# ~8 {- q5 n% k2 I7 I# m! r
    4.Master继续刚才被中断的写操作;. T& H) r$ K6 V. B- }' g- u- p* x$ e' a/ s: n) h, N9 t
    5.注意此时Pointer的值是0X7F,所以读到的值是0X7F这个地址的值。
      F9 X8 u, c3 Y  o0 y! l+ q  c1 ]9 Z/ V. f1 g, f- P0 z( `$ f! Q/ G* K/ J* e
    这里就清楚了:一次完整的I2C读操作访问,如果中间加了不应该有的Stop,就会被其它进程强占,从而插入另外的写操作,导致访问memory或者寄存器的地址指针被覆盖,Master然后接着完成刚刚被中断的操作,也不能正确读写到要访问的值。
    , Z! H6 G. F, R  g4 E, H* n. A( n$ d2 ?
    9 L9 {- U- U/ @0 ?0 K. _/ s这里分享几件有趣的事:: q7 A, D- x% B
    1.由于只是读有问题,写操作是好的,所以产品的功能是OK的,在市场卖了那么多,都没有人发现这个问题,也蛮搞笑的;
    3 \! Q6 t( G/ b5 ~4 p2.I2C的读操作一直NAK操作是SDA=HIGH, 由于SDA默认就是High(前面讲过Open drain和上拉),所以即便设备没有做什么? 也会让等待NAK的设备误认为NAK已经产生了;
    , f! A+ i$ V( ?* V  U3.系统软件有时候是会和硬件打架的,所以相互合作才能找到问题的根源,否则相互推责任只会让解决问题很困难;2 a8 _/ z1 D5 G! G
    4.发现问题并且解决问题,写个文章很简单,但是调试的过程却是痛苦的,特别是I2C这种接口,一共2根线,很多人比较轻视,这是不可取的。
    8 U8 c3 [& |2 E/ I6 v# @
    注:本文为EDA365电子论坛原创文章,未经允许,不得转载。* N% v: U/ a# n2 ?5 f

    本帖被以下淘专辑推荐:

    该用户从未签到

    推荐
    发表于 2020-5-11 10:47 | 只看该作者
    文章真的好

    “来自电巢APP”

    该用户从未签到

    2#
    发表于 2019-5-16 10:31 | 只看该作者
    生动的文章,分析得有条有理,赞~~!

    该用户从未签到

    3#
    发表于 2019-11-19 18:16 | 只看该作者
    各位,有john大神的联系方式吗,很想认识一下,我邮箱2929219135@qq.com
  • TA的每日心情
    开心
    2020-12-3 15:53
  • 签到天数: 38 天

    [LV.5]常住居民I

    4#
    发表于 2019-11-26 18:33 | 只看该作者
    看看,学习一下

    该用户从未签到

    5#
    发表于 2019-12-18 20:38 | 只看该作者
    谢谢资料分享

    该用户从未签到

    7#
    发表于 2023-6-12 19:01 | 只看该作者
    很多图片没有加载出来,楼主能麻烦再更新下图片吗??

    “来自电巢APP”

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2026-4-18 22:10 , Processed in 0.109375 second(s), 30 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表