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

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

[复制链接]
zero99 发布时间:2017-5-5 09:34
STM8Lxxx I2C 程序第二次数据通信失败的问题分析
. ~. J8 o  M+ ]# X" s7 m2 v
前言
# x* O( a5 X" W' P; ~9 [" F+ l本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。- ~% z- G5 p; z' C0 E

0 O' a% x4 R" B' Y. ^1. I2C 协议总体分析。5 C6 H# Y2 S* Y3 ]
STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。- w3 T) P- n) z) a  @$ u
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。6 y1 G2 w" R- T* {4 B. p/ [
SCL 信号由主控提供。$ W/ _9 f7 R  M& l6 f% Y
STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。; e% F% g# E1 R) E% Y3 [
下面协议为简单的单主控单从机收发协议。' a6 A) U( _9 n$ m  Z5 D
11.jpg $ L7 f' g- f; U
0 a  e. M& G: M2 q( W: o5 T7 s
2. 下面对一个简单的单主机发送,单从机接收协议进行说明6 f/ O( a* ^, O/ s( E4 s! H
下面为主发送的一个协议图:
- w& z. W$ l/ O# h主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。& N1 X: ?, @. H) Q; I
12.jpg
# F  s; u/ w+ }& D  I' @7 h: f5 z- Q3 ?* q9 Q/ A& r3 U
下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。
1 O  H- t+ }% ^ 13.jpg / O; V9 r4 x9 U( k9 |; g6 G

/ d; ?' u# ]& r3. 程序中的出错现象9 N8 r) @& _4 s" j4 |$ d# e
客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。
/ E3 {1 s$ R) ~* v& E! S( o9 i- d- e; z$ U# z& o
4. 问题产生原因9 m7 n, D: m( {4 R) B8 b* n
客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
- i" i3 j+ ?; s% M' p  [ 14.png 6 D3 s" }" [' [! h
15.jpg
. s2 W  p" N9 B4 f/ Y9 t
6 W0 ~  A/ D: P: Q  s/ u5 u! U: B客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。2 o! y0 z# |/ |3 O, W
16.jpg . H( n9 P$ v& |; E* Q4 \
17.jpg
" |2 z3 N; ], U
1 \# _9 N- k% E. |" o4 [客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
1 N1 U8 o; o2 m& t 18.jpg - G- w9 h7 \9 E* y+ }7 [0 X8 O
8 f( @. A0 f7 h1 w3 U) \
跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。8 g6 S! {. D$ G7 T! @1 J0 X
跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。7 B+ ?; }  D) }! o9 F" _
19.jpg

; [; r; i7 V1 h把程序恢复成示例程序,通信正常。2 T5 f2 ^' d# I  {: }$ g" l1 s
- j: b# C3 E  f- |% v
5.代码设计中应注意的地方。
! ^% Q( k8 g3 B* j建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
* o" k8 k' |! b' u8 I( l不要测试完成后又忘了修改回来。1 ?# ]+ Q! {9 f2 W

7 w0 S1 Q4 J1 }, w4 ]- }. O* Z0 \0 z
文档下载' q6 B  o6 x  j& Q$ t
. v% d  n" S5 q: @+ k+ K3 I
更多实战经验
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
希望这个回答能帮助到大家。我也遇到相同的问题。8 D- _% v5 ^  Z% F
在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。 7 E# l1 J8 F; y' ]
下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。  C# L* U1 F. E3 {" Z& C4 E5 w: l. g
void bsp_i2c_slave_received_for_isr(void){6 {4 h  r' O4 b5 J) q* Y6 Q; k
        //static uint8_t a=0;
$ N7 \5 N/ ?7 G: A* z* F  J8 A" p        /* Read SR2 register to get I2C error */
  J' y" s% _1 V7 A        if ((I2C->SR2) != 0)9 o$ b1 W0 b8 k2 \
        {6 k6 b3 t/ k* G0 l- w* w
        /* Clears SR2 register */
* t2 B" o* w, O) o9 ^1 A8 A0 ~        I2C->SR2 = 0;; m( ^, f+ d* b' h. K, T9 ?$ `
" U, U' H: u+ w7 H
        }
9 ~* v# V2 g: e, e) n$ |; Q5 U. @        i2c_slave.Event = I2C_GetLastEvent();
2 V% O/ U- o" d        switch (i2c_slave.Event)
$ m/ Z  M8 [' l! h! c3 V        {
$ U( V1 R3 @  K5 T5 n- y1 d3 [          /******* Slave transmitter ******/% V& W! e. {5 k0 ]  e8 a
          /* check on EV1 */0 G# ]' l+ u' G
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:3 v6 w+ v1 w  K
          i2c_slave.Tx_Idx = 0;- H, u9 u5 F- ?3 j  ?2 T4 Z" D  b
          break;+ }4 e, d/ O3 ]* b+ r* J7 ]
, I. ?2 y% O0 W5 n; {7 m
          /* check on EV3 */. Z0 U- _& G, c: r
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
' C! u. s# u! t8 e          /* Transmit data */0 S: q: R5 c; y' f$ `
          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);' M0 J5 L+ t) I% B4 i( Q- c: m
          break;
9 l8 V* ~- m  y' s2 e2 K. J          /******* Slave receiver **********/
0 m7 L, O9 G. }- c, J7 s4 Z          /* check on EV1*/
) p- F0 b+ v# ^/ b0 x7 l* E        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:0 r! k2 J# B  f$ g+ c
          break;
9 Z  \+ X0 ]$ Y# [. ~" F% z1 [
! T0 k2 E; d8 y9 e! M. n+ t6 g          /* Check on EV2*/" ^/ y) T$ }5 G0 R( y& n
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:* G) |9 J0 p: f4 f
          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
! g) L" y/ g  |1 R& C4 W; k          ! k- h6 u: Q  i' H4 s5 h( q
          break;. G  S0 v/ R) S

6 @5 v" ]* v4 J9 B& k5 j+ ]7 H          /* Check on EV4 */
3 u0 y( Z6 c  |9 v* i+ ?5 e1 C5 v6 y        case (I2C_EVENT_SLAVE_STOP_DETECTED):+ L5 |0 Z  L6 T3 e
                        /* write to CR2 to clear STOPF flag */2 Q# e, q( _. R. ]
                        I2C->CR2 |= I2C_CR2_ACK;' N$ a9 h4 c! p4 b* m# t
1 u2 u1 a. I6 G+ e3 w+ }  N
          break;
* F$ y, [( s$ d9 Z
6 b1 r. Z1 Q! e7 n        default:5 R( T- I# P# M- H3 l' c8 a: I4 Q
          if ((I2C->SR1&0x40) != 0)6 c; I- i1 B, q5 Z8 }
          {  h& I# m1 ^; K! q
          /* Clears SR2 register */
. X- C) E, {/ l" B" X$ O9 X, O, P            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();: q( R* n; N7 i, H
1 r- k6 R" {9 U3 S2 K) c* T
          }' l1 x6 z/ L: f9 G5 z1 L, ~
          if ((I2C->SR1&0x04) != 0)% r6 j) r6 S% ?. V% p  Q' v& b
          {
- B7 ^- ?0 d( ^: y          /* Clears SR2 register */( K& v' ^2 e! w# |$ i) k) I
            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);3 |' [! X" E$ F& ]% n" t& E- [

. B( X0 }( t: i" J4 |7 C! w# j          }; }+ i' n& F/ g
          break;
" C. A  b% I3 c# z1 r2 ~  U, V        }
1 W7 e4 E9 e! x! S, i( `! X+ n9 m& w        
7 N4 y% L# C8 f. X  X$ h2 q}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。
1 Y. K" a: u) Z+ I2 f, H$ U/ h9 E0 m  ~
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版