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

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

[复制链接]
zero99 发布时间:2017-5-5 09:34
STM8Lxxx I2C 程序第二次数据通信失败的问题分析
5 u, t- e0 R7 n* H
前言
" k5 {. J6 |; H- n; T6 h" M本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。  l2 s" F0 o' P: ^, j

8 e1 e! f" z) a9 _5 ^" _! \$ G1. I2C 协议总体分析。' {6 k) F! b  x) K1 v3 @, L
STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。% Q; L9 F) D* U1 m. s2 ], x0 G9 M
下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。9 s( K" l; \* G9 i% U5 X
SCL 信号由主控提供。
# F! Z+ M( Y- R, }& `STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。
1 y' T. c! l2 u9 w/ ^2 B' O( D下面协议为简单的单主控单从机收发协议。
# S, P8 c' o. s$ P- h* _* u 11.jpg . Y( s$ G9 Y# l
8 ^' L1 S4 {: F. j
2. 下面对一个简单的单主机发送,单从机接收协议进行说明' ?$ k: b8 V  P) s: _
下面为主发送的一个协议图:
' F9 v. R, \3 R主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。! R% i$ G+ d1 y6 \! Z0 h: s
12.jpg + c9 _$ w& h1 J% p* F

- ^% F* @2 g! s' ~; d/ B' J下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。
: h6 D, e& e& f3 x# Y; r 13.jpg 4 r0 h) [1 ]  G
. O- R) P8 G( R& P, [  ?' M
3. 程序中的出错现象6 f) r0 c/ x( v9 T
客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。
" Q& |& R) e1 ~/ U8 O
$ f% _% {# U9 S( O4. 问题产生原因
$ `9 d$ y! M: A客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
0 b4 Q7 o+ J! O) e. P& l 14.png 5 h( ]( H* q0 p( N, u
15.jpg
6 h# v, p- l. t0 D9 ^' V8 U. }+ Z$ \: s' v  h+ }
客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。
7 d) C( V3 I, z/ w 16.jpg
1 v( B; a( e: z* F# }1 p9 W/ K 17.jpg
; b: J$ m+ I" U* O* H
" ^" ?6 N8 A8 `3 M客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
& z5 ?1 M. x, c" f& r 18.jpg 0 |, M3 w+ [  d( \: }+ h8 u

2 n" ]  L* `& Z, N1 ^5 |6 X6 V跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。
1 M9 l4 }/ y! z2 w' o; b. M跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
0 B7 m- A. ?+ m6 m3 F) S: N) K$ k7 A6 G 19.jpg
$ s7 w: A; t2 N. [' L% @
把程序恢复成示例程序,通信正常。# i3 T, z# [5 [
; E4 q, C; g7 {+ t4 N/ j
5.代码设计中应注意的地方。4 f( m6 t; G2 p  }
建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
+ E; R5 B& a2 L  J9 b  s. W不要测试完成后又忘了修改回来。+ \, a# j" E# W8 k/ e. ^3 M

' H+ r- `. q2 i8 G7 R7 P, ~7 Z( O0 e
文档下载4 x7 u* e2 [8 W* r& B& q' I' c0 D

$ i' T, A" _6 t, d! D更多实战经验
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
希望这个回答能帮助到大家。我也遇到相同的问题。, e2 D0 c$ @; U' ?! h1 B
在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。 # v, b' ]! s, B' m) C. {
下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。! g! R3 I3 E- i' h: w
void bsp_i2c_slave_received_for_isr(void){
% P/ U' F' ~. V" X; ~8 w        //static uint8_t a=0;7 L) U; p5 U) w7 I
        /* Read SR2 register to get I2C error */  Y  I8 I* F' E/ q8 B
        if ((I2C->SR2) != 0)8 @/ y" U4 B2 z
        {7 _) C( e: f' u0 t& q$ J
        /* Clears SR2 register */
0 P) A8 F; v8 E$ Z6 {        I2C->SR2 = 0;. b) O0 p' Z- A6 p

. ^9 q5 m# o) A        }, R- Z" W, ?# ^
        i2c_slave.Event = I2C_GetLastEvent();* {  v3 M3 L) H3 B+ S  R
        switch (i2c_slave.Event)
) _( x$ u2 W4 g" k0 L* K        {
6 k2 U, o3 }0 S- Z9 S( z          /******* Slave transmitter ******/5 y/ G  J) B9 h6 q, q
          /* check on EV1 */0 L: g! V! M2 g# t$ w
        case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:7 h7 R0 {" F2 C$ n
          i2c_slave.Tx_Idx = 0;& i9 t: i. s  |2 y. \
          break;
' k6 K% G5 t7 C$ _$ G5 g8 f& Y0 t, i; N5 g, W
          /* check on EV3 */, ], P$ O7 A8 A% c1 z( m9 L: P
        case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:- U! X! g4 Q" F" {/ D6 P- n
          /* Transmit data */% r2 D& p7 i+ S) M! W1 @
          I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
! U4 S* |9 K$ {) I          break;
7 d0 c# @  F8 K. c          /******* Slave receiver **********/
) j: l2 q1 r9 q( I9 X1 X4 X# g          /* check on EV1*/
$ D3 L1 e. V% h* N  Z        case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
& e  S0 z  N- T6 f+ u3 N9 k          break;4 r8 H2 p$ G. S( P# j+ V, S. a
/ e4 r$ i; a, u% R/ d
          /* Check on EV2*/% w, ~; _& l2 I2 s/ E% ~6 w1 |
        case I2C_EVENT_SLAVE_BYTE_RECEIVED:% K, A2 s8 y+ @! i+ C
          i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
  r' h" E$ T' B/ @          0 c7 r  E7 }0 L- p; c
          break;% n- J# W6 q! J# n* t

$ M: ?( m: K* d$ ^          /* Check on EV4 */
5 F* h6 ?+ Q$ g. J0 V7 k        case (I2C_EVENT_SLAVE_STOP_DETECTED):
9 w' D' y8 |# n  u$ L& x                        /* write to CR2 to clear STOPF flag */
' s% m- @; s9 \7 M; O3 a, @. _1 S                        I2C->CR2 |= I2C_CR2_ACK;
8 s! x, l/ w3 ]: c1 o
# T/ f+ h: ?( r9 F% |( x* k2 S  C          break;
. C% ~5 K; U9 }5 Q) K6 ~' o: j+ W
' {7 |3 \; p+ P" p+ X8 g        default:
& {+ u5 w9 f+ a4 i: s! ?% s          if ((I2C->SR1&0x40) != 0)
0 _1 x. Z: s1 c. o& X% U          {' |+ j. U. x3 Q' ?1 ^
          /* Clears SR2 register */; [9 t6 k% J. [6 a# a5 ~, X! O# h" b
            i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
1 _9 b8 U3 A; z/ [
6 ~2 Y' T9 h2 Q( Q+ v1 i          }7 v% E# l; Q/ v
          if ((I2C->SR1&0x04) != 0)
7 g$ t% d# i2 ~6 K7 m, `) @          {4 O; s- h( w  a/ \' d
          /* Clears SR2 register */
, P/ \% j6 q) Y- g6 y/ U            I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);7 `' R2 F/ d9 W/ }- r3 J
& J$ N  ?/ d8 [- D( y% Y2 E# _
          }1 o3 I2 x: [2 w) y; W) T
          break;
0 m& U9 F+ e, M: I& ?9 I7 j        }
; L9 r" g- H& Y& Z* M        
& o5 a% H& J, e% J% G}
yf14789652 回答时间:2019-12-27 13:24:22
感谢分享,顶起来。
: i1 h3 E! P5 ], k8 f& i. Y) w9 H" M6 I' E6 ]" v( Y9 Y- }
昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版