【转载】也谈WinCE6.0+S3C6410 IIC驱动Bug

转载自:http://jazka.blog.51cto.com/809003/702584

最近在调试Camera驱动时候,发现通过IIC读写Camera设备时,总是出现问题。跟踪调试发现,对Camera设备的写操作基本不会出现问题,但是读操作有时候正常,有时候不正常。从串口输入调试信息发现,读操作总是出现“ACK NOT received”,在分析这部分源码时,发现此处的逻辑有些问题,同时从网上查找到了有人也遇到了这个问题,不过对于网上的分析,本人有一些不同的看法,这里描述一下。如果有不正确的地方,望指正。
 
先给出网络上对这一问题分析的文章《s3c6410 winCE6.0 IIC驱动BUG》,地址http://blog.csdn.net/knock/article/details/4758818
其次给出本人的平台环境:Wince6.0+S3C6410+Android6410开发板。
 
问题一:为什么读操作会出现“ACK NOT received”
查看该提示出现的函数是IIC中断处理函数IIC_IST中,如下:
if (iicstat & ACK_NOT_RECEIVED) 

  DEBUGMSG(ZONE_ERROR,(TEXT("I2C_IST[0x%x, %d]: ACK NOT received \r\n"), 
    g_OwnerContext, g_uIIC_PT)); 
}
在IIC_IST中断处理函数中,对于读操作的处理代码如下:
case Master_receive: 
        if (g_uIIC_PT>0) 
        { 
                bDone = FALSE; 
                g_pcIIC_BUFFER[g_uIIC_PT-1] = g_pIICReg->IICDS; 
        } 

        g_uIIC_PT++; 

        if (g_uIIC_PT==g_uIIC_DATALEN) 
        { 
                g_pIICReg->IICCON &= ~(1<<7); 
        } 
        else if (g_uIIC_PT > g_uIIC_DATALEN) 
        { 
                bDone = TRUE; 
                g_pIICReg->IICSTAT = MRX_STOP; 
        } 

        g_pIICReg->IICCON &= ~(1<<4); 
        break;
在这部分代码中加入调试信息会发现,在请求读取Camera设备8字节数据的过程中,共进入此处三次,也就是说明中断了三次。博文《s3c6410 winCE6.0 IIC驱动BUG》中对第二中断非正常的中断,本人不是很赞同这种说法。
Master在初始化读取配置之后,先是开始信号,之后是将slave address写入IICDS寄存器,在该地址传递给Camera设备之后,Camera设备回复ACK,同时Master发生中断,此乃第一次中断;之后Camera设备发送请求的数据,SDA上的数据移入IICDS寄存器,此时产生第二次中断,Master读取8字节的数据;读取之后,由于没有发送结束信号,所有SDA上数据依然移入IICDS寄存器,故产生第三次中断,此时发送结束信号。
       结合上面的源码发现,逻辑确实有些问题,在第一次中断中,将IICCON寄存器的bit[7]清空,导致第二次中断时,if (iicstat & ACK_NOT_RECEIVED)语句成立,也就出现了ACK NOT received的提示,但是之后仍然能够将请求的数据读取到,所以应该是逻辑上的不合理,而不应该说是错误。
       解决的方法就是将IICCON寄存器bit[7]清空的操作往后移一个Clock即可,如下:
case Master_receive: 
        if (g_uIIC_PT>0) 
        { 
                bDone = FALSE; 
                g_pcIIC_BUFFER[g_uIIC_PT-1] = g_pIICReg->IICDS; 
        } 

        //g_uIIC_PT++;         //delete by jazka 2011.10.31 

        if (g_uIIC_PT==g_uIIC_DATALEN) 
        { 
                g_pIICReg->IICCON &= ~(1<<7); 
        } 
        else if (g_uIIC_PT > g_uIIC_DATALEN) 
        { 
                bDone = TRUE; 
                g_pIICReg->IICSTAT = MRX_STOP; 
        } 

  g_uIIC_PT++;  //add by jazka 2011.10.31 

        g_pIICReg->IICCON &= ~(1<<4); 
        break;
 
问题二:读操作时常出现失败
  上面问题一提到了,虽然总是提示ACK NOT received,但是不影响请求数据的读取,所以读操作偶尔失败,偶尔成功的现象是由其他地方引起的。写操作总是可以成功,所以需要看一下读操作和写操作的区别,最大的区别莫过于每次读操作之前都会进行一次写操作,如下代码所示:
BOOL HW_Read(PHW_OPEN_INFO pOpenContext, PIIC_IO_DESC pInData ,PIIC_IO_DESC pOutData)

        BOOL retVal  = TRUE;                // Initialize to success 
        DEBUGMSG (ZONE_FUNCTION, (TEXT("+HW_Read(0x%X)\r\n"),pOpenContext)); 

        HW_SetRegister(pOpenContext); 
        HW_Write(pOpenContext, pInData); 

        ResetEvent(g_hTransferDone); 
        //Wait until IIC bus is free. 
        if(!WaitForReg((PVOID)&(g_pIICReg->IICSTAT), (1<<5), 0x0, TIMEOUT_MS_RX)) 
        { 
                DEBUGMSG(ZONE_ERROR,(TEXT("[IIC ERROR]IIS BUS is busy.\r\n"))); 
                retVal = FALSE; 
                goto CleanUp; 
        } 
        g_pcIIC_BUFFER =  pOutData->Data; 
        g_uIIC_PT  = 0; 
        g_uIIC_DATALEN = pOutData->Count; 

        g_pIICReg->IICCON |= (1<<7);                //Ack generation Enable 

        g_pIICReg->IICDS = pInData->SlaveAddress; 

        g_pIICReg->IICSTAT = MRX_START; 

        if(WaitForSingleObject(g_hTransferDone, TIMEOUT_MS_RX) == WAIT_TIMEOUT) 
        { 
                DEBUGMSG(ZONE_ERROR,(TEXT("[IIC ERROR]RX Time out.\r\n"))); 
                retVal = FALSE; 
        } 

CleanUp: 
        DEBUGMSG (ZONE_FUNCTION, 
                            (TEXT("+HW_Read(0x%X)\r\n"), 
                             pOpenContext)); 
        return retVal; 
}
       在HW_Write之后,等待IIC总线空闲之后才开始真正的读操作。在其他代码处经常看到在读写操作之后都会Sleep几秒,所以猜测是不是在HW_Write之后没有Sleep操作的原因导致的。于是在HW_Write之后加入Sleep(1)之后变发现读操作正常了。可能时钟设置的不同,Sleep的时间也不同,这里猜测还是时序问题导致的,不过本人没有细究下去了。以后有机会再细研究。
      
问题三:IIC_IST函数中对g_hTransferDone的不合理
       这个问题采用博文《s3c6410 winCE6.0 IIC驱动BUG》中的解决方法即可,修改的代码如下:
if (bDone) 

        DEBUGMSG(ZONE_INFO, (TEXT("SetEvent DONE\r\n"))); 
  bDone = FALSE;                 //add by jazka 2011.10.31 
        SetEvent(g_hTransferDone); 
}
       这样可以避免前面Master_receive情况下,多次执行SetEvent(g_hTransferDone)函数导致的不合理。

转载于:https://www.cnblogs.com/hao507/articles/2816492.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值