EDA365电子论坛网
标题: I2C七宗罪之第六罪 [打印本页]
作者: alexwang 时间: 2019-3-20 14:08
标题: I2C七宗罪之第六罪
本帖最后由 EDA365_PCB 于 2024-1-22 17:45 编辑 - I6 }7 n6 t0 B) \2 @
! O; \* }/ s1 n8 m+ f/ o, \I2C七宗罪之第六罪——枯燥的协议
$ F2 C1 X2 F! ]EDA365原创 作者:John
% W! C9 y& U( G" [% k* U) N
. H) }" l( q8 V3 h* v7 `) v2 M+ x4 h: Z
' B! v2 p% M" Q
+ Q, c9 ?; J( A
* c; Q* K6 n% v9 C& ^( ^8 u9 \/ x L0 h
越到后面的几宗罪,难度越来越大,请读者要认真仔细的思考,确保学为己用。( u! Z" W* S* N+ S' E
- u" O" f: I" f% `) N5 w1 Y c. |* v% D" ^
先来讲个有趣的故事,我们在大学里喜欢去图书馆自习的时候抢位置,特别是喜欢抢靠近漂亮女生旁边的位置,可以一边上自习一边欣赏美女,^_^ m6 U8 }- t2 @1 [( t0 E+ X" Y7 ]0 y) A! ^
4 _2 l* c9 J' b9 C8 |) {' Q+ Z$ I" Q( e4 Z* \
" w; ~7 f6 B! L9 z& u9 ^; J
当你要临时离开一会儿的时候,方法也比较简单,就是放一本书在椅子上,很多时候当你回来的时候却发现你的书被人拿开了,椅子上坐着的另外一个帅哥和旁边的那位美女在攀谈,恨的牙痒痒啊。0 ]# Z- b l% P" A9 L" O- v: e$ m$ j, m; `
8 X; { D- r1 X& F- ]& w# s$ I3 A- z0 ~ s/ p5 Y
你能做的就是等那位帅哥和美女聊完走人,你再回到那个座位上,可是你却沮丧的发现,刚刚旁边那位美女也走了,换了另外一位男的,唉,人生最悲惨的事情不过如此。* w. I" l6 ?- c, V. K% y5 D H% v
! y/ ]! v/ M" W3 h$ o) p下面给出一张图,大家来看看是否存在问题。这张图是用I2C协议分析仪抓出来的,乍一看也没啥问题,该有的都有,特别是最后在Stop之前的NAK也是有的,但真的是OK的吗?9 r* s, r$ x+ Q0 F6 W+ i+ v& f# Q
我们再来看一张图。4 ?5 A) T! ^% r# z- x2 x
* e6 {& \" {- k t3 @# {; | 对比这两张图,我们得出:这是一个读数据的操作。 u$ T$ S5 m$ o6 @: n# N @
2 o0 Q' w* _, L5 C$ h, @' m# |0 r0 d7 z ?( X7 P
要找到第一张图的问题其实不难,我们只要仔细核对就可以了。
% R( K" Z$ g2 [% B6 Z+ M5 ^6 X4 G: i) [% [& g3 F6 j- Q9 v6 ~2 ?0 ~4 J
下面是核对出来的结果,我们发现在第二个Start之前,多了一个Stop。 这样一看,这个错误还是挺明显的。4 z! N/ u3 Z5 S+ u4 U$ _( J0 u+ \7 g% @/ \8 O, n0 B
; c; {- s9 s1 m: G" y: |. F! y# W+ k8 l- s! J1 q: ~4 f
说说总是很容易,软件工程师在代码里构建这个时序的时候,很自然会认为,前面第一笔的写操作(把Word address写入Slave的指针)已经结束,后面的一笔,读操作开始之前就应该Stop掉。
为了清洗的说明,我们列一个顺序如下:4 K& j' t: P$ v n B" y. D; M# P+ r
- ?% p* L3 q5 J6 l2 r; Z( R; B/ D& d3 Z7 F( K
1.Master把要读的数据(或者寄存器)的Address先写入Slave,这里要注意理解好,这里Word Address相当于是一笔数据;
7 x/ ^4 H6 t* n$ ?8 I B" B- U2.此时要注意整个读操作刚刚进行了一半,千万不能加Stop;
9 w7 V; I) V" A$ R! G: w$ b3 u3.Master在收到前面写操作的ACK后,发一个Start;; |0 i- l- \0 W4 \" X
% ^& J: A3 s# m( R0 P. y4.Master再发一次Device Address,然后开始接收读的数据;/ M7 M) T; t& \, w7 j' p
2 c o% ^0 p* s: M( O5.Master收到数据发一个NAK, 然后再发一个Stop结束整笔操作。
0 j! g5 k. m% n) i2 n/ t
" f. U0 z# v% K- j" t有人问,既然我们在第二个Start前多加了一个Stop,也没有见系统报错,一切正常啊,有时候访问还是成功的,这到底是为什么啊?
8 G2 P; b o9 L: Y2 r$ U9 L; s+ ]% F, Z2 ^" |0 V( a' P% e( n- d3 j' f
这里有个原因很重要:因为读操作最后是有Master发出的NAK + Stop来结束掉的,而NAK是SDA-HIGH,所以即便有时候操作不正常,只要不操作SDA(SDA默认的电平时HIGH),也能得到NAK误导对方。! x6 [7 v9 b9 n$ `+ C2 }
: V( R2 W1 Q/ \我们继续来说一下,如果第二Start前面多了一个Stop会产生什么样的现象?
; z4 _4 Y& Q: e9 E4 a9 e6 W" t. H3 g, Z: i& b9 G4 I
! p% z( e0 J" A8 [这是发生在ONU光猫上的Issue,现象是:从光模块SFP读回来的数据值总是不对,反复试验发现偶尔也能读对,但是写操作都是准确的。& P" X/ |" | e9 X; }
! J5 }8 P$ N; y$ y; ]2 Y' H5 l1 I2 u3 b, E: w
这里一定会有人问,你读操作不正常,怎么知道写的是对的啊? 好问题, 我们通过设置环回和打开/关闭光模块等写寄存器操作,反复确认我们写寄存器的操作是准确的。
/ T- z' |1 e9 r/ h1 y3 Z; }" G0 ?9 D9 B3 i8 y5 o3 V8 L$ l, @; _! R# H
我们来看光模块的I2C读写标准SFF-8431里面的图,可以看到一次读操作和前面叙述的一样,分为两个部分,中间用一个START隔开。% H; e0 o! S$ D4 I8 e/ k6 K
1.Master写device address =0XA2和写命令1 Y! l5 O- l$ k! t" L2 R9 N4 ]* U" j
2.Master发出word address 0X6E
0 }5 n; a' a* Q% }3.Master插入第二个Start. b$ E9 H' K! C' J3 q5 F: [8 L& K. }" ^+ d7 b" H8 l' Y1 z2 f
4.Master再次发出device address =0XA2和读命令6 K7 f# k0 D$ U! I# {' n
7 O- P: ^3 {) U) D1 F) _5.Master接收光模块的数据0X820 C b% ^! P" G8 A( @
6.Master发NAK8 u8 E1 j7 Z' f2 B- x( u/ L; L2 S% r9 t7 S6 E7 |/ g& a
7.Master发Stop结束本次操作! T- s! ~5 d2 y: F8 N. h
注意:图中黑色部分是我们在Vendor的平台上用准确的方式读写抓到的波形。/ |) `# f( W$ |8 b, J
9 S( L& E8 y* d" m7 z9 `& A' P, \ i4 k* @* ~8 H
如果按照上面所说的,我们在中间加了一个Stop会产生什么样的现象呢?
& o/ s3 |. \7 [, W+ a- D: c, `5 n
3 H* T/ ~, x/ R0 ?* w; D8 p, a为啥读数据会不正确,但是I2C总线并没有出错信息吖? 前面我们已经林林总总的叙述了一些,下面给出最终的描述。- r3 l. J7 K8 z, l
$ c& i% S& U7 J1 x4 n- b Y1 H' l' f看下面这张图,是我们和Samtec的FAE在出问题的板子上一起抓到的波形图,很明显我们看到多了一个Stop,下面我们来进行分析:8 D0 \/ J4 H/ S"
1.Master写device address =0XA2和写命令
- I" b, m9 J) P( Q3 o2.Master发出word address 0X6E$ B/ h9 Z" Q4 w- Q/ U! D. X9 M( P, E K5 G( h; g+ B: w
3.Master多插入了一个Stop+ ^9 p6 ^% \! [& i
' ]4 P$ E8 i, T: C3 U" i4.Master插入第二个Start( f& J: ^) K, z( a
注意:下面被插入了一笔完整的写数据的操作。. H; o8 l% M# K# \2 n7 g! ?" ]* h2 C3 p& x8 \4 m
/ [9 v7 q3 |( u/ a& A) I
5.Master又发出device address =0XA2和写命令: {9 E* [+ T" K4 q( g. l
6.Master发出word address 0X7F- }" i i e4 b+ P0 @4 e* N3 \; v3 y& B: f/ M
7.Master发出写的数据0X80
. k: x8 y; e9 D2 c2 Q. l q! f3 O注意:开始接着上面未完成的读操作继续/ n( e7 g: r* ~* G
3 ?4 ?: ] U, q9 C: x$ f* E; r. r" O1 U' N1 z
8.Master又多插入了一个Stop
* L1 E) s' h. _6 D* D4 n9.Master又插入第二个Start* E' \$ G( @* |2 n' [: f6 n6 i O6 |* S" v* {+ Y
10.Master再次发出device address =0XA2和读命令9 L; O% k! B- |+ g7 ?4 E6 U6 T% m7 x
11.Master接收光模块的数据,我们看到读到的数据是全0,为什么呢?& L6 S5 l1 m/ O4 n) F- P
) o, @* u: q, L) R3 w+ U12.Master发NAK7 F, c" ?2 K7 v& G' U. s J" [% v$ m' X) h
13.Master发Stop结束本次操作+ }, |. d; W/ t( ?8 x7 Q( u: h
: `9 ^) P( O c* v+ j4 B+ x/ N2 F1 X' t- \! e. g
相信很多人已经晕了,这到底是咋回事啊?- B' Y: O6 }4 G; M
7 t* U. G$ C6 Q Q: i/ j( D- ]0 L* S# a2 D0 I) s4 a7 V/ [" W7 H2 o
原来:一笔读操作,由于中间多了一个Stop,所以系统软件进程误以为前面读操作完成了,所以横空插进来一个写的操作,并且这里的写操作准确的完成了。- E9 w; X# u4 `: D4 V" S% W9 g( ~" h# x( n/ }
2 Z/ h$ r3 Z- ]; x在写操作完成了,我们看到Master试图继续完成刚刚被中断掉的读操作,其实这也可以啊,大不了分两次,只要最终数据能准确读出来也行,可我们此时得到的数据却不是刚刚的0X82了,而是0X00,这又是为什么呢?
我们来结合这张图描述一下发生错误的过程:
* t' \. F( N' O0 Y/ r5 `! E( ?& H2 Q* V" [* X' y& v* U
1.Master开始读操作的第一步把0X6E写入Device;: ~9 R0 D& O4 F/ Z, g- x, S, P
2.此时被插入另外一个写操作;- j9 u2 ~# a, R/ x+ ~# E; d7 }- ?) b5 `/ n! a8 j F
3.写操作顺利完成并且把Pointer写成了0X7F(注意已经不是原来的0X6E);# S& x' U* t- {: T1 }8 l8 C$ a. X j- [( j0 e( c
4.Master继续刚才被中断的写操作;. T& H) r$ K6 V. B- }' g- u- p* x$ e' a4 x$ L7 f" v3 |. V% r
5.注意此时Pointer的值是0X7F,所以读到的值是0X7F这个地址的值。8 x- B2 u( J) | V$ {9 }* b
c1 ]9 Z/ V. f1 g, f- P- y+ ]" l& t$ _9 F _
这里就清楚了:一次完整的I2C读操作访问,如果中间加了不应该有的Stop,就会被其它进程强占,从而插入另外的写操作,导致访问memory或者寄存器的地址指针被覆盖,Master然后接着完成刚刚被中断的操作,也不能正确读写到要访问的值。7 b: V& ]* T! }
g4 E, H* n. A( n$ d2 ?
4 N" T1 s) j: ^9 H4 _* c# l% k6 y这里分享几件有趣的事:
5 O7 n+ o! V8 t5 x1.由于只是读有问题,写操作是好的,所以产品的功能是OK的,在市场卖了那么多,都没有人发现这个问题,也蛮搞笑的;/ X9 ^6 ?- p7 S% l4 @
2.I2C的读操作一直NAK操作是SDA=HIGH, 由于SDA默认就是High(前面讲过Open drain和上拉),所以即便设备没有做什么? 也会让等待NAK的设备误认为NAK已经产生了;
b9 n- B4 |4 V8 Y( t3.系统软件有时候是会和硬件打架的,所以相互合作才能找到问题的根源,否则相互推责任只会让解决问题很困难;
# s: v* b& o) W: H( R# ]4.发现问题并且解决问题,写个文章很简单,但是调试的过程却是痛苦的,特别是I2C这种接口,一共2根线,很多人比较轻视,这是不可取的。
+ x; [+ l9 }& z5 Y! w* ?
注:本文为EDA365电子论坛原创文章,未经允许,不得转载。
# Q- U' v" J, v, ]- V( s7 ~1 Z: x% S
作者: xiaoxiaozhou 时间: 2019-5-16 10:31
生动的文章,分析得有条有理,赞~~!
作者: yongbudl2015 时间: 2019-11-19 18:16
各位,有john大神的联系方式吗,很想认识一下,我邮箱2929219135@qq.com
作者: ddny 时间: 2019-11-26 18:33
看看,学习一下
作者: ohdsp 时间: 2019-12-18 20:38
谢谢资料分享
作者: 13671672266 时间: 2020-5-11 10:47
文章真的好
作者: 两面包夹芝士 时间: 2023-6-12 19:01
很多图片没有加载出来,楼主能麻烦再更新下图片吗??
| 欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) |
Powered by Discuz! X3.2 |