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

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

[复制链接]
zero99 发布时间:2017-5-5 09:34
STM8Lxxx I2C 程序第二次数据通信失败的问题分析
2 {1 Q. }' n' n6 n" v5 h" l: ]: Y! U
前言; \, k. O; E) K: b- I# R
本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。
  s) T8 u% c- o+ R  n3 `: O& p
$ O3 \* f& E; G, V1. I2C 协议总体分析。/ h* b4 _1 r4 X+ u, k3 I: a* t
STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。' J8 O* I: V: v" H: h& @2 f
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
; y9 D# L8 A- L& h& [SCL 信号由主控提供。! |8 f1 E. }% M- B
STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。
7 }3 I" x, b1 d( o# h6 ?+ a下面协议为简单的单主控单从机收发协议。* [' R* \! R; J% l. @- X3 T2 G
11.jpg
& R% ~7 V" E2 x7 {0 M5 {7 d5 z9 R; l# ]3 ]& h5 o9 K2 O
2. 下面对一个简单的单主机发送,单从机接收协议进行说明" |2 c) i3 g- B9 J3 z6 \- Y$ W
下面为主发送的一个协议图:
% b5 S0 _% f# N$ m, W0 H+ O主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。
5 ^- R; Z2 {& F0 i3 u$ J, R2 q 12.jpg
: F1 C' ?/ O7 T- i. U
+ h* m+ L/ N' c. c7 R3 O6 w' }下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。& Y' m2 @8 X' o; M: ^
13.jpg
5 a7 w9 p1 ^; c
% ~0 T$ f0 L. s6 J, t1 ~# \1 c% N3. 程序中的出错现象# c' S$ ^9 u: @* }
客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。4 \7 ]6 M0 w& ]/ T" u- ]

+ m! Y8 F' ~+ ]2 }2 A4. 问题产生原因
( z, k- a6 y/ F' r客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
' f$ k. f. n8 s  \' w 14.png
0 W( {3 O! O3 \' P 15.jpg
& `9 z: Z2 I( X# }; z8 N. _
, u- @9 d/ O. r+ D: ]' e客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。
/ @- v$ ?# Z7 d# h; O 16.jpg
1 M6 h- B9 ^% V, M. J& @; C5 e 17.jpg : d5 A' \% o1 o5 P4 B+ ]5 ?# i. n0 |
# L0 N3 B% C2 a2 I$ l
客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
; E0 a! s, B+ }& J1 A 18.jpg : {$ ~' A: a, C6 \/ @/ D- `

! P/ e' o3 P6 V- ?) `& G跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。5 ?# H- I0 }. c% N# i
跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。$ B3 i! L; Y1 t. t8 Q5 P
19.jpg
% C! P, k# l! P0 T
把程序恢复成示例程序,通信正常。) f% ]& }0 S: F9 Q- C& N: k' w
9 z! _" V, j7 q- |. F' \# l
5.代码设计中应注意的地方。
$ h& Z2 i; P. H# ?# T7 A; ]' o建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
+ [+ S9 ^2 B  o3 B- x不要测试完成后又忘了修改回来。
# F& _: Z6 Z) d8 a
& a/ ~6 z* u7 c0 Y4 c! H0 i5 O( M
) Y# @/ U! A! w8 I+ ?# |! d. q4 I1 s文档下载
4 C! p  G7 \8 A7 p
1 N) p7 d: K7 a/ ?) p/ 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
希望这个回答能帮助到大家。我也遇到相同的问题。
1 C/ e  Y1 t; B- b# y. c在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。
. l* ?) \" J/ H1 W8 Q4 A下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。
) n) x7 M- Z% G  D0 z& ^; b" Gvoid bsp_i2c_slave_received_for_isr(void){2 G/ W  R- X3 Q; G2 ^9 O
        //static uint8_t a=0;- ~6 q+ H: g* a; c" T9 N( V0 A
        /* Read SR2 register to get I2C error */
) g  h/ G$ g, p- J: I9 W$ f" V% {$ V        if ((I2C->SR2) != 0)" D) k, B: f5 B. ^3 |$ n
        {9 s. r3 U; J( D* C% x
        /* Clears SR2 register */0 t( K! l% k* \
        I2C->SR2 = 0;$ L; R$ }* t% ?

4 \5 x- q& x3 Y* ~        }$ e  |+ s: @) y! ?$ e0 z
        i2c_slave.Event = I2C_GetLastEvent();
" ~3 |) o, P1 S# r9 Q        switch (i2c_slave.Event). z- A1 |( G% \! G: H! Y1 B
        {
2 s: x" a; R& w! t! d          /******* Slave transmitter ******/
1 ?+ K- M5 ]5 i+ U7 }, K6 i( K          /* check on EV1 */
, ]- t% O6 K( X6 c% y6 G        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
+ ]* X: @/ U$ Q' p& ~: m7 Z' D          i2c_slave.Tx_Idx = 0;7 {9 a, N" r% j7 Z# y/ D$ n$ T4 K
          break;) T( C$ C( J# _' q9 U! y- B  W

) L9 U$ r! U  S1 N3 ]+ c$ B# }          /* check on EV3 */
! u7 d1 `8 x# q3 W* F) ?        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
4 a4 U  y8 U; r; z. E          /* Transmit data */
* B& F6 i5 q0 w          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);3 v3 M: [8 ]6 L$ r7 M( x
          break;( ]* ~. n, ~& O: z* G: ?
          /******* Slave receiver **********/1 v; n# n" T' s( P# t: U# |
          /* check on EV1*/
7 G( c& D/ r3 S1 F7 f) T! g        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:* K6 W$ j4 i( I  k
          break;' }; [" @. _" j0 U8 @
1 y: ]' b  w) }/ F* V
          /* Check on EV2*/
5 r4 u: U/ V0 P# j' P* [        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
( |- R8 j" z( ?6 \- h          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
+ B  B: R( M% f: Q( M% U9 e          ( S2 u; M! I0 n( c) U7 {8 x
          break;0 B3 L- ~+ j, d; o# W

) @& r- H+ Z* g7 o          /* Check on EV4 */
9 }' ^1 F" M) v) T3 Y! F        case (I2C_EVENT_SLAVE_STOP_DETECTED):
# ^) d& z0 b5 I2 |9 `/ g, q% k                        /* write to CR2 to clear STOPF flag */
. m9 B8 Q' o  x6 G; ]6 v; F                        I2C->CR2 |= I2C_CR2_ACK;3 I5 s* m5 s. f" v. {8 O5 H+ S

- z4 n5 T+ t- M% E" z4 W          break;
3 \# F/ U9 j5 w& d7 C; \( J7 ]9 o1 A, U' n
        default:0 n& j/ _1 R6 |7 A
          if ((I2C->SR1&0x40) != 0)
0 }& B! i* t2 u& j          {6 g; h/ R( k2 k9 T3 j+ f
          /* Clears SR2 register */+ ], z0 t, g% o$ S/ |
            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
8 d4 U, T" k# ]9 |$ J! S
' W/ t8 q$ `4 T2 m          }- x+ [% j* e/ L
          if ((I2C->SR1&0x04) != 0)
) K$ I" E$ k+ X: @4 f9 e1 d- z          {
# K7 Q4 z. b! ?9 I: H. c6 k. _          /* Clears SR2 register */
$ D. a6 l3 P  a( C2 G- n& {" V            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
8 w4 t- A7 ~% W; g7 v
! |5 B+ N3 }* u3 ?+ S  N          }
0 b6 \# l% e" ]+ H9 u5 @          break;
/ K" V! g# O7 U2 d& Y9 D        }
' g2 l5 H5 }  C' {2 ^! Q, f        # k% n0 P7 }- |1 [9 p  `% m" v( e
}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。3 ^& X" {, }9 h8 q  o8 Z
1 J0 U$ q9 ^7 c# ~% B" f  V
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版