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

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

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

+ y  F; Y$ o8 \3 x前言
( e/ R6 G" ?& l0 x本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。1 N& o; P0 ^" b" e9 q
  r( G5 B! k6 G7 b
1. I2C 协议总体分析。8 T. \  f  ~- Y9 h) {
STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。: G4 w6 k9 c7 ~/ _- N0 t
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
* J( f* c( R0 Q2 c1 v0 a+ p. dSCL 信号由主控提供。
4 J4 ?( W% x( \9 q' ASTM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。& V  f$ S0 b, I& }2 l/ n. w& B
下面协议为简单的单主控单从机收发协议。& ~2 W' i7 I# q1 S/ o2 \# w: ]# |/ d
11.jpg 5 j! O" M1 d8 G8 L. S( w! p1 ?
- Q- D. j. s9 f* \2 B1 T
2. 下面对一个简单的单主机发送,单从机接收协议进行说明
) p& u7 f- H2 T; V8 u) d下面为主发送的一个协议图:
4 c) t- e/ W8 ?# |! C' C主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。6 _% s: f4 v8 H+ T, O8 U0 M
12.jpg
0 r, b8 y8 a3 t0 L) N$ ^+ w  y% }& g' w8 ]8 g1 O, D7 g2 ?6 p
下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。
0 ^8 L" w7 S: M: ?6 O' F 13.jpg
9 q7 f; \6 ~9 D
  k0 s% i" V& ?3. 程序中的出错现象
2 n" h+ g! h8 |3 }客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。
$ l: C) T2 ^$ ~( Q- M
) h" B$ R+ W5 ~' w4. 问题产生原因
% h" P- y) {9 L, `2 e) R$ z. g客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。5 D8 Y! ~( ~) @2 ?- H) p" {7 P
14.png 9 d$ o. ~& ^7 v
15.jpg
) H) F8 |1 n5 w% l" U6 `
7 M, U. B( H6 ]0 U客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。& ?+ C; C' {; A) q
16.jpg $ s( J2 {' {5 r/ v- [: ~
17.jpg ; M& c& _7 S# g+ E* M- p/ c+ u( z& V

# `+ z* q  p. Q# _- L$ w  O9 L$ m客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:0 L0 _, \4 F4 z& u: c" Z6 p4 x
18.jpg   p) B2 j( S+ y( E9 X
5 q& S8 y2 y9 N
跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。
5 s. M0 Q: g9 y跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。! i0 w. a5 L. d
19.jpg

: Q8 m" o* b# i/ t# H* ^把程序恢复成示例程序,通信正常。
# X5 W# s+ \2 E; W% g8 T# X6 Y4 l5 o( R) }& u- O6 E" ]
5.代码设计中应注意的地方。( D/ o: C1 Z- i% Q/ G
建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,1 c9 T: d1 E3 F' q1 V  |% t
不要测试完成后又忘了修改回来。) ~% d1 R$ y( r- i: A- s2 Q& G" u
* U* I! F$ A* |- t+ H$ n" A
# f/ }: H, |) d  Z! T2 Y
文档下载
8 N" k) @7 z: f& ?, U7 ~% r( Z" C5 q7 B
更多实战经验
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
希望这个回答能帮助到大家。我也遇到相同的问题。
& D7 t, F$ @# ]; C& y6 g" N在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。
* J' L5 G# C: G  u% }下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。
- g& E$ w* r: i/ Q/ {void bsp_i2c_slave_received_for_isr(void){
$ ]- t/ ]& A. d3 M2 n  _        //static uint8_t a=0;
/ k, G. c5 c% i4 U. h) d" x        /* Read SR2 register to get I2C error */9 B) S1 B4 D1 `5 j( J5 N* U
        if ((I2C->SR2) != 0)
6 O# G  e7 I8 F. {: v, {" \+ U        {: n! y8 W$ F2 Y/ v, x5 j, K% t- x
        /* Clears SR2 register */
( t( R7 _3 X& U        I2C->SR2 = 0;
6 j: L4 ^  {! o, x9 w5 F6 y- O( A$ U7 S; K3 g
        }: N' Y; _% I& F9 H: X  S# T
        i2c_slave.Event = I2C_GetLastEvent();
# {1 R- j8 ?" x  n: N        switch (i2c_slave.Event)
" y3 N9 ~: S& O  w5 J, e: D        {
* Z/ G' A8 S5 @( L& t          /******* Slave transmitter ******/
* p  A, m/ C8 R! o* c          /* check on EV1 */  W2 C) E7 W9 r: W
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:' ~3 N$ j. `! r5 N( }4 z3 l# v) O
          i2c_slave.Tx_Idx = 0;& i6 Q& y4 B( V* X! W" W
          break;
" F6 B9 H) f/ A" @# Y7 V. A9 F7 u- @2 B
          /* check on EV3 */
9 [5 `3 M$ u  n$ n& {5 n. B# e1 R1 Y        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:( i) ~2 u; V1 w5 s: z
          /* Transmit data */) W, M: ]8 e5 u. N9 V( R' q+ }
          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
( ?9 b  V0 d2 N7 V# O  ^% k          break;
; a+ [  b! ?+ x9 E; h9 t5 Q          /******* Slave receiver **********/" ~+ ?8 @& _3 E( s! j1 W' @
          /* check on EV1*/
& V) A1 l% [2 x7 {        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
! D" q9 Y8 V1 ]6 p" k9 W$ P& ~          break;. q3 _+ F# h$ ]  g) ~# }/ N

) q& r9 N& U$ o7 b9 b0 J          /* Check on EV2*/
  r' y' U! R, i! r; Z+ {# \        case I2C_EVENT_SLAVE_BYTE_RECEIVED:
# Y5 R9 f% s9 Y9 L- o          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
. _4 [+ _7 W( e         
( M- w  e- |0 P& _3 S$ D2 K          break;
0 w& p2 q6 R* G: O6 }, ?" l0 _6 H) b+ y3 K+ L
          /* Check on EV4 */& R" ?1 w! T  L! U9 Q/ u3 L
        case (I2C_EVENT_SLAVE_STOP_DETECTED):
* n& O. s5 j8 [& F                        /* write to CR2 to clear STOPF flag */# X/ x3 j2 R* _6 q* x& J
                        I2C->CR2 |= I2C_CR2_ACK;2 d  h, Z7 p% C. B% t; F% i
2 y! q* c; d, V+ u- B" z; b
          break;; \% o7 Z, m! D1 j5 i
( t/ {; C0 A* M7 }$ Q" _
        default:
' G; M6 I; ^* X. L7 n% G9 k% _          if ((I2C->SR1&0x40) != 0)
3 m9 u) g) [: |0 R          {
' j' E( y1 Z) p9 Z+ K0 q          /* Clears SR2 register */3 f5 W$ a0 I+ h7 q, ^8 E- @
            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
0 A; I9 I  F* O9 t! b% k+ Y; _' Q; b6 T0 {& D  Q+ i. Z' t
          }; h7 @9 {1 U; \% n# C! i
          if ((I2C->SR1&0x04) != 0)
  L* A6 L' ]* i9 X$ l( X          {
* w  Q% J9 ]3 l5 i1 \          /* Clears SR2 register */
& R" U; x. M* r            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
2 m0 s& j6 j/ |" x$ X: B
$ M' x5 U, p: B          }/ c' T" z/ d' n  W
          break;' w9 _8 ^/ j& N% a
        }' T2 B* J4 A: H/ S. ^. \
        ! m" ~# N; P* z5 E" c; ~5 B
}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。9 y. q! i  ^" m* v) x

; u; }2 f9 `( E# R0 M) T) [9 }昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版