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

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

[复制链接]
STMCU小助手 发布时间:2022-2-14 23:46
前言
, E' n5 r! s$ `8 J* ~本篇文章主要是对 STM8Lxxxx 在 I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。
, o. m, c/ S; g
4 n9 a  t( S* z# e( a: R# G( h1. I2C 协议总体分析。
) @0 T  x* {8 h" ^: u- f4 K8 j$ j   STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。) y3 `. b* }! }& a+ j7 K' N
   下面是 I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
8 R6 W. ~  W% {  j   SCL 信号由主控提供。
' x6 d* ~/ B5 _: n   STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。
7 M( U# p' v3 {. M+ {' D/ x   下面协议为简单的单主控单从机收发协议。
$ {* D& G* L7 ?" |6 {- a; @ XIN`NCJHC7P_DHP]ZGA6V.png
9 n1 @; |# d. V4 e/ B
; k9 ~5 ]9 h- O/ r2 t+ ~2. 下面对一个简单的单主机发送,单从机接收协议进行说明7 Z6 q  m6 X+ \5 O
0 \0 s. u8 F0 j
下面为主发送的一个协议图:
$ {+ L9 ]+ r: x0 Y; F主控给从机发送数据,等到从机应答信号后再发送下 byte 数据,直到数据发送完成后,主机发送一个 stop 信号释放总线。+ E" P, ?) p0 ?3 ?/ |
3 d& O+ T+ _7 i/ w/ o
2D43FXAOKO(%YOF`XTM0E)B.png : ]- }- D  |# H* T8 K( N& i
" w) K* c2 u5 n) o" C3 r+ x) d
下面是从机接收协议图,从机接收主机发过来的数据并存储,每 byte 传输完成后发送一个应答信号给主机(从机在每 byte 传输完的第九个 Clock 把 SDA 信号线拉低到低电平)。
  R1 t  W; J- P
2 S1 s% w5 O; ^: f# t XKNMVV]}43A3KB(]~~({FB2.png
* c/ i. j  |5 b5 W
& [8 v4 D; Z* x' n3. 程序中的出错现象: C7 U9 r- C" \% q4 c) K. R
客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一 byte 数据发送完成后,主机收不到从机的应答信号。
) i; ^, R1 {5 j8 I0 G. b' m8 \( s  D5 @  s9 A4 J. L* m
4. 问题产生原因5 T  \8 g8 ~7 d% j, r" p
客户使用的是 E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-
( |0 j& J, V/ ~% J7 I, r: gL_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。7 M$ w* Q! o6 O- S* E# @2 G1 O# i* T
  1. /**( k: h; z3 u4 ^( p7 y

  2. + ]) Y- f4 j4 C* d* ]8 P6 P
  3. * @brief I2C1 / SPI2 Interrupt routine.
    - `9 o. P- y/ W+ _5 n: ^( T
  4. * @param None
    8 T) w& m8 ?# g2 K- `4 I2 l0 L
  5. * @retval None5 g* R4 ]" W, Q' A+ {6 ?
  6.   */( _" e( N4 T6 h5 c% X* O; d) a
  7.   INTERRUPT_HANDLER(I2C1_SPI2_IRQHandler, 29)6 Y& M( C: Q, n. y) k
  8.   {9 s! \+ w2 v+ p% i, |
  9.   /* Read SR2 register to get I2C error */0 g1 M/ C  t' S
  10.   if (I2C_ReadRegister(I2C1, I2C_Register_SR2))
    1 f( F" @9 \, ~/ R. g; c3 G
  11.   {
    - ~4 e5 ?( G5 w! K$ @) h" |
  12.   /* Clears SR2 register */
    6 M6 v) I! f' z% E8 D
  13.   I2C1->SR2 = 0;* v# |" T/ K% ?% a: U
  14.   /* Set LED2 */
    ' `: g% q. J% `1 A
  15.   STM_EVAL_LEDOn(LED2);
    1 i, _$ l% t; @1 F. X- {# K
  16.   }
    + F! X! j8 U7 J4 m0 q4 u8 h
  17.   Event = I2C_GetLastEvent(I2C1);: `, {. |8 B8 _- C! `1 K
  18.   switch (Event)
    & C, L& q/ `  Z+ ^
  19.   {
    & A7 c7 ?, A6 w: l
  20.   /******* Slave transmitter ******/
    % s' V( g# v% l) w
  21.   /* check on EV1 */1 I: j* Q5 j0 j' X7 z* D7 Q
  22.   case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
      C' b7 i2 M& j* D
  23.   Tx_Idx = 0;
    - C2 c; O( t0 s% |
  24.   break;
    * U: o# Z. F- z& o4 Q0 S
  25.   /* check on EV3 */
    7 m4 r# ?2 L# x6 ?( f( `
  26.   case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:7 h8 S- n, u; ~
  27.   /* Transmit data */: Z' T+ B$ s) ?
  28.   I2C_SendData(I2C1, Slave_Buffer_Rx[Tx_Idx++]);# w( g" \6 u7 P, p. a7 k: Q
  29.   break;2 i3 ]6 K- s) Z2 T& k& X8 U6 V; m
  30.   /******* Slave receiver **********/
    ! i% H. X5 o  F3 Z/ A
  31.   /* check on EV1*/8 U0 ]* p! c$ a1 m2 W6 V# B
  32.   case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
    / p+ b- t' P; v5 g7 e- T
  33.   break;, C2 g$ a7 C3 `. R: g
  34.   /* Check on EV2*/
    ; K, z: h7 _/ @/ c# }
  35.   case I2C_EVENT_SLAVE_BYTE_RECEIVED:
    + A+ o" l: X+ F1 {2 E; _. S: Y$ |: M
  36.   Slave_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData(I2C1);
    8 ], H* q, Y4 T5 s0 i! r; I- a
  37.   break;
    ! v5 ?9 s- ~5 g7 ~
  38.   /* Check on EV4 */" x+ n( J) V/ Q3 L8 m
  39.   case (I2C_EVENT_SLAVE_STOP_DETECTED):
    ' g! S3 z3 I! @% [3 p
  40.   /* write to CR2 to clear STOPF flag */
    , V6 G, |) R+ P8 A/ e/ ~9 Y
  41.   I2C1->CR2 |= I2C_CR2_ACK;
    ; D6 t" _. z- e3 J+ n
  42.   break;
    ( P2 A+ |3 R9 T' ~
  43.   default:
    / d1 \0 h1 h! C# W0 j% g. M* N! p+ w1 G- r6 d
  44.   break;, H- o2 p. S& g8 p
  45.   }! s" C7 c) ^; t% s
  46.   }
复制代码
/ v: P1 O  N' B0 D6 v& D
  客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到 I2C 的 STOP 信号后,从机都要给 I2C_CR2 的STOP 置位来释放 SCL 和 SDA 信号线。
* q& l' F0 k4 V. B+ |
7 {! {  u, ]! |# w E04GTO~GKN_@95G%1@TM$_B.png $ D3 H) F6 U1 w: F8 W% w6 c' t. W
- F: q* j) U, m; W: V- }' z" @

& x8 L1 D0 k$ @" O3 P# |/ L! y
6 E- y+ p1 Z! F7 e8 N' h2 {% E  客户对 I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:0 |; u2 {( q3 u" i* ~* j
  1. case (I2C_EVENT_SLAVE_STOP_DETECTED):4 V, j) ^7 q& U9 e
  2. /* write to CR2 to clear STOPF flag */
    8 J9 s, G. W6 C! y9 B1 ^
  3. //I2C1->CR2 |= I2C_CR2_ACK;
    ' e7 n( r& q; ^: x& B  Y! q
  4. I2C1->CR2 |= (I2C_CR2_ACK + I2C_CR2_STOP);
    ( W# J" n: P7 W( a! ^0 X( a3 {9 w
复制代码
9 y7 ]$ t9 ]  j+ \8 k
  跟踪程序发现 I2C 主机在发送第二次数据时,从第一个 byte 数据传输完成时信号波形开始不正常,从机一直没有 ACK 发出来。
0 U) b% S9 R" z0 ^  SCL 线一直保持在低电平。
' K# b0 h( |% _- s2 ^9 i3 N  跟踪从机程序,发现第二次传输时 ADDR 中断能正常进入,从机也有应答,但之后 RXNE 位一直不会被置位,被置位的是I2C_SR1 的 bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
1 Y! j+ {. Z4 u$ C3 Q& I3 R# y3 z( ?: l, M9 n0 {
~DN07}I~B2H)XG$ETEBSA8J.png 8 X, A& P4 O) i/ I1 V, b$ a
$ O( s' V$ D* M- a
把程序恢复成示例程序,通信正常。$ f7 U  h0 f$ w& d) f
9 _' a+ g' h9 Z; b" z2 y
9 n- K  `( d* Y4 |$ L" y% O
5.代码设计中应注意的地方。4 C# f* }6 g- e; |- ~8 h
建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
- S/ T8 ^. i6 g  Z# v! A不要测试完成后又忘了修改回来。4 `4 J& t8 Z$ ^/ P* _/ B

- U1 y0 E" N/ ]2 `# F. G' }
赞 收藏 评论0 发布时间:2022-2-14 23:46

举报

0个回答

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版