Windows CE串口驅動簡析(2)-PDD層實現:CReg2410Uart和TX部分(基於WinCE5.0 SMDK2410 BSP的Serial驅動)

二.PDD層
1.PDD架構
現在我們就來看看SMDK2410中串口驅動的PDD部分.
MDD層和PDD COMMON層都是由微軟提供的,一般情況下我們基本無須改動.微軟爲開發者提供了一個CSerialPDD類作爲開發工作的起點.CSerialPDD是個純虛類,我們需要將驅動程序的PDD層定義成CSerialPDD類的繼承類,其成員必須準確全面的反應目標硬件平臺的特定類型串口的屬性.
MDD和PDD COMMON層不需要知道用戶的CSerialPDD繼承類的命名和具體實現,以CSerialPDD類指針引用其繼承類實例的功能.
CSerialPDD的定義如下(位於/WINCE500/PUBLIC/COMMON/OAK/INC/cserpdd.h):

CSerialPDD類以CRegistryEdit類作爲它的父類.CRegistryEdit向它的繼承類提供了訪問系統註冊表的能力.成員函數定義在cserpdd.cpp中.
CSerailPDD類的數據成員和成員函數可以劃分爲以下幾個部分:
(1) 初始化部分
(2) 串口設備操作部分
(3) 電源管理部分
(4) 中斷接口部分
(5) 數據發送與接收部分
(6) MODEM功能部分
(7) 線路功能部分
(8) 串口配置部分
(9) IR特殊處理部分
(10) 錯誤處理部分
SMDK2410串口驅動PDD中CSerialPDD的繼承類就是CPdd2410Uart,這是2410平臺上3個UART端口都擁有的共同一個抽象類,裏面實現了串口大部分操作與具體哪個UART無關.
而CPdd2410Uart的繼承類CPdd2410Serial1和CPdd2410Serial2則實際對應於具體串口,分別爲UART0和UART1.
CPdd2410Uart實現在pdds3c2410_ser.cpp,而CPdd2410Serial1和CPdd2410Serial2實現在ser_smdk2410.cpp.
下面就先來看看CPdd2410Uart類.
2.CPdd2410Uart
(1)CPdd2410Uart原型
該類原型如下,繼承自CSerialPDD和CMiniThread類.

(2)CReg2410Uart
在詳細看CPdd2410Uart的成員函數之前,我們先來看看CPdd2410Uart會用到的另一個類CReg2410Uart.這個類封裝了對串口寄存器的操作函數.原型如下:
  
其中Write_ULCON,Read_ULCON等就是讀寫相應的UART寄存器,後面的m_pReg就是操作寄存器的虛擬地址.使用的READ_REGISTER_ULONG和WRITE_REGISTER_ULONG是CEDDK函數,用來讀寫寄存器.
下面來看看其他幾個成員函數.
[1] 構造函數CReg2410Uart
  
這個函數只是用來獲得CPU時鐘,同時給m_pReg附初值,也就是對應的UART寄存器地址.
[2] Init
用來初始化UART寄存器初值,都設爲0.
   
[3] Backup,Restore
用來備份和回覆UART寄存器內容.

[4] Write_BaudRate
寫波特率,首先判斷UCON(UART控制寄存器)BIT10選擇分頻時鐘源,然後寫UBRDIV(波特率分頻寄存器)來設置波特率.
   
另外還有個DumpRegister,用來輸出寄存器值,供調試使用,這裏就不多說了.
下面就來看看CPdd2410Uart的成員函數.
3.CPdd2410Uart構造函數
初始化了一些變量,如CReg2410Uart類對象,事件及其他標誌等.註釋如下:
 
4.析構函數~CPdd2410Uart()
主要就是關閉線程,關閉事件,禁止中斷,釋放地址空間資源,如CReg2410Uart類對象空間,寄存器地址空間等.
  
5.Init
該函數首先調用基類的Init函數,CSerialPDD的Init成員函數主要負責初始化串口驅動程序的電源管理.Init同時並檢查註冊表是否打開和m_XmitFlushDone,都爲TRUE則進一步初始化.
然後通過GetIsrInfo獲得邏輯中斷號,創建IST事件(m_hISTEvent),初始化m_dwSysIntr對應的中斷.觸發事件爲m_hISTEvent.
接着讀註冊表獲取如DeviceArrayIndex,InterruptBitsShift,ISTTimeouts等信息.
最後調用MapHardware和CreateHardwareAccess來映射硬件寄存器和創建特定UART的CReg2410Uart類對象.

接下來就來看看MapHardware和CreateHardwareAccess這兩個函數.
[1] MapHardware
該函數首先判斷m_pRegVirtualAddr是否爲NULL,如果爲NULL說明未初始化,第一次運行時應該爲NULL,接着使用DDKWINDOWINFO的結構通過讀註冊表還獲得InterfaceType和MemBase,MemLen(註冊表中設置的是50000000,即UART0寄存器物理地址)然後調用TranslateBusAddr將一個總線相對地址轉換成系統物理地址.使用MmMapIoSpace映射到IO虛擬地址空間.最後將2410中斷寄存器物理地址映射到IO虛擬地址空間.之所以有這樣的轉換過程,是因爲2410串口的母總線是Busenum.

[2] CreateHardwareAccess
這個函數就是生成CReg2410Uart類對象,針對具體的串口(註冊表中設置的是UART0),這樣調用該對象的成員函數就是對UART0寄存器進行讀寫操作了.
  
6.PostInit
該函數也是初始化函數,在Init之後調用,首先設置一個CRITICAL_SECTION防止重入寫衝突,然後設置UCON爲0,禁止UART中斷.如果此時SUBSRCPND有中斷請求,則調用InitReceive和InitLine進行接收並使能中斷結束後清除中斷標誌位.InitReceive和InitLine留在後面的內容分析.當確定SUBSRCPND無中斷請求時,調用基類的PostInit和設置線程優先級(從註冊表項Priority獲得),並啓動線程.
CSerialPDD::PostInit功能是初始化中斷處理和初始化MODEM.

7.ThreadRun
這個就是IST線程,創建自CMiniThread類,CMiniThread類封裝了對線程的基本操作,如ThreadStart,ThreadStop等.詳情可參考/WINCE500/PUBLIC/COMMON/OAK/INC/Cmthread.h.
像通常的驅動IST一樣,首先等待事件m_hISTEvent的發生,發生後去獲取中斷狀態來判斷是哪個中斷髮生了,根據不同的狀態設置不同的標誌.然後調用NotifyPDDInterrupt(基類CSerailPDD函數實現)向串口驅動程序報告串口中斷事件,接着清除中斷標誌位.最後調用InterruptDone結束本次中斷IST過程.
當其他中斷(RX,TX)沒有發生時,IST會默認INTR_MODEM來輪詢MODEM.也就是最後else裏做的工作.代碼如下:
  
8. InitialEnableInterrupt
這個函數比較簡單,用來初始化允許或者禁止RXD和ERR中斷.

9.InitXmit
InitXmit負責初始化串口的數據發送,該函數有一個bool型參數bEnable,TRUE表示初始化數據發送,FALSE表示解除初始化串口數據發送.
如果爲TRUE,則初始化UART寄存器,設置中斷方式(level觸發,傳輸模式-中斷請求或輪詢),復位發送FIFO,禁止FIFO,Tx FIFO中斷觸發方式(4字節),最後重新使能FIFO.
如果爲FALSE,則等待UTRSTA寄存器FIFO狀態爲空,即數據都已發送完畢.
代碼如下:
  
10.GetWriteableSize
GetWriteableSize用來獲取FIFO中可以寫入的字節數.首先讀取UFSTAT來獲得當前FIFO狀態,如果爲FULL則返回0,無可寫字節數.如果不爲0,則計算出當前可寫字節數,並返回.
代碼如下:

11. XmitInterruptHandler
XmitInterruptHandler被串口驅動程序的IST線程調用用以處理串口的數據發送.

中斷髮生後,調用的過程是這樣的:中斷髮生後,m_hISTEvent事件觸發,IST線程ThreadRun獲取中斷類型調用NotifyPDDInterrupt(cserpdd.c)通知PDD,NotifyPDDInterrupt會調用MDD層中的SerialEventHandler(mdd.c),該函數會根據不同的狀態調用相應的事件處理程序,如發送數據處理XmitInterruptHandler.
XmitInterruptHandler首先判斷是否有發送數據,如果沒有直接關閉中斷返回.如果有則判斷是否需要流控制,沒有流控制僅僅關閉中斷;如果需要流控制,則FIFO可寫字節數,將該數目的字節寫入UTXH(發送Buffer寄存器)中,寫滿後打開中斷返回.最後清除中斷標誌位.

12. XmitComChar
XmitComChar供驅動程序發送單個字符,主要是軟件流控制情況下的X-ON和X-OFF流控字符,以及應用程序以IOCTL_SERIAL_IMMEDIATE_CHAR爲操作碼調用COM_IOControl函數向串口發送立即字符.
如果FIFO not full,則向UTXH發送字符數據,否則允許發送中斷,等FIFO中數據發送完畢後在發送(等待m_XmitFlushDone事件).

13. EnableXmitInterrupt
EnableXmitInterrupt是暫時地關閉及重新開啓串口的發送中斷.

14. CancelXmit
CancelXmit取消串口的數據發送,直接調用InitXmit(TRUE)重新初始化,如reset fifo等.    

下一篇接着來看接收RX及MODEM,LINE,IR部分.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章