打印
[Kinetis]

i2c slave模式通信异常

[复制链接]
2036|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
thammer|  楼主 | 2015-3-27 18:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 thammer 于 2015-3-27 20:03 编辑

主从机都是KL16,从机以中断方式接收,中断服务程序如下:
extern uint8_t Rx_Count,Tx_Count;
extern uint8_t I2C0_RxBuf[I2C0_ReceBufSize];
extern uint8_t I2C0_TxBuf[I2C0_ReceBufSize];

void I2C0_IRQHandler(void)
{
    // uint8_t u8_Resigter;
    static uint8_t u8_SlaverMOde = 0;
    //u8_Resigter = I2C0_S;
               
/*-----------------地址匹配事件-----------------------------*/
//                 if(((u8_Resigter & I2C_S_IAAS_MASK)!=0)||((u8_Resigter & I2C_S_RAM_MASK)!=0))//从机地址匹配--寄存器I2C_C1写入任何值清零--设置模式中已经相当清零(I2C_C1写入一次)
//                 {
//                         //u8_ReadAddress = I2C0_D;//读取从机地址        
//                 }
          printf("I2C int \r\n");
    /*-----------------停止事件----------------------------*/               
    if((I2C0->FLT & I2C_FLT_STOPF_MASK)!=0)
    {
        I2C0->FLT |= I2C_FLT_STOPF_MASK;//写1 清零 停止位标志清零,需要先清零stopf,再清零IICIF        
        I2C0->S   |= (1 << 1);        //        I2C_S_IICIF_MASK--清零中断标志
        I2C0->C1  &= ~(1 << 3); //I2C_C1_TXAK_MASK 返回非应答
        printf("I2C stop event \r\n");
    }
    I2C0->S   |= (1 << 1);        //        I2C_S_IICIF_MASK--清中断标志         
    /*-----------------Arbitration Lost事件----------------------------*/               
        
    if((I2C0->S & I2C_S_ARBL_MASK)!=0)
    {
        I2C0->S |= I2C_S_ARBL_MASK;//写1清零 清除ARBL
        printf("I2C ARBL \r\n");
        if (!(I2C0->S & I2C_S_IAAS_MASK)) //如果地址不是从机地址,跳出
        {   /* IAAS 非 1  */
            return;
        }                  
    }
    /*-----------------从机接收处理 ----------------------------*/               
    if ((I2C0->S & I2C_S_IAAS_MASK)==I2C_S_IAAS_MASK) //地址匹配事件
    {                                                                          
        printf("I2C Address \r\n");
        if((I2C0->S & I2C_S_SRW_MASK)!=0)//从机发送模式
        {
            printf("I2C Tx \r\n");
            i2c0_Put_Tx_Mode;
            u8_SlaverMOde = 0;//从发送
            I2C0->D = 0x23;//I2C0_TxBuf[Tx_Count++];//从机发送数据
        }
        else                            //从机接收模式
        {
            printf("I2C Rx \r\n");
            i2c0_Put_Rx_Mode;
            u8_SlaverMOde = 1;//从接收
            if (I2C0->D);    //读一次  
        }                                
    }         
    else
    {
        printf("I2C dataing \r\n");
        switch (u8_SlaverMOde)
        {
            case 0://从发送
                printf("I2C Send \r\n");
                if (I2C0->S & 0x01 ) //从机发送 主机ACK应答失败  停止发送
                {/* 应答检测                     */
                  /* 主机应答失败,停止发送       */
                    I2C0->C1 &= ~(1 << 4); //设置为接收模式 /* 接收模式 */
                    if (I2C0->D) ; /* 读一次 */
                    printf("I2C ACK error \r\n");
                }
                else //从机发送 主机ACK应答成功
                {         
                    #if 0
                    if(Tx_Count<I2C0_ReceBufSize)             /* 发送其他数据  */        
                    {
                        I2C0->D = I2C0_TxBuf[Tx_Count++];
                        printf("send Data:%p\r\n",I2C0_TxBuf[Tx_Count]);
                    }
                    else
                    {
                        Tx_Count = 0;
                        I2C0->D = I2C0_TxBuf[Tx_Count++];
                    }
                    #else
                        I2C0->D = 0x12;
                    #endif
                }                                
                break;        

            case 1://从接收
                printf("I2C Rece \r\n");
                if(Rx_Count<I2C0_ReceBufSize)
                {
                    I2C0_RxBuf[Rx_Count++]=I2C0->D;
                }
                else
                {
                    Rx_Count = 0;
                    I2C0_RxBuf[Rx_Count++]=I2C0->D;
                }
                printf("%p\r\n",I2C0_RxBuf[0]);
                break;
               
            default :
                printf("I2C defalut \r\n");
                i2c0_Put_Rx_Mode;                                  /* 接收模式                     */
                if(I2C0->D) ;                                  /* 读一次                       */                 
                break;                                
        }
    }
        //I2C0_S |= I2C_S_IICIF_MASK;//写1 清零
}
主机能正确读到第一次的数据0x23,之后SCL,SDA被拉低。错误发生在:
if (I2C0->S & 0x01 ) //从机发送 主机ACK应答失败 停止发送
{/* 应答检测 */
/* 主机应答失败,停止发送 */
I2C0->C1 &= ~(1 << 4); //设置为接收模式 /* 接收模式 */
if (I2C0->D) ; /* 读一次 */
printf("I2C ACK error \r\n");
}
从机接收流程:
                     地址匹配中断-->切换为接收模式--->接收数据--->地址匹配中断--->切换为发送模式紧跟着发送第一个字节---->接收到停止中断,非应答,从机一个字节发送完成



但是看打印实际跑的流程是:
                       地址匹配中断-->切换为接收模式--->接收数据--->地址匹配中断--->切换为发送模式紧跟着发送第一个字节---->(未收到停止中断)准备发送第二个字节前检测到主机对第一一个字节无应答,卡死。

这里,应该不是主机没应答,而是SCL,SDA被从机拉死。请问这是什么原因?


下面是主机发送程序:
unsigned char I2C0_ReadRegister(unsigned char SlaveID,unsigned char u8RegisterAddress)
{
  unsigned char result;
        //unsigned char SlaveID;
        uint8_t I2C_Temp;
  /* Send Slave Address */
  I2C0_StartTransmission(SlaveID,MWSR);
  i2c0_Wait;
  /* Write Register Address */
  I2C0->D = u8RegisterAddress;
  i2c0_Wait;

  /* Do a repeated start */
  I2C0->C1 |= I2C_C1_RSTA_MASK;

  /* Send Slave Address */
  //I2C0->D = ((unsigned char) (ACCEL_I2C_ADDRESS << 1)|0x01); //read address
        I2C0->D = (unsigned char) (SlaveID|0x01); //read address
  i2c0_Wait;

  /* Put in Rx Mode */
  I2C0->C1 &= (~I2C_C1_TX_MASK);

  /* Turn off ACK since this is second to last byte being read*/
  I2C0->C1 |= I2C_C1_TXAK_MASK;

  /* Dummy read */
  result = I2C0->D ;
        I2C_Temp = result;
  i2c0_Wait;

  /* Send stop since about to read last byte */
  i2c0_Stop;

  /* Read byte */
  result = I2C0->D ;
        I2C_Temp = result;
  return I2C_Temp;
}




相关帖子

沙发
598330983| | 2015-3-27 21:22 | 只看该作者
这种问题我也不会,坐等高手

使用特权

评论回复
板凳
598330983| | 2015-3-27 21:22 | 只看该作者
主要吧楼主调试成功过没,还有官方例子有木有

使用特权

评论回复
地板
598330983| | 2015-3-27 21:41 | 只看该作者
好复杂的应用

使用特权

评论回复
5
thammer|  楼主 | 2015-3-31 18:48 | 只看该作者
这个问题已解决,原因是:
        发送完第一个数据,我这边会收到TCF产生的中断,然后进入56行那个else里面,而此时应答还没过来,程序就会进入63-69行,此时总线拉死。
改进的方法是将56行的else改为:else if((I2C0->S & I2C_S_TCF_MASK)==I2C_S_TCF_MASK)

不过我依然发现一个问题,每次进中断必须延时一下,否则i2c通信失败      

使用特权

评论回复
6
FSL_TICS_ZJJ| | 2015-4-10 15:45 | 只看该作者
非常感谢你关于Kinetis的技术问题。如果你没有其他问题,我们将此帖默认为已解决.

使用特权

评论回复
7
我是MT| | 2015-4-16 20:41 | 只看该作者
  发送完第一个数据,我这边会收到TCF产生的中断,然后进入56行那个else里面,而此时应答还没过来,程序就会进入63-69行,此时总线拉死。,原来是这样

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

34

帖子

0

粉丝