天天看點

WinCE6.0+ S3C6410 IIC驅動源碼學習

今天總結一下IIC驅動的源碼學習。IIC驅動也是Wince下的流接口驅動,是以配置檔案的設定和其他流接口都一樣,本人在以前已經對該問題做了介紹,這裡就不重複了。

       IIC驅動較為簡單,主要的源檔案有iic.h、iic_pdd.h、iic_mdd.h、iic_mdd.cpp和s3c6410_icc_lib.cpp五個檔案,三個h檔案都是關于相關資料結構和宏的定義,cpp檔案是所有功能的實作。

       下面主要從流接口的幾個接口函數來分析驅動源碼,包括DllEntry、IIC_Init、IIC_Deinit、IIC_Open、IIC_Close、IIC_IOControl、IIC_PowerUp和IIC_PowerDown。

       一、在Device.exe加載IIC驅動時,首先執行的是DllEntry和IIC_Init函數,DllEntry函數沒有任何實際的操作,這裡跳過,直接看IIC_Init函數。

       入口參數是關于IIC驅動在系統資料庫中的路徑。

       144行是為PHW_INIT_INFO結構體在堆上配置設定空間,pInitContext存儲在IIC_Init函數中獲得的相關資訊,并作為參數傳遞給IIC_Open函數。PHW_INIT_INFO結構體的定義在檔案iic_mdd.h中,這裡不再給出。

       174到204行讀取系統資料庫中的相關資訊,并将資料填充到pInitContext中。

       208行在後面的IIC中斷處理函數中使用,用來判斷是否驅動解除安裝。

       212行進行IIC硬體的相關初始化工作,後面分析。

       222行傳回pInitContext,将在後面作為IIC_Open函數的參數。

       HW_Init函數在檔案s3c6410_icc_lib.cpp中,下面分析一下該函數。

       94行MapVirtualAddress函數實作在本檔案s3c6410_icc_lib.cpp中,完成相關寄存器的虛拟位址映射。

       100行InitializeGPIOPort函數實作在本檔案s3c6410_icc_lib.cpp中,完成GPIO中GPB的相關設定,使IO為SCL和SDA功能。

       104到118行建立了兩個事件,g_hTransferEvent用于記錄發送和接收資料的事件,g_hTransferDone用于記錄發送結束或者接收結束的事件。

       122到139行首先向核心注冊中斷邏輯号(IRQ_I2C),然後通過InterruptInitialize将中斷号與相應的事件進行映射。當核心觸發該中斷時,通過查表觸發相應的事件。

       143行建立相應的中斷處理函數IIC_IST,該函數也在本檔案中,下面進行分析。

       677行和682行用來判斷IIC運作狀态,前面初始化時已經設定成了IIC_RUN的狀态,當退出IIC驅動的時候,修改狀态為IIC_FINISH,進而退出中斷處理線程。這是中斷處理線程中經常使用的方法。

       680行用來等待IIC收發資料事件的發生,逾時時間設定為無限等待。

       685到709行是對IIC四種狀态的判斷。ARBITRATION_FAILED代表IIC總線仲裁失敗即在申請對總線的使用權時失敗,SLAVE_ADDRESS_MATCHED代表收到的從裝置位址與ICCADD寄存器裡面的值相等,SLAVE_ADDRESS_ZERO代表收到的從裝置位址為0,ACK_NOT_RECEIVED代表收到的最後一個bit不是0,即沒有收到ACK信号。

       711行是用來判斷目前裝置處于何種狀态,由于CPU總是作為主裝置存在,是以隻能是主裝置接收和主裝置發送兩種狀态。

       741到756行是主裝置發送狀态的情況,if (g_uIIC_PT<g_uIIC_DATALEN)判斷資料是否發送完畢,沒有則繼續從Buffer中讀取一個位元組到IICDS寄存器中,如果發送完了,就置結束标志bDone,同時設定IICSTAT寄存器發送STOP信号,g_pIICReg->IICCON &= ~(1<<4)用來清除中斷标志,沒發送一個位元組都需要清除中斷标志。

       761到765行用來在接收或者發送結束的情況下,設定結束事件,以保證在程式的其他地方檢測到結束事件後進行相應的處理。

       二、上面操作完成之後,IIC驅動就已經成功加載了,當使用者調用CreateFile函數是調用IIC_Open函數,下面分析該函數,隻列出比較重要的内容。

       PHW_INIT_INFO是初始化函數IIC_Init傳回的資訊結構體,而PHW_OPEN_INFO是将該函數中收集的相關資訊結構體,用于傳回給IIC_IOControl的參數。

       pInitContext->OpenCnt用來記錄IIC打開的次數。

       372到378行用于初次打開IIC裝置時的處理,HW_OpenFirst函數主要完成從裝置位址設定和使能中斷。如下:

// slave address setting 

pInitContext-PDDCommonVal.SlaveAddress = DEFAULT_SLAVE_ADDRESS; 

pInitContext->PDDCommonVal.InterruptEnable = DEFAULT_INTERRUPT_ENABLE;

       HW_PowerUp函數用來打開IIC裝置Power,如下:

g_pSYSCONReg->PCLK_GATE |= IIC_POWER_ON;

       381行完成打開IIC裝置的大部分操作,HW_Open函數後面介紹。

       387行用來增加IIC裝置的開啟數量。

       HW_Open函數的絕大部分操作如下:

       401到404行主要完成時鐘、主從收發模式、過濾使能以及延時的設定。時鐘要根據從裝置的情況而設定,否則收發會出現問題,此處為了3000Hz。模式預設選擇為主裝置發送模式。

       CalculateClockSet函數用來設定時鐘分頻以達到想要的時鐘頻率。S3C6410有兩種模式,通過IICCON寄存器進行設定。

       408行的DirtyBit用來标記寄存器設定是否發生變化,每次設定寄存器時都需要判斷該标志。

       410行的HW_SetRegister函數用來設定IIC的寄存器,包括IICADD、IICSTAT、IICLC、IICCON四種寄存器,如下:

if(g_OwnerContext != pOpenContext || pOpenContext->DirtyBit == TRUE) 

        DEBUGMSG (ZONE_FUNCTION, 

                            (TEXT("+HW_SetRegister(0x%X)\r\n"), 

                             pOpenContext)); 

        g_pIICReg->IICADD = pOpenContext->pInitContext->PDDCommonVal.SlaveAddress; 

        g_pIICReg->IICSTAT = (g_pIICReg->IICSTAT & ~(0x3<<6)) | (1<<4) | (pOpenContext->PDDContextVal.ModeSel<<6); 

        g_pIICReg->IICLC = (pOpenContext->PDDContextVal.FilterEnable<<2) | (pOpenContext->PDDContextVal.Delay); 

        g_pIICReg->IICCON = (pOpenContext->PDDContextVal.ClockSel << 6) | (pInitContext->PDDCommonVal.InterruptEnable << 5) | 

                                                        (pOpenContext->PDDContextVal.ClockDiv & 0xf); 

        g_OwnerContext = pOpenContext; 

        pOpenContext->DirtyBit = FALSE; 

       三、最後在打開IIC裝置之後,便是通過IIC_IOControl接口對IIC裝置進行各種操作。IOControl控制碼主要包括一下幾種:

IOCTL_POWER_CAPABILITIES、IOCTL_IIC_WRITE、IOCTL_IIC_READ、IOCTL_IIC_SET_CLOCK、IOCTL_IIC_GET_CLOCK、IOCTL_IIC_SET_MODE、IOCTL_IIC_GET_MODE、IOCTL_IIC_SET_FILTER、

IOCTL_IIC_GET_FILTER、IOCTL_IIC_SET_DELAY、IOCTL_IIC_GET_DELAY等。

         在這些控制碼中,比較常用的是讀寫請求IOCTL_IIC_WRITE與IOCTL_IIC_READ、時鐘設定IOCTL_IIC_GET_CLOCK、延時設定IOCTL_IIC_SET_DELAY。

       時鐘設定的請求,實際調用的函數依然上面提到的CalculateClockSet函數。

       延時設定調用pOpenContext->PDDContextVal.Delay = (IIC_DELAY)*(UINT32*)pBufIn;

       寫請求主要調用HW_Write函數,大部分情況用來設定從裝置的初始化等,位于s3c6410_iic_lib.cpp檔案中,如下:

       578行根據寫請求之前的各項設定重新設定相關寄存器。

       580行重置g_hTransferDone事件,在每次的讀寫操作之前都需要該操作。

       582行是通過IICSTAT寄存器的狀态判斷IIC總線是否空閑,如果有其他裝置正在使用則需要等待其釋放。

       588行到598行首先記錄要發送資料的buffer以及長度,然後設定接收ACK信号和收發模式、從裝置的寫位址,最後發送START信号,此時IICDS上的資料變随着CLK發送到了從裝置,并且每次發送完一個位元組都會觸發收發資料的中斷處理線程函數中,前面已經介紹了。

       600行用于等待所有的資料都發送完成,包括STOP信号的發送。

       讀請求主要調用HW_Read函數,主要用來讀取從裝置的狀态及有效資料等,位于s3c6410_iic_lib.cpp檔案中,如下:

       529行到539行的内容基本都喝HW_Write函數的一樣,唯一不同的是多了一個函數HW_Write,在讀取從裝置資料之前,首先需要發送從裝置的寫位址,其次需要告訴從裝置你要讀取哪些資料(大多數是要讀取資料的位址),是以此處會包含該函數。

       540行到548行首先設定接收資料的buffer和長度,然後設定接收ACK信号和裝置模式、從裝置的讀位址等,最好發送START信号。

       600行用于等待所有的資料都接收完成。

本文轉自jazka 51CTO部落格,原文連結:http://blog.51cto.com/jazka/707401,如需轉載請自行聯系原作者

繼續閱讀