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

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

[复制链接]
zero99 发布时间:2017-5-5 09:34
STM8Lxxx I2C 程序第二次数据通信失败的问题分析
" [% K3 H6 K, N" t& C
前言) e$ l9 f+ x8 H
本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。- \9 |- w$ j# s- K! d# ]
$ ^1 i1 e; D" w9 y& U
1. I2C 协议总体分析。
1 E  A# K0 s! X% N1 j1 v. pSTM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。
" Y: u! _. {* H1 X9 _7 v下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
" }, M$ x) U) r, y2 y& U' T' Z( PSCL 信号由主控提供。$ ~; f+ k2 q1 ], G4 {% Q
STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。1 {2 r  _1 Q9 Q- v3 }7 I2 T( e
下面协议为简单的单主控单从机收发协议。- L0 z% D- y: M+ [/ J. {, U% I
11.jpg - r! o  |( I$ D4 Z4 `, s5 S
+ [  w/ y+ O$ w$ y1 p. v1 V
2. 下面对一个简单的单主机发送,单从机接收协议进行说明
- ]3 R% _1 F5 q( f# ^0 ]2 F* U' }下面为主发送的一个协议图:( Z- S  Z$ `; h+ Q/ n; J
主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。
* F5 w& m& C+ { 12.jpg
# b6 {7 s, ^  J0 B3 q) y' X# m
- d' s0 @8 t: t  H" N4 \& F4 J2 h下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。3 `. s0 I- J/ J2 C6 {$ o' u
13.jpg
7 x; {/ m, o6 D; ^' n' D# G% D- d3 @8 q
3. 程序中的出错现象
& ~, o3 G: `0 t- {客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。
9 W" ?7 N2 [6 M
$ w; O: B% x2 M4 X. h: k* M7 S4. 问题产生原因
2 Q. x4 w* u/ Q客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。" E, a6 V* X% \. |- i
14.png ' A$ A4 q9 N  r: k' {& h# \
15.jpg
1 H& a" a8 k; [9 ~1 Y  a( r* q( f7 F6 R$ O
客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。
# z, D* Y7 K9 B& Y4 i7 @ 16.jpg
( ~) c7 w1 I/ E3 V2 O+ t1 M 17.jpg
  h, I% i( j' X* k% G. v4 \: J1 q7 k- I
客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
0 K8 i0 C( I% c% w 18.jpg ( ]' Q0 A5 q* i6 H2 V1 D* A$ i3 [

1 o: L7 E6 B) {9 s, e$ _跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。- Z9 ^! F" k: g, _, k" O+ @% n
跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
, S1 q! ?' j$ M1 m" {5 w+ J 19.jpg
5 @" X9 V; x# N: Q
把程序恢复成示例程序,通信正常。
3 \8 s* f0 Y( Y5 i3 H% N$ |' E+ T2 `- y% v& l3 V( d
5.代码设计中应注意的地方。5 h4 B0 H5 y# ^) _7 [- x
建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,  ?( w& |! G5 Q1 s3 q( F
不要测试完成后又忘了修改回来。
* ^0 _6 j" K' E3 a
3 E1 W2 O2 e) C+ G0 u+ R! n+ G! c; F7 \# L8 W, Z! y  a- w
文档下载
" x5 m4 M4 [' Q/ }4 P8 ^
! S8 {# `) [2 }# L* q+ c更多实战经验
赞 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
希望这个回答能帮助到大家。我也遇到相同的问题。: g/ [9 v% ]/ ?* W
在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。 7 |8 q0 J" \: n, G) y, y0 ?
下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。
7 y' Q8 g8 g. ovoid bsp_i2c_slave_received_for_isr(void){
; ^/ b, g! l, U& I5 r  _. ]        //static uint8_t a=0;/ k0 e) Y) h0 m) O% e" H
        /* Read SR2 register to get I2C error */
6 [7 l% l' @- d  |: v        if ((I2C->SR2) != 0)
% `+ y+ @" l" L0 |6 a1 m        {
: a- e! n: [0 Y/ M) ?0 N        /* Clears SR2 register */5 V- ~6 D; U) G! C% c6 j" }5 U3 b0 C% G
        I2C->SR2 = 0;1 a5 s% F% }1 a7 J5 e+ U, P6 L- ~3 U
4 Q& C0 S- P( t& S
        }
  @2 a8 [& d. T        i2c_slave.Event = I2C_GetLastEvent();8 y4 Y1 V% P! e3 K1 S/ t3 t; ]
        switch (i2c_slave.Event)
/ G! T' _6 Q5 v" K, a3 c9 Z5 T0 O        {+ u' v3 `3 ?0 {; f
          /******* Slave transmitter ******/( P& R" q' r) T, A
          /* check on EV1 */
" D- x; y' V5 G0 \' {, }) {) d, e        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:, w: R% Z/ A& M0 @% P6 ~% y/ G
          i2c_slave.Tx_Idx = 0;
( S8 k4 F9 x; _) T          break;1 C1 N' L& `& K+ h7 ~

$ l2 ~7 K4 W3 v, o% ?- h' t          /* check on EV3 */
* ?5 k0 i& i7 t: P- F        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:7 c# m7 Q/ o+ r1 |0 @# b
          /* Transmit data */" M% b6 N7 d' H. B' i
          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);6 g. @+ M# k" _$ H
          break;# V- `2 h/ ?2 Z0 G" g" K. }8 S
          /******* Slave receiver **********/
- b3 I; T- o) b, h* w0 r          /* check on EV1*/
3 k5 G/ w5 V! f: M6 j% t  p. l        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
, E8 u2 K3 |- C* d( _2 J          break;
% J( r! `6 X. C/ D" W) v& \6 a
          /* Check on EV2*/: A  R$ ~" {) j/ _
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:' Z4 a" e4 ^- R: H
          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
& f$ g- K7 O1 N' g* l  X1 i1 i          # {  \9 ]  T6 g& K
          break;
1 ?' J4 c. |  Z' G8 Y% M, k* Z, _3 [; ~% [# }5 z2 W
          /* Check on EV4 */
  {% F' f1 M' H) N1 I5 n% q6 ~        case (I2C_EVENT_SLAVE_STOP_DETECTED):: C5 S  Q1 i* \7 \+ J
                        /* write to CR2 to clear STOPF flag */  I. y7 f& v. _8 \3 `; I
                        I2C->CR2 |= I2C_CR2_ACK;
& Y* M5 M8 c( X# A# T# P( D  |: d( Y2 x: n- d, m/ ~! y
          break;5 h0 `3 l' J$ a$ G

& N! ~+ ~. x5 X& S+ b& O0 f" G        default:, k# e0 o7 X. k! U1 R
          if ((I2C->SR1&0x40) != 0)
, \0 u& H0 u3 {: o2 y          {
( y3 {6 g- e5 H' E* Q9 \6 f4 I          /* Clears SR2 register */1 U+ h* U" w4 ?" x! y5 Q* m
            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
' o, F3 y# O3 M+ Z2 u6 n) `6 d4 T4 U2 u7 Y
          }% p; o7 R# A# v) `7 N# u' _
          if ((I2C->SR1&0x04) != 0)
9 b+ Z& a, y$ w( _$ Y# V          {0 u- y2 M8 w3 R4 Q8 Z5 w' W+ T
          /* Clears SR2 register */
& c9 g/ W# Z% N$ h8 N1 i            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);- G6 m) d1 ^) l' A1 ]7 o
( [! ?2 w; j5 c8 y0 E
          }
  I, i/ S) }: c9 C. D9 \6 a3 f1 V          break;
1 d0 P9 o: V; D: t  x2 S) R3 q        }( R/ b( J% ^: ?  \/ L, U( P
        - ^7 l5 z' |& x) I/ k, A1 S! a$ K
}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。4 r5 m- p2 w& x7 ^6 X
& x, E/ X" M9 \9 D* H9 O
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。

所属标签

相似技术帖

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