WINCE6.0+S3C6410下的DM9000A驱动
作者:LoongEmbedded(kandi)
時間:2011.05.26
類別:WINCE驅動開發
********************************LoongEmbedded************************
1.????? 原理圖設計
?
?
圖1
DM9000的總線是16位的,接在6410的Xm0的總線上。
DM9000 默認I/0 基地址為300H。CMD 引腳用于設置COMMAND 模式,CMD為高時,選擇數據端口。CMD為低時,選地址端口。數據端口和地址端口的地址碼由下式決定:
DM9000地址端口=高位片選地址+300H+0H
DM9000數據端口=高位片選地址+300H+4H
其中,高位片選地址由S3C6410的Bank1提供,即為:0x18000000 ,結合圖2和圖3可更深刻理解:
?
?
圖2
?
?
圖3
?
⑴DM9000 CMD引腳接至6410的Xm0的地址線ADDR2上,可以用來選擇發送的是地址還是數據。
⑵DM9000的IOR 和IOW接至6410的Xm0總線的讀寫引腳。
⑶DM9000的復位引腳接至6410的復位輸出,以保證CPU運行后再復位芯片。
⑷DM9000的EECS和EECK引腳可以選擇8位還是16位總線和高低電平觸發中斷。
⑸DM9000的中斷引腳接至CPU的EINT7引腳,高電平觸發中斷。
?
2.????? DM9000A介紹
2.1?? DM9000A
DM9000A具有一個通用的微處理器接口,內部集成了16kB SRAM(其中13kB用作接收緩沖區,3kB作為發送緩沖區),對內部存儲器訪問支持8位和16位數據接口以適用于不同的微處理器;內部集成了一個 10/100M自適應PHY,可以連接到3類、4類、5類的10M無屏蔽雙絞線和5類的100M無屏蔽雙絞線。
?
DM9000A體積小,只有48個引腳,有利于縮小PCB面積;它完全支持IEEE802.3u規格,還支持IEEE802.3x全雙工流控制。該電路還集成了EEPROM接口,自舉時通過EEPROM接口接入到芯片中,從而實現自動初始化DM9000A功耗非常低。DM9000A單電源3.3V工作,內置 3.3V變2.5V電源電路,I/O端口支持3.3V到5V的容差
?
2.2?? DM9000A的工作原理
?
2.2.1???????? DM9000A的總線
總線是ISA總線兼容模式,8個IO基址,分別是300H, 310H,320H, 330H, 340H, 350H, 360H, 370H。IO基址與設定引腳或內部EEPROM的共同選定
?
在DM9000A中只有INDEX端口與DATA端口兩個寄存器可以直接被CPU直接訪問,其它所有內部控制和狀態寄存器都是通過這兩個端口寄存器間接訪問的。網絡控制器CMD引腳決定了處理器訪問的是哪個端口寄存器:當CMD=0時,主機訪問的是INDEX端口寄存器;當CMD=1時,訪問的是DATA端口寄存器。設計中將CMD引腳與處理器的地址線Xm0ADDR2相連,則DM9000A的2個外部接口端口地址分別為:
?
INDEX端口地址=IOaddress+0x00,注意這里的0x00不是指網絡控制寄存器(NCR)。
DATA端口地址=IOaddress+0x04,這里的0x04不是指幀II的TX狀態寄存器。
?
實際中INDEX端口寄存器保存的是訪問DATA端口寄存器的內部寄存器(比如網絡狀態寄存器)的地址(01H),因此對DM9000A控制或者狀態寄存器訪問的命令順序是:
1)????? 寫要訪問寄存器的地址到INDEX端口。
2)????? 通過DATA端口來讀/寫數據(這里是要訪問寄存器的值)。
至于中間的動作時由DM9000A的DMA來完成的。
?
?
2.2.2???????? DM9000A的SRAM
DM9000A內置了16KB的SRAM用來作為首發數據的緩沖區,其中從0x000到0x0BFF工3KB用于發送數據緩沖區,此緩沖區可以同時保存2個完整的以太幀,在DM9000A的設計中將發送緩沖區看作2個獨立的發送緩沖區,分別用來保存幀I和幀II;從地址0x0C00到0x3FFF的13KB的空間作為數據接收緩沖區,它是一個環形結構。
?
2.2.3???????? DM9000A的DMA控制(Direct Memory Access Control)
DM9000提供DMA(直接存取技術)來簡化對內部存儲器的訪問。在對內部存儲器起始地址完成編程后,然后發出偽讀寫命令就可以加載當期數據到內部數據緩沖區,可以通過讀寫命令寄存器來定位內部存儲區地址。根據當前總線模式的字長使存儲地址自動加1,下一個地址數據將會自動加載到內部數據緩沖區。要注意的是在連續突發式的第一次訪問(偽讀寫命令命令)的數據應該被忽略,因為此數據是上一個讀寫命令獲取的值。
?
內部存儲器空間大小是16K字節。低3K字節單元用作發送包的緩沖區,其他13K字節用作接收包的緩沖區。所以在寫內存緩沖區操作的時候,如果中斷屏蔽寄存器(IMR,FFH)的第七位被置1(使能SRAM讀/寫指針在超過SRAM大小的時候可以自動返回到開始地址),當SRAM寫地址超過SRAM的大小的時候,自動跳回0地址(為什么是0呢?因為地址0x0000到0x0BFF是作為數據發送緩沖區的)。同樣在讀接收數據緩沖區的時候,當SRAM寫地址超過SRAM的大小的時候,自動跳回0x0C00地址(為什么是0x0C00呢?因為地址0x0C00到0x3FFF是作為數據發送緩沖區的)。
?
2.2.4???????? 9000A的初始化
?
為了啟動網絡控制器DM9000A,并使之處于接收和發送就緒狀態,必須對其進行初始化。DM9000A的初始化主要是設置一些關鍵的寄存器,見圖20的代碼處理,具體流程如下:
1)????? 激活PHY
設置GPR(1FH)的 bit[0]=0,復位后,DM9000A恢復默認的休眠狀態,以降低功耗,因此需要首先喚醒PHY。
2)????? 進行兩次軟復位,具體步驟如下
設置NCR(REG_00)bit[2:0]=011,至少保持20μs;
清除NCR(REG_00)bit[2:0]=000;
設置NCR(REG_00)bit[2:0]=011,至少保持20μs;
清除NCR(REG_00)bit[2:0]=000;
3)????? 配置NCR寄存器
設置NCR(00h)的bit[2:1]=00;配置為正常模式,通過改變該寄存器可以選擇設置內部或者外部PHY、全雙工或者半雙工模式、使能喚醒事件等網絡操作。
4)????? 清除發送狀態
設置NSR(01h) bit[3]=1 bit[2]=1。
5)????? 設置中斷屏蔽寄存器IMR的Bit[7](PAR位)為1,使能RX/TX緩沖區的
存讀/寫地址指針的自動返回功能。
?
6)????? 設置中斷屏蔽寄存器IMR的Bit[0]/Bit[1],使能發送和接收中斷。如果需
要在一個數據幀發送完成后產生一個中斷,就應該將bit[1]=1;如果需要在接收到一幀新數據時產生一個中斷,就應該將bit[0]=1。
?
7)????? 設置接收控制寄存器RCR的Bit[0](RXEN)為1,使能接收功能.
完成上述初始化后,網絡控制器就可以正常啟動和收發數據包了。
?
?
2.2.5???????? DM9000A的發送
?
DM9000A中的發送緩沖區可以同時存儲兩幀數據,依次命名為幀index I和幀index II。TX控制寄存器(02H)控制CRC校驗碼和PAD的插入,這兩個幀發送的狀態分別保存在幀index I發送狀態寄存器(03H)和幀index II發送狀態寄存器(04H)
?
在軟件或者硬件復位后,發送的起始地址是0x00h和當前是幀index II。首先CPU通過寫MWCMD命令來告訴DM9000A有數據發送(CPU有數據發送給DM9000A),這時DM9000A的DMA就把CPU通過SD數據線發送過來的數據發送到TX SRAM中(先寫入6個字節的目的MAC地址,再寫入6字節的源MAC地址,最后再寫入發送的數據),然后寫要發送的數據的長度到TX幀長度寄存器FCH和FDH中,如果數據長度是16位,將高8位寫入寄存器FCH,低8位寫入寄存器FDH中。隨后,CPU通過寫TX狀態寄存器(TXCR,02h)的第0位為1來請求DM9000A發送index I幀,DM9000A會自動做一些處理才將數據發往以太網,這包括:插入報頭和幀起始分隔符;插入來自上層協議的數據,如果數據量小于64字節,則自動補齊64字節;根據目標地址、源地址、長度/類型和數據產牛CRC校驗序列,并插入校驗序列位。這些處理都無需CPU干預。處理完畢后,這樣DM9000A就會發index I數據幀。在index I幀發送完成之前,index II幀會寫入到發送緩沖區。在index I幀發送完成后,將index II幀的數據長度寫到TX幀長度寄存器FCH和FDH中,并且寫TX狀態寄存器(TXCR,02h)的第0位為1來請求DM900A發送index II幀,這樣就可以發送index II幀。依此類推,下面發送的幀將會繼續是index I幀、index II幀、index I幀、index II幀……按照同樣的方式發送。
?
如果CPU將中斷屏蔽寄存器 IMR(FFH)的bit[1]置為高電平(這個動作在DeviceEnableInterrupt函數設置),那么發送完畢后,DM9000A將會產生一個指示發送完成的中斷信號。在發送過程中,CPU可以查詢寄存器標志位寄存器NSR(01h)中的TX1END bit[2]或者TX2END bit[3],若為1表示對應的幀發送完成(圖28有代碼說明),得到數據幀的發送狀態,通過對這兩個發送緩存區進行如此輪流操作,不僅可以避免在單一發送緩沖區模式下向發送緩存區寫入數據包時容易產生覆蓋了上一次沒有發送完的數據的錯誤操作,也不必等待上次數據發完后再向發送緩存區寫入當前的數據,從而有效的避免了處理器的等待時間,提高數據發送的效率和速度。
??? 發送流程,寄存器ISR中的PTS標志位是發送中斷標志位,當一幀數據發送完畢,PTS=0,CPU檢測到該標志后,應清除標志位以便發送新的數據幀。這里需要注意的是,向FC、FD所寫的幀長度應該包含目的MAC地址段、源MAC地址段和有效數據的總長度。
?
發送流程的總結:
當處理器要向以太網發送數據幀時,先將數據打包成UDP或IP數據包,并通過8位或16位總線逐字節發送到DM9000A的數據發送緩存中,然后將數據長度等信息填充到DM9000A的相應寄存器內,隨后發送使能命令,DM9000A將緩存的數據和數據幀信息進行MAC組幀,并發送出去。
?
?
2.2.6???????? DM9000A的接收
?
DM9000A的接收緩存區是一個環形結構,初始化后的起始地址為0C00H,每幀數據都有4字節長的首部,然后是有效數據和CRC校驗序列。首部4字節依次是01H、狀態、長度低字節和長度高字節。 首部4字節含義如下:
??? 第一個字節用來檢測接收緩存區中是否有數據,如果這個字節是01H,表明接收到了數據;如果為00H,則說明沒有數據。但是,如果第一個字節既不是01H,也不是00H,DM9000A就必須作一次軟復位來從這種異常狀態中恢復。
??? 第二個字節存儲著以太網幀狀態,由此可判斷所接收幀是否正確。
??? 第三和第四字節存儲著以太網幀長度。后續的字節就是有效數據。
接收過程如下:
查看中斷狀態寄存器,如果接收到新數據,寄存器ISR的PR位將被置為0;如果檢測到PR=0,清除PR,CPU開始讀接收緩存區數據。如過第一字節是01H,說明有數據,00H說明無數據,否則要進行復位; 根據獲取的長度信息,判斷是否讀完一幀,如果讀完,接著讀下一幀,直到遇到首字節是00H的幀,說明接收數據已讀完。CPU可重新查看中斷狀態寄存器,等待新的有效數據幀。在接收過程中,DM9000A將收到的數據幀經過解碼、去幀頭和地址檢驗等步驟后緩存在接收數據緩沖區中(這些是DMA9000A完成的,不需要CPU參與),接著在C_DM9000::DeviceInterruptEventHandler()函數->C_DM9000::Dm9LookupRxBuffers函數來讀取接收緩沖區的數據包。
?
?
3.????? WINCE下DM9000AEP驅動的實現
3.1?? WINCE下網絡驅動的架構
?
?
圖4????
??
?????????????????????????????????????
?圖5
NDIS:
?
?
WinSock應用層:
最上層的WinSock是提供給應用層的API接口,一般開發網絡應用都會用WinSock接口來開發。
?
協議驅動層:
協議驅動層執行具體的網絡協議,如TCP/IP、IrDA等、協議驅動層為應用層客戶程序提供服務,接收來自網卡或中間驅動程序的信息。
?
?
圖6
NDIS接口
在WINCE系統中式以ndis.dll的形式存在的,NDIS也是一組API,也是一個庫ndis.lib,網絡底層驅動需要靜態連接ndis.lib來使用它的函數。協議驅動層通過調用NDIS封裝層的接口函數,實現與底層硬件驅動的交互。對于協議層來說,NDIS相當于一個Miniport Driver,而對于底層的硬件驅動來說,NDIS相當于上層的協議層,所以NDIS起到承上啟下的作用,也起到對底層硬件接口的規范作用。
?
?
Miniportq驅動層
也就是Miniport Driver,實際的網卡驅動就是指Miniport Driver,它向上為NDIS提供了
Miniport相關的接口函數,向下則通過NDIS的接口來訪問硬件網卡。Miniport driver導出的這些接口函數會在系統注冊一個Miniport Driver的時候與NDIS封裝層的接口函數對接,這樣內核協議層通過調用NDIS的接口就可以訪問頂層硬件了。
?
?
圖7
?
3.2?? Miniport Driver導出的函數接口
如圖4和圖5所示,在協議層看來,它調用NDIS接口函數訪問網絡設備,具體的實現過程是通過調用底層的Miniport Driver接口函數來實現的。在WINCE系統中NDIS接口函數庫是微軟開發好的,所以開發WINCE下的網卡驅動就是編寫Miniport driver,它向上導出函數接口與NDIS接口實現對接,向下直接管理網卡硬件,為了后面更好去理解一些函數,下面貼出DM9000A的驅動的注冊表信息
?
?
圖8
?
3.2.1???????? 入口函數DriverEntry
?
?
圖9
DriverEntry的參數介紹如下:
⑴pDriverObject:指向一個由系統創建的驅動對象,這里pDriverObject是PDRIVER_OBJECT類型指針,此結構體在PUBLIC/COMMON/DDK/INC/ntcompat.h下定義
?
?
圖10
?
結合圖11,通過添加打印信息可知,pDriverObject->DriverName.Buffer=“DM9CE”和pDriverObject->RegistryPath.Buffer=“Comm/DM9CE”。
⑵pRegistryPath:指向注冊表中該驅動參數的路徑,此參數的結構類型在PUBLIC/COMMON/DDK/INC/Wdm.h下定義,如下:
?
?
圖11
過添加打印信息可知,pRegistryPath->Buffer=“Comm/DM9CE”。
?
DriverEntry函數主要有兩個任務:
⑴調用NdisMInitializeWrapper函數來通知ndis.lib要注冊一個miniport,這樣NDIS就創建一個來跟蹤miniport driver的狀態并且返回一個句柄hwrapper。因為在隨后調用NdisXXX函數和初始化函數時會用到這個句柄,所以Miniport driver會保存這個句柄。
?
⑵填充NDIS40_MINIPORT_CHARACTERISTICS結構體類型變量ndischar的成員變量,然后調用NdisMRegisterMiniport函數來注冊miniport,而調用NdisMRegisterMiniport函數并且在DriverEntry函數結束后會緊接調用MiniportInitialize函數。
?
3.2.2???????? 網絡設備的初始化接口函數MiniportInitialize
?
參數描述:
⑴OpenErrorStatus:如果MiniportInitialize函數返回NDIS_STATUS_OPEN_ERROR,MiniportInitialize函數會設置一個指示錯誤的額外信息的變量的值為NDIS_STATUS_XXX,而此參數就是指向于這個變量的指針。
?
⑵ SelectedMediumIndex:被選中的媒介類型的索引號,以太網一般是NdisMedium802_3。
⑶ MediumArray:媒介類型數組,包含了不同類型的網絡媒介
⑷ MediumArraySize:媒介類型數組大小
⑸ MiniportAdapterHandle:Miniport適配器句柄,該參數要被保存,以后調用Ndisxxx函數時會被用到。
⑹ WrapperConfigurationContext:一個封裝配置句柄,會被NdisOpenConfiguration函數用到。
函數體如下:
?
?
圖12
⑴ NIC_DRIVER_OBJECT::EDriverInitialize函數
看此函數體的第一部分:
?
?
圖13
下面先來看DeviceRetriveConfigurations的函數體
?
?
圖14
繼續看NIC_DRIVER_OBJECT::EDriverInitialize函數,第二部分函數體如下:
?
?
圖15
?
1) C_DM9000::EDeviceRegisterIoSpace函數
?
?
圖16
在此也學習一個很重要的函數C_DM9000::DeviceReadPort
??
圖17
假如我們要讀取0x2A寄存器的值,需要經過下面的動作才能完成
①調用NdisRawWritePortUchar函數來把0x2A的值寫入到總線0x18800300+00地址處。
②Xm0總線拉低Xm0WEn引腳來向DM9000A發出寫命令的動作,這樣0x2A會寫到DM9000A的內部存儲器起始地址處(00h,也就是相當于填寫了DMA的源地址),通過寫命令寄存器,DMA把0x2A寄存器的值復制到內部數據緩沖區中。
③調用NdisRawReadPortUchar函數來從總線地址0x18800300+04地址處讀取數據。
④調用NdisRawReadPortUchar函數后,Xm0總線拉低Xm0OEn引腳來向DM9000A發出讀命令的動作,通過讀命令寄存器,DMA把內部數據緩沖區的數據拷貝到DM9000數據端口地址0x18800300+04處,這樣NdisRawReadPortUchar函數就可以獲取到0x2A寄存器的值了。
?
補充一點,根據下圖我們可以更深刻理解ndis.lib提供的函數和miniport driver導出的函數接口的調用關系
?
?
圖18
?
2)NIC_DEVICE_OBJECT::EDeviceLoadEeprom函數
?
?
圖19
上圖計算出來DIM(m_szEeprom)/sizeof(EEPROM_DATA_TYPE)=128/2=64,在此不明白為什么需要讀取64次。
?
3) C_DM9000::EDeviceInitialize函數
先看此函數的第一部分函數體:
?
?
圖20
接著看第二部分
?
?
圖21
4) NIC_DEVICE_OBJECT::EDeviceRegisterInterrupt函數
?
?
圖22
5) C_DM9000::DeviceOnSetupFilter函數
先看此函數體的第一部分
?
?
圖23
接著看此函數體的第二部分
?
?
圖24
?
⑵NIC_DRIVER_OBJECT::DriverStart函數
此函數主要是通過調用C_DM9000::DeviceStart函數來實現的,下面就來看這個函數
?
?
圖25
?
3.2.3???????? MiniportISRHandler函數
該函數為網卡的ISR函數,該函數中應做盡可能少的工作,大部分工作應該交給MiniportHandleInterrupt函數來完成。
InterruptRecognized:中斷確認。如果確實是一個網卡中斷,返回TURE。
QueueMiniportHandleInterrupt:如果需要MiniportHandleInterrupt函數處理,返回TRUE。
MiniportAdapterContext:一個指向網卡結構的句柄,該網卡結構在MiniportInitialize函數中被創建。
此函數會調用C_DM9000::DeviceIsr函數來實現
?
?
圖26
?
3.2.4???????? MiniportInterruptHandler函數
該函數調用NIC_DRIVER_OBJECT::DriverInterruptHandler()->C_DM9000::DeviceInterruptEventHandler()函數,下面就來看最底層的函數
?
?
圖27
下面來學習C_DM9000::Dm9LookupRxBuffers函數
先看該函數體第一部分:
?
?
圖28
看第二部分:
?
?
圖29
該函數如果接收過程發現出錯,例如CRC出錯,將會丟掉當前的包并且對出錯包的數量進行計數并且在最后接收完成后往上層報告。
?
3.2.5???????? MiniportQueryInformation函數
該函數用于查詢網卡信息,返回網卡狀態等信息。
?
3.2.6???????? MiniportSetInformation函數
該函數用于設置網卡的信息。
?
3.2.7???????? MiniportReset函數
對DM9000A復位,該函數主要通過調用C_DM9000::DeviceReset函數和C_DM9000::DeviceStart函數來實現,其中C_DM9000::DeviceStart函數見圖26,下面就來學習C_DM9000::DeviceReset函數。
?
?
圖30
?
3.2.8???????? MiniportCheckForHang函數
該函數檢查硬件網卡的狀態,該函數為可選的,可以不去實現。該函數的調用流程:MiniportCheckForHang()->NIC_DRIVER_OBJECT::DriverCheckForHang()->
NIC_DEVICE_OBJECT::DeviceCheckForHang()下面來看DeviceCheckForHang函數體:
?
?
圖31
Miniport確定網絡適配器沒有工作的狀態下,或者中間層驅動檢測到miniport
Driver沒有響應的情況下,該函數會返回TRUE。
?
DeviceCheckForHang函數中需要進一步描述的內容:
?
⑴???? C_DM9000::DeviceReadPhy函數
?
?
圖32
⑵???? 絡狀態寄存器link status位描述
?
?
圖33
?
⑶???? ?NIC_DEVICE_OBJECT::SetConnectionStatus函數
?
?
圖34
?
?
3.2.9???????? MiniportHalt函數
該函數用于停止網絡適配器(network adapter),如果驅動控制一個物理網絡適配器,必須釋放驅動為網絡適配器分配的所有資源,該函數調用關系:MiniportHalt()->NIC_DRIVER_OBJECT::DriverHalt(),本驅動中此函數什么都沒有做。
?
?
3.2.10?????? MiniportSend函數
?
該函數的調用關系:MiniportSend()->NIC_DRIVER_OBJECT::DriverSend()
?
?
圖35
下面介紹最后的發送函數C_DM9000::DeviceSend
?
?
圖36
?
4.????? DM9000A調試
4.1?? 沒有接入網線
上層驅動會每隔一段時間調用MiniportCheckForHang函數來判斷網絡線是否連接,見3.2.8的描述。
?
4.2?? 網線到DM9000A的對外接口RJ45,沒有用戶參與的任何動作
我根據串口輸出信息來說明處理流程,其中上層驅動會每隔一段時間調用ISR函數MiniportISRHandler來處理,存在的流程如下:
1)????? 接收到數據包
?
?
圖37
2)????? 沒有接收到數據包
見圖37中間的注釋部分
3)????? 發送數據包
?
?
圖38
是檢測到發送數據包中斷,在調用MiniportISRHandler函數之前會先調用MiniportSend函數,因為就是上層的NDIS調用MiniportSend函數之后才會產生發送數據包的中斷,這個動作會被MiniportISRHandler捕捉到,從而被MiniportInterruptHandler函數做具體的發送處理。當然也有TX包II發送的處理。
?
4.3?? 打開網頁應用程序,訪問網頁,比如http://192.168.1.10。
輸出串口信息如下:
?
?
圖39
?
?
?
?
總結
以上是生活随笔為你收集整理的WINCE6.0+S3C6410下的DM9000A驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WINCE6.0+S3C6410串口驱动
- 下一篇: USB OTG概述