也谈WinCE6.0+S3C6410 IIC驱动Bug

简介:
  最近在调试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) 函数导致的不合理。


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/702584,如需转载请自行联系原作者
相关文章
|
18天前
【STM32】通过RTThread驱动W25QXXX
【STM32】通过RTThread驱动W25QXXX
|
10月前
|
C语言
野火F1开发板STM32案例-MultiButton移植
野火F1开发板STM32案例-MultiButton移植
128 0
|
11月前
|
缓存 Linux 芯片
Linux驱动分析之Uart驱动
之前对Uart驱动的整体架构做了介绍,现在来分析具体的驱动程序。我们以NXP 的 IMX6来进行分析。
|
11月前
|
存储 芯片 UED
【STM32】单片机模式配置&FlyMcu串口下载固件&STLINK Utility
【STM32】单片机模式配置&FlyMcu串口下载固件&STLINK Utility
316 0
|
11月前
|
Linux 芯片
Linux驱动分析之SPI设备
前面我们对SPI控制器驱动进行了分析,接下来来分析SPI设备驱动。我们以DS1302驱动作为分析对象。DS1302是一款RTC芯片,估计很多人在学单片机时用到过。RTC芯片算是比较简单的,也方便分析理解。
Linux驱动分析之SPI设备
|
11月前
|
缓存 Linux API
Linux驱动分析之Uart驱动架构
UART设备驱动可以使用tty驱动的框架来实现,但是因为串口之间有共性,所以Linux在tty接口上封装了一层(serial core)。后面我们再拿一篇文章来解释tty驱动,tty其实就是各种终端设备,串口其实也是终端设备。
Linux驱动分析之Uart驱动架构
|
Linux 开发工具 git
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
189 1
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型
|
Ubuntu Linux 开发工具
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动(下)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动
243 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动(下)
|
Ubuntu Linux 数据安全/隐私保护
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动(上)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动
293 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发(八)IMX6ULL开发板编译第一个程序以及驱动(上)
|
XML Ubuntu 前端开发
嵌入式linux/鸿蒙开发板(IMX6ULL)开发流程(六)烧写整个系统或更新部分系统
嵌入式linux/鸿蒙开发板(IMX6ULL)开发流程(六)烧写整个系统或更新部分系统
663 0
嵌入式linux/鸿蒙开发板(IMX6ULL)开发流程(六)烧写整个系统或更新部分系统