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

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

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

* M* ?% ]- O0 t2 K, i( g前言
( t, S1 b( R1 Y本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。
3 M) [: o7 @% \1 k+ F
! ?$ b4 \% p* b; }! v3 S) C& u, g1. I2C 协议总体分析。& y' [2 A+ `* O8 @+ }. {
STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。) `/ b9 P; }1 k4 b, j0 e! }
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。$ z! `: i8 M) }
SCL 信号由主控提供。
+ e* A6 {. _6 w2 w0 m  VSTM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。
5 c* j% D3 C) b! O- Y1 x+ d下面协议为简单的单主控单从机收发协议。
( Z4 ~/ M! x8 v# c2 u6 ]$ y 11.jpg 7 z' R1 y8 X+ `( ?; N% K
6 s6 A" \3 j& j7 {
2. 下面对一个简单的单主机发送,单从机接收协议进行说明
) @% m7 m. X7 x. w+ ]" a& @; @  v下面为主发送的一个协议图:' R2 X  s9 [$ |
主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。3 r- z9 H/ [# z- S, b+ ^9 z
12.jpg
; N, G2 \7 E7 B' N
9 y- j5 b* X" n% ~, {5 J下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。: N  A; N1 Z" U* Y2 V4 [3 Z
13.jpg % c+ K# Z( e0 ~$ f" C) S0 `
/ t8 E2 c: A# D3 i2 P
3. 程序中的出错现象
) }/ O8 }1 K+ V. ]* b3 e, \' V# q客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。* ~. ^0 M5 U3 S9 J( M

+ u6 B9 ]1 ~+ P4. 问题产生原因
: f) K8 y( s) ?( k5 V  Z. y客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
' _/ t8 V8 h2 l( [ 14.png
3 A/ O: t& d6 y% L) C1 a 15.jpg
$ U. w" Y$ g1 Z3 H( O$ E) K3 C+ G3 z0 L% G4 R; f
客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。
7 w5 P9 j6 s( g 16.jpg
' X1 b3 A) z' t0 e" c: _ 17.jpg
- s3 V1 r: p2 p, a7 M; y: U0 \) m
1 v& N/ |  _$ n  }  s客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:5 U8 C5 ]# N+ G; ]( ~
18.jpg
6 ~' z' {2 j/ N2 v% d
8 d( Z. v& j+ d2 {1 Z! m跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。
; h6 d- g1 Z; r) S1 [  }: M跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
3 p& ]" w5 i9 y7 h 19.jpg
8 R( _! f# g2 U' D) A5 D5 n
把程序恢复成示例程序,通信正常。
# A% v3 B5 X& A0 p% g6 @
1 |& N6 t- X7 C5.代码设计中应注意的地方。
* S- Q1 p( A% u5 M( G0 c1 P建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
8 J5 }4 A3 v% f; C; n# N3 H不要测试完成后又忘了修改回来。) [1 t& ]/ q) H! n/ t* j

' W5 P" t5 h0 P6 V
8 i' n" m* @% s4 l文档下载
, l9 I3 j8 V4 b. N1 {: b8 d2 I% |! M
更多实战经验
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
希望这个回答能帮助到大家。我也遇到相同的问题。
! _# m7 x; ]: Q在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。
' e! \, J; X) p, H' L/ \下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。
/ J4 M3 {( ?/ b" I! h: B/ I3 `void bsp_i2c_slave_received_for_isr(void){9 ~0 i! h4 x/ {% _! R% G
        //static uint8_t a=0;
  C; w7 @7 r# T: V; o- ]* E        /* Read SR2 register to get I2C error */' @7 v+ A; b% G
        if ((I2C->SR2) != 0)
  q$ Z4 [8 W7 A. ~* d% _8 i# O: B        {6 H+ @$ c2 s3 d9 i' ]# l+ D
        /* Clears SR2 register */( P/ r1 g0 ?5 w6 e, }( U  D! O  p
        I2C->SR2 = 0;
- ^4 n! d2 ~0 i9 F1 C: w! q+ H9 U, X  Q, x* D5 c9 O
        }' v# W. t; ^6 S0 p) F
        i2c_slave.Event = I2C_GetLastEvent();
9 X8 w* B7 M0 F$ D5 F# |3 Z        switch (i2c_slave.Event)
/ F" y% A$ w( j: D        {
5 Z; z" _( K8 E* S  A8 y) h          /******* Slave transmitter ******/' ]8 C; X" {( E4 m
          /* check on EV1 */
, [; S9 m2 T4 s3 J        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:! p* W( M8 |! S9 n0 s
          i2c_slave.Tx_Idx = 0;
1 {8 }8 m$ Z: C) k. P" B          break;
% t, X6 V  S! h# V- E2 q9 K* f) j% {& i7 w
          /* check on EV3 */+ p7 F+ e* Q# ]) j! \
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:* Z9 j1 c# t2 [
          /* Transmit data */
. Z. i3 G: W( `  ?          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);! T" a+ C8 F* W4 x/ ^* i2 h3 C
          break;5 n+ {6 x$ a0 j1 Z4 K
          /******* Slave receiver **********/
( a; k' ]/ K3 |; \$ j1 q          /* check on EV1*/
1 s% M0 `' X# F        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
' v, l. `. B! E/ E$ u          break;
' Z& I. |3 ^3 {0 |9 d. ^6 ^% e1 R7 P( B
          /* Check on EV2*/
( g% M# r9 O' w: u( v! D        case I2C_EVENT_SLAVE_BYTE_RECEIVED:7 ]9 f9 F7 F& S$ m( n0 @& V0 W9 Q6 b
          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();  m  W1 s7 L! J" j
         
! k/ p( c8 v; Y" q          break;' w3 |- I8 D6 I/ M4 g: m

" U& c9 K: x' w4 o; E. V          /* Check on EV4 */
" o6 k0 n8 t- L2 P* L, B        case (I2C_EVENT_SLAVE_STOP_DETECTED):
3 {/ ^5 E* u( I, t. x5 p                        /* write to CR2 to clear STOPF flag */
( q9 y2 f7 \( `  e: {8 m5 i                        I2C->CR2 |= I2C_CR2_ACK;" ^+ i/ H9 }1 e# X* c$ q! k" D3 d

3 a. ?' a9 V* Z+ o0 m          break;
' `) \  d) e0 F9 O# n9 @! l! ]& t, z8 V4 B" x
        default:0 U9 a4 I1 G  p3 c
          if ((I2C->SR1&0x40) != 0)
0 @4 @4 F% Y+ h( K+ s' ]0 m; _# i          {
2 f6 \* R. R9 W% R          /* Clears SR2 register */
9 L6 r  H* ^- x7 d- A            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();) Y' ~, ]; {# A  L; X, Y2 c8 r% S# U

, H4 s3 y8 u8 r          }" _) W$ D$ X) X9 i! U7 [
          if ((I2C->SR1&0x04) != 0)
- b4 {" {1 ?- G+ {4 y+ H          {
0 @! D0 E3 w# m          /* Clears SR2 register */
5 W. k5 [3 w/ L4 S5 y4 n            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);2 ~) s- ]% [4 A! {9 ]" a9 s

+ W4 g; L- p6 E1 C9 V: N/ }: j0 `) r          }4 Q- l3 S  s. ]& V+ ?0 R
          break;
7 [  |1 L( |& i& Q  D) l        }
5 @' V+ s7 O2 Q0 y: w; M        
+ p5 t+ ^3 t& Y; s+ @& T. n6 z8 k}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。
# F6 f& \1 N0 n* b& |, U' E7 c- s" O! {5 ]- {9 M7 n" C3 o! x
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版