天天看點

也談WinCE6.0+S3C6410 IIC驅動Bug

  最近在調試Camera驅動時候,發現通過IIC讀寫Camera裝置時,總是出現問題。跟蹤調試發現,對Camera裝置的寫操作基本不會出現問題,但是讀操作有時候正常,有時候不正常。從序列槽輸入調試資訊發現,讀操作總是出現“ACK NOT received”,在分析這部分源碼時,發現此處的邏輯有些問題,同時從網上查找到了有人也遇到了這個問題,不過對于網上的分析,本人有一些不同的看法,這裡描述一下。如果有不正确的地方,望指正。

       其次給出本人的平台環境: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即可,如下:

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

  g_uIIC_PT++;  //add by jazka 2011.10.31 

       問題二:讀操作時常出現失敗

       上面問題一提到了,雖然總是提示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"))); 

CleanUp: 

        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,如需轉載請自行聯系原作者

繼續閱讀