搜索
查看: 4885|回复: 4

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

[复制链接]
  • TA的每日心情
    开心
    2018-2-6 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    1182

    主题

    4967

    帖子

    1

    蝴蝶豆

    论坛元老

    最后登录
    2020-3-17
    发表于 2017-5-5 09:34:51 | 显示全部楼层 |阅读模式
    STM8Lxxx I2C 程序第二次数据通信失败的问题分析

    前言
    本篇文章主要是对STM8Lxxxx 在I2C 通信调试中遇到的第一次通信正常,但第二次通信失败问题的分析和处理。

    1. I2C 协议总体分析。
    STM8Lxxx I2C 硬件逻辑使用时非常灵活,因此也造成对各个状态处理的复杂性,稍不注意,I2C 调试就不能通过。
    下面是I2C 开始(START)和结束(STOP)波形,STM8Lxxx 也是遵守这个协议的。
    SCL 信号由主控提供。
    STM8Lxxx 总线端口为开漏输出,外部需要上拉电阻。
    下面协议为简单的单主控单从机收发协议。
    11.jpg

    2. 下面对一个简单的单主机发送,单从机接收协议进行说明
    下面为主发送的一个协议图:
    主控给从机发送数据,等到从机应答信号后再发送下byte 数据,直到数据发送完成后,主机发送一个stop 信号释放总线。
    12.jpg

    下面是从机接收协议图,从机接收主机发过来的数据并存储,每byte 传输完成后发送一个应答信号给主机(从机在每byte 传输完的第九个Clock 把SDA 信号线拉低到低电平)。
    13.jpg

    3. 程序中的出错现象
    客户的程序调时发现相同的数据连续从主控发给从机,只有第一次的通信波形是好的,第二次通信时设备地址可正常发送,从机也有应答,但当第一byte 数据发送完成后,主机收不到从机的应答信号。

    4. 问题产生原因
    客户使用的是E:\Download\STM8L\STSW-STM8016\STM8L15x-16x-05x-AL31-L_StdPeriph_Lib\Project\STM8L15x_StdPeriph_Examples\I2C\I2C_TwoBoards\I2C_DataExchange 中的程序。
    14.png
    15.jpg

    客户在程序编写时看到下图中用橙色标出的文字,就错误理解成从机每次收到I2C 的STOP 信号后,从机都要给I2C_CR2 的STOP 置位来释放SCL 和SDA 信号线。
    16.jpg
    17.jpg

    客户对I2C 中断处理程序进行了修改,对应的代码如下,黄色部分标出了客户修改的代码:
    18.jpg

    跟踪程序发现I2C 主机在发送第二次数据时,从第一个byte 数据传输完成时信号波形开始不正常,从机一直没有ACK 发出来。SCL 线一直保持在低电平。
    跟踪从机程序,发现第二次传输时ADDR 中断能正常进入,从机也有应答,但之后RXNE 位一直不会被置位,被置位的是I2C_SR1 的bit7, TXE 位一直为“1”,而中断处理中并没对这一状态进行处理和清空,所以一直会不断进入中断处理程序,不做处理又跳出中断,程序通信就死在了这里。
    19.jpg

    把程序恢复成示例程序,通信正常。

    5.代码设计中应注意的地方。
    建议客户在修改示例代码时谨慎一些,特别要注意重要寄存器的操作;弄明白后再进行更改;如果需要测试,最好标注清楚,
    不要测试完成后又忘了修改回来。


    文档下载

    更多实战经验
    回复

    使用道具 举报

    该用户从未签到

    19

    主题

    309

    帖子

    0

    蝴蝶豆

    金牌会员

    最后登录
    2019-1-17
    发表于 2017-5-5 13:48:15 | 显示全部楼层
    谢谢分享,,不过我一般都用模拟 的。。。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    帖子

    0

    蝴蝶豆

    新手上路

    最后登录
    2018-6-22
    发表于 2017-6-21 10:25:37 | 显示全部楼层
    我遇到了一样的问题,可是我用的是官方示例代码,且没有做任何修改,在100kbps的速度下,会出现跟你说的问题一样,然而5kbps就不会了 。能给我些建议么
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    帖子

    0

    蝴蝶豆

    新手上路

    最后登录
    2018-6-22
    发表于 2017-6-21 16:19:39 | 显示全部楼层
    希望这个回答能帮助到大家。我也遇到相同的问题。
    在这几天的努力下主要发现两个问题1.在传输过程中,特别当速度快的时候,当从机处于接收状态时, 有些时候,SR1寄存器中RXNE和STOPF两个状态位同时被置1,不知道这种情况是不是被允许的,然而官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败;当从机处于发送状态时,SR1寄存器中BTF和TXE两个状态位同时被置1,相同的,官方给的示例代码里没有对这种状态进行处理,导致I2C传输失败。
    下面是官方给的中断中的示例代码,其中default中的内容为我修改的内容,主要是对传输过程中,SR1寄存器中有两个状态位同时被置的处理。经修改后,能正常通信。但是不知道是不是真的是这个问题,希望大虾们拍砖。
    void bsp_i2c_slave_received_for_isr(void){
            //static uint8_t a=0;
            /* Read SR2 register to get I2C error */
            if ((I2C->SR2) != 0)
            {
            /* Clears SR2 register */
            I2C->SR2 = 0;

            }
            i2c_slave.Event = I2C_GetLastEvent();
            switch (i2c_slave.Event)
            {
              /******* Slave transmitter ******/
              /* check on EV1 */
            case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
              i2c_slave.Tx_Idx = 0;
              break;

              /* check on EV3 */
            case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:
              /* Transmit data */
              I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);
              break;
              /******* Slave receiver **********/
              /* check on EV1*/
            case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
              break;

              /* Check on EV2*/
            case I2C_EVENT_SLAVE_BYTE_RECEIVED:
              i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();
             
              break;

              /* Check on EV4 */
            case (I2C_EVENT_SLAVE_STOP_DETECTED):
                            /* write to CR2 to clear STOPF flag */
                            I2C->CR2 |= I2C_CR2_ACK;

              break;

            default:
              if ((I2C->SR1&0x40) != 0)
              {
              /* Clears SR2 register */
                i2c_slave.Slave_Buffer_Rx[i2c_slave.Rx_Idx++] = I2C_ReceiveData();

              }
              if ((I2C->SR1&0x04) != 0)
              {
              /* Clears SR2 register */
                I2C_SendData(i2c_slave.Slave_Buffer_Rx[i2c_slave.Tx_Idx++]);

              }
              break;
            }
            
    }
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    1

    主题

    18

    帖子

    2

    蝴蝶豆

    初级会员

    最后登录
    2020-7-31
    发表于 2019-12-27 13:24:22 | 显示全部楼层
    感谢分享,顶起来。

    昨天调试STM8L还发现了一个硬件问题, IIC通信线的上拉电阻太小,导致通信没有识别“低”状态。建议将I2C两个脚初始化成标准IO,一秒钟翻转一次,发现IO口能输出方波,但是没有低状态。。把上拉电阻换大一点问题解决。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

    GMT+8, 2024-4-28 02:13 , Processed in 1.212252 second(s), 41 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表