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

【实战经验】STM8Lxxx I2C 程序第二次数据通信失败的问题分析

[复制链接]
zero99 发布时间:2017-5-5 09:34
STM8Lxxx I2C 程序第二次数据通信失败的问题分析

8 |( Z$ `: @3 O6 j' Y- U前言0 z5 |# [4 x8 x; f( y$ L
本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。
, ?2 F, s4 x! k1 G8 z7 O7 m4 H  E/ P% I) s) Z, B
1. I2C 协议总体分析。
8 @+ e' g, j2 s2 T8 e1 ]! ESTM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。* U, ^! r& P5 n
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
+ {1 \4 l3 n0 y+ `# P8 ~SCL 信号由主控提供。
2 `  ]& e& c# z6 w0 [/ D# I8 xSTM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。- k, D0 D: q5 V. F; n# T: ^" G
下面协议为简单的单主控单从机收发协议。
7 ?) B1 ?! a2 w# H; Z 11.jpg
  U+ n) Y( F3 v, ~# h! ~0 L9 j7 F' L+ W
2. 下面对一个简单的单主机发送,单从机接收协议进行说明
, T& a- M  G! j) l- n+ A: m. I* n下面为主发送的一个协议图:+ C  V* }# L- p' o8 J/ ^
主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。
/ H  i& C' `' @0 D) Z9 x- M 12.jpg
, W& m* D( q  U: f( w7 r/ s6 S
/ U2 g7 A0 f: G4 P下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。6 P" o* ~$ _$ z* O! ]# I* }
13.jpg
3 V3 K( }4 p; N
# D1 E- ?5 e) H9 s9 U3. 程序中的出错现象2 e: a  h& ~: Z# s: Y% Z
客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。8 o) A& g: }, `

2 z6 i( @& \: ^) j4 P+ L  z! y4. 问题产生原因
8 }! _% M9 j: t( d" A6 r" }客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
* z% g, `9 V. O- l* u! @* A& H 14.png
+ T( r/ l* K0 @ 15.jpg
/ H# I, C2 ]/ f$ c; o; G* w( @. U' b* U" s/ |
客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。! l8 b. U' ~  I8 _
16.jpg 6 N' X) @  P" C1 x! e) O
17.jpg 6 H: m& f' H; ?) p8 @" _
( C; q# x+ F- b2 T. ^" u
客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
2 {2 A! A5 s& m2 O; @3 ` 18.jpg
- _7 g& @, Q  J9 ~+ z( n, D4 T3 [4 T2 A4 J
跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。
" l: c& q. z  L跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
  }0 r/ P! |2 A( y$ y 19.jpg

  ^# \8 e( b3 {7 ~# `把程序恢复成示例程序,通信正常。
' j' [; M% ^: u( L2 P; i* E8 k! Q* y5 R5 Y( B( X& a" O& T! J
5.代码设计中应注意的地方。
: ?8 h. N0 _" m3 F# |建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,* }* n0 ?$ ?: P
不要测试完成后又忘了修改回来。
* S- o" v9 M+ G- c, k, A9 H$ y$ m+ j. _( n0 [5 r9 ^" D

) @" u1 Y  M, f' \文档下载6 @: z4 }7 C5 ?) E
6 B' e0 \5 p( {/ o5 i. E. K
更多实战经验
1 收藏 2 评论4 发布时间:2017-5-5 09:34

举报

4个回答
aderson 回答时间:2017-5-5 13:48:15
谢谢分享,,不过我一般都用模拟 的。。。
yyyyyyy-425811 回答时间:2017-6-21 10:25:37
我遇到了一样的问题,可是我用的是官方示例代码,且没有做任何修改,在100kbps的速度下,会出现跟你说的问题一样,然而5kbps就不会了 。能给我些建议么
yyyyyyy-425811 回答时间:2017-6-21 16:19:39
希望这个回答能帮助到大家。我也遇到相同的问题。$ N; v" z; L: Z5 m
在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。
/ T' D6 `3 |# E下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。5 G' ~  \4 n- }+ r# [6 ]: K2 }: a
void bsp_i2c_slave_received_for_isr(void){4 C( r7 P  h# u; f6 r
        //static uint8_t a=0;' s* p* F. D4 H; @2 D
        /* Read SR2 register to get I2C error */
2 h7 s0 S$ D' V" U- f7 l# Q6 \        if ((I2C->SR2) != 0)  f1 y" ?& F% W& P8 Y% K7 V- h
        {4 W/ x" T1 H- p5 j
        /* Clears SR2 register */) P7 |9 r; I5 W
        I2C->SR2 = 0;
  b+ }) ]7 F; A9 N. K
6 R' t4 [4 H0 G. Y! O/ @- ?, V3 X        }
8 {9 ^3 z/ `7 `, w' x        i2c_slave.Event = I2C_GetLastEvent();3 P4 k$ D8 W# h
        switch (i2c_slave.Event)* @6 T5 ~- q/ B# a% [
        {" }$ s$ l( w2 I
          /******* Slave transmitter ******// c+ z: x$ X0 N
          /* check on EV1 */
- A, B0 B2 d4 c* L' ?        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:% v4 j1 t% ~8 p5 @9 r
          i2c_slave.Tx_Idx = 0;: U8 c7 U# s# m9 R& y5 f6 C3 P9 h
          break;
9 X6 \$ T+ i" I6 i3 w! ?" i0 J* o0 Y% G' D
          /* check on EV3 */
4 \, _; \$ }7 K0 m) k0 x        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
. f$ G0 J2 a9 @3 f( F- L6 Z          /* Transmit data */. w! L! K/ p/ [2 Q- f! c) s
          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
) i9 h% L6 Q* d& Y) z5 Y, e          break;
5 C' {' [$ g, y4 f          /******* Slave receiver **********/
- g$ r# z8 D# E- b3 L7 c7 B( G; t          /* check on EV1*/
* n( u, Y" S( k4 o( d/ C6 Q; R        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:  O. U" s7 D& [* d
          break;8 z2 i1 o0 w6 N0 u# o3 R1 |, ?

( _. k' j; m8 i. W( l          /* Check on EV2*/2 v/ r6 E. o& z8 T( p
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:: z1 t0 P, H. y% z' Q7 o* U
          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();) m5 K# |: r' I( T7 ]3 q& g# Z
          3 o" N) f$ n' G5 E
          break;" Q4 ?) R! y  C' f* V
- V- e3 Q3 u4 b! w2 @
          /* Check on EV4 */5 b, i) F- m0 a4 Q
        case (I2C_EVENT_SLAVE_STOP_DETECTED):" i) s$ z& F+ U
                        /* write to CR2 to clear STOPF flag */
, v1 D9 U8 x7 W  p4 W3 g; y                        I2C->CR2 |= I2C_CR2_ACK;* K& ?* b% v1 h. i" L* P

# j+ V3 y, J7 [          break;
8 z$ X, X1 p6 R' w. _6 i# B" L: ^( d" q" P
        default:' g( z' O3 C# V+ D- h
          if ((I2C->SR1&0x40) != 0)
8 h) y6 `1 ~5 H) Z          {
2 G- x7 @  q" Q          /* Clears SR2 register */9 y' h; `7 N2 e* O, n; P+ s- P
            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
9 q# `0 C: o1 [. E- S% |
% T" G8 T4 r6 e, ?          }2 Q; p+ F1 _! `# Y8 X
          if ((I2C->SR1&0x04) != 0)
+ Z0 P1 f2 x/ p/ p" P3 y; o          {
% @: L& ?6 W  r4 o4 m9 t8 A          /* Clears SR2 register */( q5 ?0 L2 {( M$ v' i! F
            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);, h! Y# h8 b) p/ |; k( ]

  w8 h0 A  S7 h# \# t6 g          }
. h% i1 \2 m: R7 [6 K# e          break;* {( d% F6 s; `2 X1 \
        }
5 h+ s" W& M4 i- A        
% m* ^- [: m; ~- N5 l: F  Y; ?}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。  F% a' ?+ L3 g
. C% o3 Y. E0 E" b) E1 k) K
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版