[Kinetis] i2c slave模式通信异常

[复制链接]
 楼主| thammer 发表于 2015-3-27 18:50 | 显示全部楼层 |阅读模式
本帖最后由 thammer 于 2015-3-27 20:03 编辑

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

  4. void I2C0_IRQHandler(void)
  5. {
  6.     // uint8_t u8_Resigter;
  7.     static uint8_t u8_SlaverMOde = 0;
  8.     //u8_Resigter = I2C0_S;
  9.                
  10. /*-----------------地址匹配事件-----------------------------*/
  11. //                 if(((u8_Resigter & I2C_S_IAAS_MASK)!=0)||((u8_Resigter & I2C_S_RAM_MASK)!=0))//从机地址匹配--寄存器I2C_C1写入任何值清零--设置模式中已经相当清零(I2C_C1写入一次)
  12. //                 {
  13. //                         //u8_ReadAddress = I2C0_D;//读取从机地址        
  14. //                 }
  15.           printf("I2C int \r\n");
  16.     /*-----------------停止事件----------------------------*/               
  17.     if((I2C0->FLT & I2C_FLT_STOPF_MASK)!=0)
  18.     {
  19.         I2C0->FLT |= I2C_FLT_STOPF_MASK;//写1 清零 停止位标志清零,需要先清零stopf,再清零IICIF        
  20.         I2C0->S   |= (1 << 1);        //        I2C_S_IICIF_MASK--清零中断标志
  21.         I2C0->C1  &= ~(1 << 3); //I2C_C1_TXAK_MASK 返回非应答
  22.         printf("I2C stop event \r\n");
  23.     }
  24.     I2C0->S   |= (1 << 1);        //        I2C_S_IICIF_MASK--清中断标志         
  25.     /*-----------------Arbitration Lost事件----------------------------*/               
  26.         
  27.     if((I2C0->S & I2C_S_ARBL_MASK)!=0)
  28.     {
  29.         I2C0->S |= I2C_S_ARBL_MASK;//写1清零 清除ARBL
  30.         printf("I2C ARBL \r\n");
  31.         if (!(I2C0->S & I2C_S_IAAS_MASK)) //如果地址不是从机地址,跳出
  32.         {   /* IAAS 非 1  */
  33.             return;
  34.         }                  
  35.     }
  36.     /*-----------------从机接收处理 ----------------------------*/               
  37.     if ((I2C0->S & I2C_S_IAAS_MASK)==I2C_S_IAAS_MASK) //地址匹配事件
  38.     {                                                                          
  39.         printf("I2C Address \r\n");
  40.         if((I2C0->S & I2C_S_SRW_MASK)!=0)//从机发送模式
  41.         {
  42.             printf("I2C Tx \r\n");
  43.             i2c0_Put_Tx_Mode;
  44.             u8_SlaverMOde = 0;//从发送
  45.             I2C0->D = 0x23;//I2C0_TxBuf[Tx_Count++];//从机发送数据
  46.         }
  47.         else                            //从机接收模式
  48.         {
  49.             printf("I2C Rx \r\n");
  50.             i2c0_Put_Rx_Mode;
  51.             u8_SlaverMOde = 1;//从接收
  52.             if (I2C0->D);    //读一次  
  53.         }                                
  54.     }         
  55.     else
  56.     {
  57.         printf("I2C dataing \r\n");
  58.         switch (u8_SlaverMOde)
  59.         {
  60.             case 0://从发送
  61.                 printf("I2C Send \r\n");
  62.                 if (I2C0->S & 0x01 ) //从机发送 主机ACK应答失败  停止发送
  63.                 {/* 应答检测                     */
  64.                   /* 主机应答失败,停止发送       */
  65.                     I2C0->C1 &= ~(1 << 4); //设置为接收模式 /* 接收模式 */
  66.                     if (I2C0->D) ; /* 读一次 */
  67.                     printf("I2C ACK error \r\n");
  68.                 }
  69.                 else //从机发送 主机ACK应答成功
  70.                 {         
  71.                     #if 0
  72.                     if(Tx_Count<I2C0_ReceBufSize)             /* 发送其他数据  */        
  73.                     {
  74.                         I2C0->D = I2C0_TxBuf[Tx_Count++];
  75.                         printf("send Data:%p\r\n",I2C0_TxBuf[Tx_Count]);
  76.                     }
  77.                     else
  78.                     {
  79.                         Tx_Count = 0;
  80.                         I2C0->D = I2C0_TxBuf[Tx_Count++];
  81.                     }
  82.                     #else
  83.                         I2C0->D = 0x12;
  84.                     #endif
  85.                 }                                
  86.                 break;        

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



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

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


下面是主机发送程序:
  1. unsigned char I2C0_ReadRegister(unsigned char SlaveID,unsigned char u8RegisterAddress)
  2. {
  3.   unsigned char result;
  4.         //unsigned char SlaveID;
  5.         uint8_t I2C_Temp;
  6.   /* Send Slave Address */
  7.   I2C0_StartTransmission(SlaveID,MWSR);
  8.   i2c0_Wait;
  9.   /* Write Register Address */
  10.   I2C0->D = u8RegisterAddress;
  11.   i2c0_Wait;

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

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

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

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

  22.   /* Dummy read */
  23.   result = I2C0->D ;
  24.         I2C_Temp = result;
  25.   i2c0_Wait;

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

  28.   /* Read byte */
  29.   result = I2C0->D ;
  30.         I2C_Temp = result;
  31.   return I2C_Temp;
  32. }




598330983 发表于 2015-3-27 21:22 来自手机 | 显示全部楼层
这种问题我也不会,坐等高手
598330983 发表于 2015-3-27 21:22 来自手机 | 显示全部楼层
主要吧楼主调试成功过没,还有官方例子有木有
598330983 发表于 2015-3-27 21:41 来自手机 | 显示全部楼层
好复杂的应用
 楼主| 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通信失败      
FSL_TICS_ZJJ 发表于 2015-4-10 15:45 | 显示全部楼层
非常感谢你关于Kinetis的技术问题。如果你没有其他问题,我们将此帖默认为已解决.
我是MT 发表于 2015-4-16 20:41 | 显示全部楼层
  发送完第一个数据,我这边会收到TCF产生的中断,然后进入56行那个else里面,而此时应答还没过来,程序就会进入63-69行,此时总线拉死。,原来是这样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

34

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部