網絡對於嵌入式系統來說必不可少。可是S3C2440沒有集成以太網接口,所以要想使S3C2440具備以太網的功能,就必須擴展網卡接口。我們使用的Mini2440就是外接DM9000EP,使其可以與以太網相連接。DM9000和DM9000EP主要是封裝不一樣,其他基本都是一樣的。
一、DM9000介紹
1.1 概述
DM9000是一款完全集成的、性價比高、引腳數少、帶有通用處理器接口的單芯片快速以太網MAC控制器。一個10/100M自適應的PHY和4K DWORD值的SRAM 。它是出於低功耗和高性能目的的設計,其IO端口支持3.3V與5V容限值。
DM9000提供了MII接口,來連接所有提供支持MII接口功能的HPNA網絡設備或其他收發器。
此外DM9000支持8位, 16位和32位接口訪問內部存儲器,以支持不同的處理器。
DM9000物理協議層接口完全支持使用10MBps下3類、4類、5類非屏蔽雙絞線和100MBps下5類非屏蔽雙絞線。這是完全符合IEEE 802.3u規格。它的自動協調功能將自動完成配置以最大限度地適合其線路帶寬。還支持IEEE 802.3x全雙工流量控制。
DM9000具有以下特性:
- 100引腳LQFP封裝;
- 支持處理器接口:I/O口的字節或字命令對內部存儲器進行讀寫操作(比如外接S3C2440);
- 集成自適應10/100M收發器(PHYceiver)
- 支持MII接口(支持外接支持MII接口的收發器)
- 支持背壓模式半雙工流量控制模式
- IEEE802.3x全雙工模式的流量控制
- 支持4個通用輸入輸出口
- 集成4K雙字SRAM
- 支持自動加載EEPROM里面生產商ID和產品ID
1.2 模塊圖
工作實質就是MAC通過MII控制PHY的過程。
這張圖的左側是一個收發器,有TX、RX引腳,類似於我們的串口,不難想象,這里最終是和網線連接的,用來接收和發送數據。
而右側是處理器接口,當然是可以用來連接S3C2440處理器的,處理器可以直接對SRAM讀取和寫入,從而控制數據的接收和發送。
1.3 網卡和網絡模型的映射關系
MAC對應的是數據鏈路層,PHY對應的是物理層。
1.4 MAC的工作原理
當網絡協議棧的IP包送到網卡的時候,先要到達MAC,MAC就根據數據鏈路層的協議對接收到的數據進行封裝,將IP包封裝成以太網包,完成數據幀的構建。當然它還具備數據糾錯以及傳送控制等功能。
1.5 關於PHY
PHY是物理接口收發器,主要和實際的傳輸硬件打交道。它接收到來自MAC的以太網包,先加上校檢碼。然后按照物理層的規則進行數據編碼,然后傳輸到物理介質,接受過程則與之相反。
1.6 Mini2440硬件接線
DM9000與S3C2440接線關系:
- SD0~SD15:16位地址、數據線,由CMD引腳決定訪問類型,連接S3C2440的LDDATA0~LDATA15;
- CMD:命令線,當CMD為高表示傳輸的是數據,CMD為低表示傳輸的是地址,連接S3C2440的LADDR2(PC16);
- INT:中斷引腳,連接S3C2440的EINT7(GPF7);
- IOR#:讀引腳,連接S3C2440的nOE(GPC5);
- IOW#:寫引腳,連接S3C2440的nWE(GPE6);
- AEN:片選,連接S3C2440的bank4的片選引腳LnGCS4(GPA15);
我們可以把網卡設備看做16位ROM存儲器,S3C2440內存訪問引腳與DM9000引腳相連:
1.6.1 DM9000和HR911103A之間只有6根接線
DM9000 | HR911103A |
TXO+ | TX+ |
TXO- | TX- |
RXI+ | RX+ |
RXI- | RX- |
SPEED#、WACKUP、LINK_O(只焊接了SPEED) | NETLINK |
LINK_ACT# | NETACT |
一般來說網卡都有兩個LED指示燈、一個亮綠燈、一個亮橙燈;
- 綠燈:代表連接指示燈LINK ,也就是電路原理圖中NETLINK所連接的YLEDK;連接指示燈亮,表示網卡與網絡連接狀況良好;
- 橙燈:代表信號傳輸指示燈ACT,也就是電路原理圖中NETACT所連接的GLEDK;信號傳輸指示燈閃爍表示網卡正在進行數據傳輸,同時燈的閃爍頻率隨數據傳輸的大小而變化 , 通信量大的閃爍頻率快 ;
燈不亮原因:
- 線路問題 :網線沒插好,網線老化,水晶頭接觸不良,信號干擾等線路問題都可能引起網絡連接信號中斷或不能定 , 導致網卡燈不亮 ;
- 網卡驅動程序:沒有正常安裝驅動網卡導致沒法工作 ,當然網卡燈就不亮了,這也是常見的網卡故障;
HR911103A是網絡插座變壓器,使用RJ45接口,外接RJ4水晶頭,也就是我們的網線。
1.6.2 DM9000 10/100M 物理層與光纖接口
24 |
SD |
I |
光纖信號檢測 PECL電平信號,顯示光纖接收是否有效 |
25 |
DGGND | P |
帶隙地信號線 |
26 |
BGRES | I/O |
帶隙引腳 |
27 |
AVDD |
P |
帶隙與電源保護環 |
28 | AVDD | P | 接收端口電源 |
29 |
RXI+ | I |
物理層接收端的正極 |
30 |
RXI- | I |
物理層接收端的負極 |
31 |
AGND |
P |
接收端口地 |
32 |
AGND |
P |
發送端口地 |
33 |
TXO+ |
O |
物理層發送端口正極 |
34 |
TXO- |
O |
物理層發送端口負極 |
35 |
AVDD |
P |
發送端口電源 |
1.6.3 DM9000 LED引腳
60 |
SPEED# | O |
低電平指示100M帶寬指示,高電平指示10M帶寬 |
61 |
DUP# | O | 全雙工指示LED LED模式0時,低電平顯示工作在10M帶寬,或在100M帶寬浮動 |
62 |
LINK_ACT# | O |
連接LED,在模式0時,只作物理層的載波監聽檢測連接狀態 |
1.7 DM9000引腳介紹(使用的引腳標紅)
I=輸入 O=輸出 I/O=輸入/輸出 O/D=漏極開路 P=電源 LI=復位鎖存輸入 #=普遍低電位。
1.7.1 MII接口相關引腳(未使用)
引腳號 |
引腳名 |
I/O |
功能描述 |
37 |
LINK_I |
I |
外部MII接口器件連接狀態 |
38、39、40、41 |
RXD [3:0] |
I |
外部MII接口接收數據 4位 半字節輸入(同步於接收時鍾) |
43 |
CRS |
I/O |
外部MII接口的載波檢測 |
44 |
COL |
I/O |
外部MII接口的沖突檢測,輸出到外部設備 |
45 |
RX_DV |
I |
外部MII接口數據有效信號 |
46 |
RX_ER |
I |
外部MII接口接收錯誤 |
47 |
RX_CLK |
I |
外部MII接口接收時鍾 |
49 |
TX_CLK |
I/O |
外部MII接口發送時鍾 |
50~53 |
TXD[3:0] |
O |
外部MII接口發送數據低4位輸出 TXD[2:0]決定內部存儲空間基址:TXD [2:0]) * 10H + 300H |
54 | TX_EN | I/O | 外部MII傳輸使能 |
56 |
MDIO |
I/O |
外部MII接口串行數據通信 |
57 |
MDC |
O |
外部MII串行數據通信口時鍾,且與中斷引腳有關 該引腳高電平時候,中斷引腳低電平有效;否則高有效 |
注意:以上介質無關端口都內部自帶60K 歐姆的下拉電阻。
1.7.2 處理器接口相關引腳(使用)
1 |
IOR# |
I |
處理器讀命令 低電平有效,極性能夠被EEPROM修改,詳細請參考對EEPROM內容的描述 |
2 |
IOW# |
I |
處理器寫命令 低電平有效,同樣能修改極性 |
3 |
AEN# |
I |
芯片選擇,低電平有效 |
4 |
IOWAIT |
O |
處理器命令就緒 當上一指令沒有結束,該引腳電平拉低表示當前指令需要等待 |
14 |
RST |
I |
硬件復位信號,高電平有效復位 |
6~13 82~89 |
SD0~15 |
I/O |
0~15位的數據地址復用總線,由CMD引腳決定當期訪問類型 |
93~98 |
SA4~9 |
I |
地址線4~9;僅作芯片選擇信號 SA9、SA8高電平、SA7和AEN低電平、SA6~SA4搭配TXD2~0,則DM9000被選中 |
92 |
CMD |
I |
訪問類型 高電平是訪問數據端口;低電平是訪問地址端口 |
91 |
IO16 |
O |
字命令標志,默認低電平有效 當訪問外部數據存儲器是字或雙字寬度時,被置位 |
100 |
INT |
O |
中斷請求信號 高電平有效,極性能修改 |
37~53 56 |
SD31~16 |
I/O |
雙字模式,高16位數據引腳 |
57 |
IO32 |
O |
雙字命令標志,默認低電平有效 |
注意:以上引腳除去SD8,SD9和IO16,都內部自帶60K 歐姆的下拉電阻
1.7.3 電源引腳(使用)
5,20,36,55, 72,90,73 |
DVDD |
P |
數字電源 |
15,23,42,58 63,81,99,76 |
DGND | P |
數字地 |
1.7.4 時鍾引腳(使用)
21 |
X2_25M |
O |
25M晶振輸出 |
22 |
X1_25M |
I |
25M晶振輸入 |
59 |
CLK20MO |
O |
20M晶振再生輸出給外部MII設備,自帶60K歐姆下拉電阻 |
1.7.5 各種其他功能引腳
16~19 |
TEST1~4 |
I |
工作模式 Test1~4(1,1,0,0)正常工作狀態 |
48 |
TEST5 |
I |
必須接地 |
68~69 |
GPIO0~3 |
I/O |
通用I/O端口 通用端口控制寄存器和通用端口寄存器能編程該系列引腳 GPIO0默認輸出為高來關閉物理層和其他外部介質無關器件 GPIO1~3默認為輸入引腳 |
78 |
LINK_O |
O |
電纜連接狀態顯示輸出,高電平有效 |
79 |
WAKEUP |
O |
流出一個喚醒信號當喚醒事件發生 內置60K歐姆的下拉電阻 |
80 |
PW_RST# |
I |
上電復位 低電平激活DM9000的重新初始化,5us后初始化當該引腳測試到電平變化 |
74,75,77 |
NC |
無用 |
二、DM9000 寄存器
DM9000包含一系列可被訪問的控制狀態寄存器,這些寄存器是字節對齊的,他們在硬件或軟件復位時被設置成初始值。以下為DM9000的寄存器功能詳解。
2.1 NCR (00H):網絡控制寄存器(Network Control Register )
位 | 名稱 | 描述 | 默認值 |
7 | EXT_PHY | 選擇外部PHY,0選擇內部PHY,不受軟件復位影響 | 0 RW |
6 | WAKEEN | 事件喚醒使能,1使能,0禁止並清除事件喚醒狀態,不受軟件復位影響 | 0 RW |
5 | 保留 | 保留 | 0 RO |
4 | FCOL | 強制沖突模式,用於用戶測試 | 0 RW |
3 | FDX | 全雙工模式。內部PHY模式下只讀,外部PHY下可讀寫 | 0 RW |
2-1 | LBK | 回環模式(Loopback) 00通常 01MAC內部回環 10內部PHY 100M模式數字回環 11保留 |
00 RW |
0 | RST | 軟件復位,10us后自動清零 | 0 RW |
2.2 NSR (01H):網絡狀態寄存器(Network Status Register )
位 | 名稱 | 默認值 | 描述 |
7 | SPEED | 0 RO | 媒介速度,在內部PHY模式下,0為100Mbps,1為10Mbps。當LINKST=0時,此位不用. |
6 | LINKST | 0 RO | 連接狀態,在內部PHY模式下,0為連接失敗,1為已連接 |
5 | WAKEST | 0 RW/C1 | 喚醒事件狀態。讀取或寫1將清零該位。不受軟件復位影響 |
4 | 保留 | 0 RO | 保留 |
3 | TX2END | 0 RW/C1 | TX(發送)數據包2完成標志,讀取或寫1將清零該位。數據包指針2傳輸完成 |
2 | TX1END | 0 RW/C1 | TX(發送)數據包1完成標志,讀取或寫1將清零該位。數據包指針1傳輸完成 |
1 | RXOV | 0 RO | RX(接收)FIFO(先進先出緩存)溢出標志 |
0 | 保留 | 0 RO | 保留 |
位3:2寫1清除數據包發送完標志位。
2.3 TCR(02H):發送控制寄存器(TX Control Register)
位 | 名稱 | 默認值 | 描述 |
7 | 保留 | 0 RO | 保留 |
6 | TJDIS | 0 RW | Jabber傳輸使能。1禁止Jabber傳輸定時器(2048字節),0使能 |
5 | EXCECM | 0 RW | 額外沖突模式控制。0當額外的沖突計數多於15則終止本次數據包,1始終嘗試發發送本次數據包 |
4 | PAD_DIS2 | 0 RW | 禁止為數據包指針2添加PAD |
3 | CRC_DIS2 | 0 RW | 禁止為數據包指針2添加CRC校驗 |
2 | PAD_DIS2 | 0 RW | 禁止為數據包指針1添加PAD |
1 | CRC_DIS2 | 0 Rw | 禁止為數據包指針1添加CRC校驗 |
0 | TXREQ | 0 Rw | TX(發送)請求。發送完成后自動清零該位 |
2.4 TSR_I(03H):數據包指針1的發送狀態寄存器1(TX Status Register I)
位 | 名稱 | 默認值 | 描述 |
7 | TJTO | 0 RO | Jabber傳輸超時。該位置位表示由於多於2048字節數據被傳輸而導致數據幀被截掉 |
6 | LC | 0 RO | 載波信號丟失。該位置位表示在幀傳輸時發生紅載波信號丟失。在內部回環模式下該位無效 |
5 | NC | 0 RO | 無載波信號。該位置位表示在幀傳輸時無載波信號。在內部回環模式下該位無效 |
4 | LC | 0 RO | 沖突延遲。該位置位表示在64字節的沖突窗口后又發生沖突 |
3 | COL | 0 RO | 數據包沖突。該位置位表示傳輸過程中發生沖突 |
2 | EC | 0 RO | 額外沖突。該位置位表示由於發生了第16次沖突(即額外沖突)后,傳送被終止 |
1-0 | 保留 | 0 RO | 保留 |
2.5 TSR_II(04H):數據包指針2的發送狀態寄存器2(TX Status Register II)
位 | 名稱 | 默認值 | 描述 |
7 | TJTO | 0 RO | Jabber傳輸超時。該位置位表示由於多於2048字節數據被傳輸而導致數據幀被截掉 |
6 | LC | 0 RO | 載波信號丟失。該位置位表示在幀傳輸時發生紅載波信號丟失。在內部回環模式下該位無效 |
5 | NC | 0 RO | 無載波信號。該位置位表示在幀傳輸時無載波信號。在內部回環模式下該位無效 |
4 | LC | 0 RO | 沖突延遲。該位置位表示在64字節的沖突窗口后又發生沖突 |
3 | COL | 0 RO | 數據包沖突。該位置位表示傳輸過程中發生沖突 |
2 | EC | 0 RO | 額外沖突。該位置位表示由於發生了第16次沖突(即額外沖突)后,傳送被終止 |
1-0 | 保留 | 0 RO | 保留 |
2.6 RCR(05H):接收控制寄存器(RX Control Register )
位 | 名稱 | 默認值 | 描述 |
7 | 保留 | 0 RO | 保留 |
6 | WTDIS | 0 RW | 看門狗定時器禁止。1禁止,0使能 |
5 | DIS_LONG | 0 RW | 丟棄長數據包。1為丟棄數據包長度超過1522字節的數據包 |
4 | DIS_CRC | 0 RW | 丟棄CRC校驗錯誤的數據包 |
3 | ALL | 0 RW | 忽略所有多點傳送 |
2 | RUNT | 0 RW | 忽略不完整的數據包 |
1 | PRMSC | 0 Rw | 混雜模式(Promiscuous Mode) |
0 | RXEN | 0 Rw | 接收使能 |
2.7 RSR(06H):接收狀態寄存器(RX Status Register )
位 | 名稱 | 默認值 | 描述 |
7 | RF | 0 RO | 不完整數據幀。該位置位表示接收到小於64字節的幀 |
6 | MF | 0 RO | 多點傳送幀。該位置位表示接收到幀包含多點傳送地址 |
5 | LCS | 0 RO | 沖突延遲。該位置位表示在幀接收過程中發生沖突延遲 |
4 | RWTO | 0 RO | 接收看門狗定時溢出。該位置位表示接收到大於2048字節數據幀 |
3 | PLE | 0 RO | 物理層錯誤。該位置位表示在幀接收過程中發生物理層錯誤 |
2 | AE | 0 RO | 對齊錯誤(Alignment)。該位置位表示接收到的幀結尾處不是字節對齊,即不是以字節為邊界對齊 |
1 | CE | 0 RO | CRC校驗錯誤。該位置位表示接收到的幀CRC校驗錯誤 |
0 | FOE | 0 RO | 接收FIFO緩存溢出。該位置位表示在幀接收時發生FIFO溢出 |
2.8 ROCR(07H):接收溢出計數寄存器(Receive Overflow Counter Register)
位 | 名稱 | 默認值 | 描述 |
7 | RXFU | 0 R/C | 接收溢出計數器溢出。該位置位表示ROC(接收溢出計數器)發生溢出 |
6:0 | ROC | 0 R/C | 接收溢出計數器。該計數器為靜態計數器,指示FIFO溢出后,當前接收溢出包的個數 |
2.9 BPTR(08H):背壓門限寄存器(Back Pressure Threshold Register)
位 | 名稱 | 默認值 | 描述 |
7:4 | BPHW | 3H RW | 背壓門限最高值。 當接收SRAM空閑空間低於該門限值,則MAC將產生一個擁擠狀態。 默認值為3H,即3K字節空閑空間。不要超過SRAM大小 |
3:0 | JPT | 7H RW | 擁擠狀態時間。默認為200us。 0000 為5us 0001為10us 0010為15us 0011為25us 0100為50us 0101為100us 0110為150us 0111為 200us 1000為250us 1001為300us 1010為350us 1011為400us 1100為450us 1101為500us 1110為550us,1111為600us |
2.10 FCTR(09H):溢出控制門限寄存器(Flow Control Threshold Register)
位 | 名稱 | 默認值 | 描述 |
7:4 | HWOT | 3H RW | 接收FIFO緩存溢出門限最高值。 當接收SRAM空閑空間小於該門限值,則發送一個暫停時間(pause_time)為FFFFH的暫停包。 若該值為0,則無接收空閑空間。 默認值為3H,即3K字節空閑空間。不要超過SRAM大小 |
3:0 | LWOT | 8H RW | 接收FIFO緩存溢出門限最低值。 當接收SRAM空閑空間大於該門限值,則 發送一個暫停時間(pause_time)為0000H的暫停包。 當溢出門限最高值的暫停包發送之后,溢出門限最低值的暫停包才有效。 默認值為8K字節。 不要超過SRAM大小 |
2.11 RTFCR(0AH):接收/發送溢出控制寄存器(RX/TX Flow Control Register)
位 | 名稱 | 默認值 | 描述 |
7 | TXP0 | 0 RW | 發送暫停包。發送完成后自動清零,並設置TX暫停包時間為0000H |
6 | TXPF | 0 RW | 發送暫停包。發送完成后自動清零,並設置TX暫停包時間為FFFFH |
5 | TXPEN | 0 RW | 強制發送暫停包使能。按溢出門限最高值使能發送暫停包 |
4 | BKPA | 0 RW | 背壓模式。該模式僅在半雙工模式下有效。當接收SRAM超過BPHW並且接收新數據包時,產生一個擁擠狀態 |
3 | BKPM | 0 RW | 背壓模式。該模式僅在半雙工模式下有效。當接收SRAM超過BPHW並數據包DA匹配時,產生一個擁擠狀態 |
2 | RXPS | 0 R/C | 接收暫停包狀態。只讀清零允許 |
1 | RXPCS | 0 RO | 接收暫停包當前狀態 |
0 | FLCE | 0 RW | 溢出控制使能。1設置使能溢出控制模式 |
2.12 EPCR/PHY_CR(0BH):EEPROM和PHY控制寄存器(EEPROM & PHY Control Register)
位 | 名稱 | 默認值 | 描述 |
7:6 | 保留 | 0 RO | 保留 |
5 | REEP | 0 RW | 重新加載EEPROM。驅動程序需要在該操作完成后清零該位 |
4 | WEP | 0 RW | EEPROM寫使能 |
3 | EPOS | 0 RW | EEPROM或PHY操作選擇位。0選擇EEPROM,1選擇PHY |
2 | ERPRR | 0 RW | EEPROM讀,或PHY寄存器讀命令。驅動程序需要在該操作完成后清零該位 |
1 | ERPRW | 0 RW | EEPROM寫,或PHY寄存器寫命令。驅動程序需要在該操作完成后清零該位 |
0 | ERRE | 0 RO | EEPROM或PHY的訪問狀態。1表示EEPROM或PHY正在被訪問 |
2.13 EPAR/PHY_AR(0CH):EEPROM或PHY地址寄存器(EEPROM & PHY Address Register)
位 | 名稱 | 默認值 | 描述 |
7:6 | PHY_ADR | 01 RW | PHY地址的低兩位(bit1,bit0),而PHY地址的bit[4:2]強制為000。 如果要選擇內部PHY,那么此2位強制為01,實際應用中要強制為01 |
5:0 | EROA | 0 RW | EEPROM字地址或PHY寄存器地址 |
2.14 EPDRL/PHY_DRL(0DH):EEPROM或PHY數據寄存器低半字節(EEPROM & PHY Low Byte Data Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | EE_PHY_L | X RW | EEPROM或PHY低字節數據 |
2.15 EPDRL/PHY_DRH(0EH):EEPROM或PHY數據寄存器高半字節(EEPROM & PHY High Byte Data Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | EE_PHY_H | X RW | EEPROM或PHY高字節數據 |
2.16 WUCR(0FH):喚醒控制寄存器(Wake Up Control Register)
位 | 名稱 | 默認值 | 描述 |
7:6 | 保留 | 0 RO | 保留 |
5 | LINKEN | 0 RW | 使能“連接狀態改變”喚醒事件。該位不受軟件復位影響 |
4 | SAMPLEEN | 0 RW | 使能“Sample幀”喚醒事件。該位不受軟件復位影響 |
3 | MAGICEN | 0 RW | 使能“Magic Packet”喚醒事件。該位不受軟件復位影響 |
2 | LINKST | 0 RO | 表示發生了連接改變事件和連接狀態改變事件。該位不受軟件復位影響 |
1 | SAMPLEST | 0 RO | 表示接收到“Sample幀”和發生了“Sample幀”事件。該位不受軟件復位影響 |
0 | MAGICST | 0 RO | 表示接收到“Magic Packet”和發生了“Magic Packet”事件。該位不受軟件復位影響 |
2.17 PAR(10H -- 15H):物理地址(MAC)寄存器(Physical Address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | PAB5 | X RW | 物理地址字節5(15H) |
7:0 | PAB4 | X RW | 物理地址字節4(14H) |
7:0 | PAB3 | X RW | 物理地址字節3(13H) |
7:0 | PAB2 | X RW | 物理地址字節2(12H) |
7:0 | PAB1 | X RW | 物理地址字節1(11H) |
7:0 | PAB0 | X RW | 物理地址字節0(10H) |
用來保存6個字節的MAC地址。
2.18 MAR(16H -- 1DH):多點發送地址寄存器(Multicast Address Register )
位 | 名稱 | 默認值 | 描述 |
7:0 | MAR7 | X RW | 多點發送地址字節7(1DH) |
7:0 | MAR6 | X RW | 多點發送地址字節6(1CH) |
7:0 | MAR5 | X RW | 多點發送地址字節5(1BH) |
7:0 | MAR4 | X RW | 多點發送地址字節4(1AH) |
7:0 | MAR3 | X RW | 多點發送地址字節3(19H) |
7:0 | MAR2 | X RW | 多點發送地址字節2(18H) |
7:0 | MAR1 | X RW | 多點發送地址字節1(17H) |
7:0 | MAR0 | X RW | 多點發送地址字節0(16H) |
2.19 GPCR(1EH):GPIO控制寄存器(General Purpose Control Register)
位 | 名稱 | 默認值 | 描述 |
7:4 | 保留 | 0 RO | 保留 |
3:0 | GEP_CNTL | 0001 RW | GPIO控制。 定義GPIO的輸入輸出方向。1為輸出,0為輸入。 GPIO0默認為輸出做POWER_DOWN功能。其它默認為輸入。因此默認值為0001 |
2.20 GPR(1FH):GPIO寄存器(General Purpose Register)
位 | 名稱 | 默認值 | 描述 |
7:4 | 保留 | 0 RO | 保留 |
3:1 | GEPIO3-1 | 0 RW | GPIO為輸出時,相關位控制對應GPIO端口狀態; GPIO為輸入時,相關位反映對應GPIO端口狀態; |
0 | GEPIO0 | 1 RW | 功能同上。 該位默認為輸出1到POWER_DOWN內部PHY。 若希望啟用PHY,則驅動程序需要通過寫“0”將PWER_DOWN信號清零。 該位默認值可通過EEPROM編程得到。參考EEPROM相關描述 |
2.21 TRPAL(22H):發送SRAM讀指針地址寄存器(TX SRAM Read Pointer Address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | TRPAH | 00H RO | 發送SRAM讀指針地址低字節 |
2.22 TRPAH(23H):發送SRAM讀指針地址寄存器(TX SRAM Read Pointer Address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | TRPAL | 00H RO | 發送SRAM讀指針地址高字節 |
2.23 RWPAL(24H):接收SRAM寫指針地址寄存器(RX SRAM Write Pointer Address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | RWPAL | X04HRO | 接收SRAM寫指針地址低字節 |
2.24 RWPAH(25H):接收SRAM寫指針地址寄存器(RX SRAM Write Pointer Address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | RWPAH | OCH RO | 接收SRAM寫指針地址高字節 |
2.25 VID(28H -- 29H):生產廠家序列號寄存器(Vendor ID Register)
位 |
名稱 |
默認值 |
描述 |
7:0 |
VIDH |
0AH RO |
生產廠家序列號高字節(29H) |
7:0 |
VIDL |
46H RO |
生產廠家序列號低字節(28H) |
2.26 PID(2AH --2BH):產品序列號(Product ID Register)
位 |
名稱 |
默認值 |
描述 |
7:0 |
PIDH |
90H RO |
產品序列號高字節(2BH) |
7:0 |
PIDL |
00H RO |
產品序列號低字節(2AH) |
2.27 CHIPR(2CH):芯片修訂版本(CHIP Revision Register )
位 | 名稱 | 默認值 | 描述 |
7:0 | CHIPR | 00H R0 | 芯片修訂版本 |
2.28 SMCR(2FH):特殊模式控制寄存器(Special Mode Control Register)
位 |
名稱 |
默認值 |
描述 |
7 |
SM_EN |
0 RW |
特殊模式使能 |
6:3 |
保留 |
0 WO |
保留 |
2 |
FLC |
0 RW |
強制沖突延遲 |
1 | FB1 | 0 RW | 強制最長“Back-off”時間 |
0 | FB0 | 0 RW | 強制最短“Back-off”時間 |
2.29 MRCMDX(F0H):存儲器地址不變的讀數據命令寄存器(Memory Data Read Command Without Address Increment Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MRCMDX | X R0 | 從接收SRAM中讀數據,讀取之后,指向內部SRAM的讀指針不變 |
2.30 MRCMD(F2H):存儲器讀地址自動增加的讀數據命令寄存器(Memory Data Read Command With Address Increment Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MRCMD | X R0 | 從接收SRAM中讀數據,讀取之后,根據操作模式(8位、16位、32位)讀指針分別增加1,2,或4 |
2.31 MRRL(F4H~F5H):存儲器讀地址寄存器(Memory Data Read_ address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MDRAH | 00H R/W | 存儲器讀地址高位。 若IMR的bit7=1,則該寄存器設置為0CH(F5H) |
7:0 | MDRAL | 00H R/W | 存儲器讀地址低位(F4H) |
2.32 MWCMDX(F6H):存儲器讀地址不變的讀數據命令寄存器(Memory Data Write Command Without Address Increment Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MWCMDX | X WO | 寫數據到發送SRAM中,之后指向內部SRAM的寫地址指針不變 |
2.33 MWCMD(F8H):存儲器讀地址自動增加的讀數據命令寄存器(Memory Data Write Command With Address Increment Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MWCMD | X WO | 寫數據到發送SRAM中,之后指向內部SRAM的讀指針自動增加1、2或4,根據處理器的操作模式而定(8位、16位或32位) |
2.34 MWRL(FAH~FBH):存儲器寫地址寄存器(Memory Data Write_ address Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | MDRAM | 00H R/W | 存儲器寫地址高位(FBH) |
7:0 | MDRAL | 00H R/W | 存儲器寫地址低位(FAH) |
2.35 TXPLL(FCH~FDH):發送數據包長度寄存器(TX Packet Length Register)
位 | 名稱 | 默認值 | 描述 |
7:0 | TXPLH | X R/W | 發送數據包長度高字節(FDH) |
7:0 | TXPLL | X R/W | 發送數據包長度低字節(FCH) |
2.36 ISR(FEH):中斷狀態寄存器(Interrupt Status Register)
位 |
名稱 |
默認值 |
描述 |
7:6 |
IOMODE |
0 RO |
處理器模式。 00為16位模式 01為32位模式 10為8位模式 11保留 |
5:4 |
保留 |
0 RO |
保留 |
3 | ROOS | 0 RW/C1 | 接收溢出計數器溢出 |
2 | ROS | 0 RW/C1 | 接收溢出 |
1 | PTS | 0 RW/C1 | 數據包傳輸 |
0 | PRS | 0 RW/C1 | 數據包接收 |
ISR寄存器各狀態寫1清除中斷標志。
2.37 IMR(FFH):中斷屏蔽寄存器(Interrupt Mask Register)
位 |
名稱 |
默認值 |
描述 |
7 |
PAR |
0 RW |
使能指針自動跳回。當SRAM的讀、寫指針超過SRAM的大小時,指針自動跳回起始位置。 需要驅動程序設置該位,若設置則REG_F5(MDRAH)將自動位0CH |
6:4 |
保留 |
0 RO |
保留 |
3 | ROOM | 0 RW | 使能接收溢出計數器溢出中斷 0屏蔽 1使能 |
2 | ROM | 0 RW | 使能接收溢出中斷 0屏蔽 1使能 |
1 | PTM | 0 RW | 使能數據包傳輸中斷 0屏蔽 1使能 |
0 | PRM | 0 RW | 使能數據包接收中斷 0屏蔽 1使能 |
訪問以上寄存器的方法是通過總線驅動的方式,即通過對IOR、IOW、AEN、CMD以及SD0--SD15等相關引腳的操作來實現。
在DM9000中,還有一些介質無關接口MII寄存器,需要我們去訪問。這些寄存器是字對齊的,即16位寬。下這里就不具體介紹了。
三、DM9000初始化
3.1 DM9000基地址
在Mini2440的原理圖:
- DM9000引腳CMD連接在S3C2440的ADDR2口上;
- DM9000數據線SD0~SD15連接在S3C2440的LDATA0~LDATA15;
- DM9000片選線是nLAN_CS(AEN),低電平有效。片選線連接在S3C2440的nGCS4上;
我們查看S3C2440的內存空間分布:
可以看到nGCS4對應的片選信號是0x20000000開頭的,在0x20000000-0x28000000之間。也就說當CPU讀寫該區間范圍內的物理地址時,CPU會自動將ngCS4引腳拉低,片選信號nGCS4有效,網卡設備被選中。
地址線為什么只有一根,這是DM9000決定的,看手冊可以知道:
- CMD管腳為0時,數據線送的是DM9000的寄存器地址;
- CMD管腳為1時,數據線送的是16位的寄存器數據。
所以對DM9000的操作至少需要兩步:先寫地址,再寫(讀)數據。它不像其它類內存總線那樣直接把數據寫到地址傳輸一次就可以了,而它要傳輸兩次,因為它的總線地址就退化成了類似於NAND的ALE信號,就是地址和數據的區分信號了,而不是DM9000里面操作的寄存器地址。
DM9000對於CPU的地址線只認識一根線,只要這根線對應的CPU傳送的地址的對應位匹配就可以了,上面接到LADDR2,也就是說:
- 讀寫寄存器地址的時候操作的總線地址滿足:以基地址起頭(0x20000000),偏移基地址LADDR2為0(低四位:0000),也就是寫的時候總線地址為:0x20000000;
- 讀寫寄存器數據的時候操作的總線地址滿足:以基地址起頭(0x20000000),偏移基地址LADDR2為1 (低四位:0100),也就是寫的時候總線地址為:0x20000004;
所以首先滿足總線地址在BANK4里面(這樣CS4才能自動選中),其次滿足最后四位為0(傳送寄存器地址)或4(傳送數據)就可以了,滿足這兩個條件地址隨便設。
/* dm9000的地址寄存器地址是0x20000000,數據寄存器的地址是0x20000004 */ #define DM_ADD (*((volatile u16 *)0x20000000)) #define DM_DAT (*((volatile u16 *)0x20000004))
DM9000 IRQ_LAN(INT)接的是S3C2440的ENT7(GPF7),用的外部中斷7,這個中斷用於接收數據時觸發的。當DM9000收到外部的數據后,會暫存到內部地址中,然后產生一個上升沿中斷,等待S3C2440讀取數據;當DM9000將S3C2440的數據轉發出去后,也會產生一個上升沿中斷給2440。
3.2 片選信息設置
我們需要初始化DM9000,那么我們必然需要設置BSWCON上有關bank4的位,以及寄存器BANKCON4。具體參考Mini2440裸機開發之存儲器控制器。
#define B4_Tacs 0x0 /* 0clk */ #define B4_Tcos 0x0 /* 3clk */ #define B4_Tacc 0x7 /* 14clk */ #define B4_Tcoh 0x1 /* 1clk */ #define B4_Tah 0x0 /* 0clk */ #define B4_Tacp 0x0 /* 6clk */ #define B4_PMC 0x0 /* normal */
/************************************************************************** * * Function : 初始化讀寫時序 1、數據寬度(BWSCON) 2、時序信號填寫(BANKCON4) * *************************************************************************/ void cs_init() { // 數據寬度設置 BWSCON &= ~(3<<16); BWSCON |= (1<<16); //時序信號設置 BANKCON4 =((B4_Tacs<<13)|(B4_Tcos<<11)|(B4_Tacc<<8)|(B4_Tcoh<<6)|(B4_Tah<<4)|(B4_Tacp<<2)|(B4_PMC<<0)); }
3.3 中斷初始化
(1). 配置相應的中斷引腳;
(2). 設置EINT7的觸發方式,高電平;
(3). 清除中斷標志(SRCPND,INTPND,EINTPND);
(4). 使能中斷,設置中斷屏蔽寄存器(INTMSK,EINTMSK);
/************************************************************************** * * Function : dm9000中斷初始化 外部中斷ENT4~7 引腳GPF7,高電平觸發 * dm9000在接受到數據時會向cpu發送一個中斷,從mini2440的原理圖可以得知它會在GPF7產生中斷 * *************************************************************************/ void dm9000_int_init() { // 設置引腳復用為為中斷 GPFCON &= ~(0x3<<14); GPFCON |= 0x2<<14; // 設置中斷觸發方式 EXTINT0 &= ~(0x7<<28); EXTINT0 |= 0x1<<28; /* 設置EINT7的信號觸發方式,高電平 */ // 中斷清除 EINTPEND |= 1<<7; /* 向相應位置寫1清除次級源掛起寄存器 */ SRCPND |= BIT_EINT4_7; /* 向相應位置寫1清除源掛起寄存器 */ INTPND |= BIT_EINT4_7; /* 向相應位置寫1清除掛起寄存器 */ // 使能中斷 EINTMASK &= ~(1<<7); /* 關閉外部中斷屏蔽 */ INTMSK &= ~BIT_EINT4_7; /* 關閉EINT4~7中斷屏蔽,總中斷 */ }
3.5 復位設備
(1).實現往DM9000讀寫數據的函數
/************************************************************************** * * Function : dm9000 IO寫數據 * *************************************************************************/ void dm9000_reg_write(u16 reg,u16 data){ DM_ADD = reg; DM_DAT = data; } /************************************************************************** * * Function : dm9000 IO讀數據 * *************************************************************************/ u8 dm9000_reg_read(u16 reg){ DM_ADD =reg; return DM_DAT; }
(2).設置I/O為輸出模式
(3).通過對GPIO0寫0為內部的PHY提供電源
(4).軟件復位(自動清0),MAC內部回環模式
(5).對(4)中的寄存器全部寫入0
(6).重復(4)(5)
/************************************************************************** * * Function : dm9000 芯片復位 * *************************************************************************/ u8 dm9000_reset(){ // 設置GPIO控制寄存器 GPIO0設置為輸出 dm9000_reg_write(DM9000_GPCR, GPCR_GPIO0_OUT); // 通過對GPIO0寫入0為內部的PHY提供電源 dm9000_reg_write(DM9000_GPR, 0); // 軟件復位(自動清0),MAC內部回環模式 dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); // 對上一步的寄存器寫入全0 dm9000_reg_write(DM9000_NCR, 0); // 重復上面,用兩次實現真正復位 dm9000_reg_write(DM9000_NCR, (NCR_LBK_INT_MAC | NCR_RST)); dm9000_reg_write(DM9000_NCR, 0); }
3.6 捕獲網卡
(1). 讀取生產廠家ID(0A46H)
(2).讀取產品ID(9000H)
(3).將兩個ID組合與之前預定義的值進行對比
/************************************************************************** * * Function : dm9000 芯片的捕獲,實際上就是對dm9000上的生產廠家ID、產品ID信息進行對比 * *************************************************************************/ int dm9000_probe(){ u32 id_val; // 讀取生產廠家ID低字節 id_val = dm9000_reg_read(DM9000_VIDL); // 讀取生產廠家ID高字節 id_val |= (dm9000_reg_read(DM9000_VIDH) << 8); // 讀取產品ID低字節 id_val |= (dm9000_reg_read(DM9000_PIDL) << 16); // 讀取產品ID高字節 id_val |= (dm9000_reg_read(DM9000_PIDH) << 24); if(id_val == DM9000_ID) { printf("dm9000 is found!\r\n"); return 0; }else{ printf("dm9000 is not found!\r\n"); return -1; } }
3.7 MAC初始化
/************************************************************************** * * Function : dm9000 mac初始化 * *************************************************************************/ void dm9000_mac_init() { /* Program operating register, only internal phy supported */ dm9000_reg_write(DM9000_NCR, 0x0); /* TX Polling clear */ dm9000_reg_write(DM9000_TCR, 0); /* Less 3Kb, 200us */ dm9000_reg_write(DM9000_BPTR, BPTR_BPHW(3) | BPTR_JPT_600US); /* Flow Control : High/Low Water */ dm9000_reg_write(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* SH FIXME: This looks strange! Flow Control */ dm9000_reg_write(DM9000_FCR, 0x0); /* 特殊位 */ dm9000_reg_write(DM9000_SMCR, 0); /* 清除發送狀態 */ dm9000_reg_write(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* 清除中斷狀態 */ dm9000_reg_write(DM9000_ISR, ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS); }
3.8 填充MAC地址
/************************************************************************** * * Function : dm9000 填充mac地址 * *************************************************************************/ void dm9000_fill_macadd() { u16 oft = 0,i = 0; /* fill device MAC address registers */ for (i = 0; i < 6; i++) dm9000_reg_write(DM9000_PAR + i, mac_addr[i]); /*maybe this is some problem*/ for (i = 0, oft = 0x16; i < 8; i++, oft++) dm9000_reg_write(oft, 0xff); /* read back mac, just to be sure */ for (i = 0, oft = 0x10; i < 6; i++, oft++) printf("%02x:", dm9000_reg_read(oft)); printf("\r\n"); }
3.9 dm9000初始化
/************************************************************************** * * Function : dm9000 初始化,其主要操作就是填入MAC地址,然后啟動dm9000 * *************************************************************************/ int dm9000_init() { /* 片選初始化 */ cs_init(); /* 中斷初始化 */ dm9000_int_init(); /* 芯片重置 */ dm9000_reset(); /* 芯片捕獲 */ if(dm9000_probe()<0) return -1; /* MAC初始化 */ dm9000_mac_init(); /*設置MAC*/ dm9000_fill_macadd(); /* 啟動DM9000,這里如果加入RCR_ALL意為接受廣播數據,會造成接收數據異常 */ dm9000_reg_write(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* Enable TX/RX interrupt mask */ dm9000_reg_write(DM9000_IMR, IMR_PAR); }
3.10 發送數據包
(1). 禁止所有中斷
(2). 寫入發送數據長度
(3). 寫入待發送數據
- 將MWCMD賦值給地址端口,做好准備,MWCMD會自動將數據送到TX SRAM中;
- 利用循環,將數據寫入數據端口;
(4) 啟動發送
(5).等待發送完成,當發送結束的時候,TCR的0位會自動清0,所以去等待他變0即可
(6).清除發送狀態
(7)開啟接收中斷
/************************************************************************** * * Function : dm9000 網卡的發送 * *************************************************************************/ void dm9000_tx(u8 *data,u32 length) { u32 i; /* 禁止中斷*/ dm9000_reg_write(DM9000_IMR,0x80); /*寫入發送數據的長度*/ dm9000_reg_write(DM9000_TXPLL, length & 0xff); dm9000_reg_write(DM9000_TXPLH, (length >> 8) & 0xff); /*寫入待發送的數據*/ DM_ADD = DM9000_MWCMD; for(i=0;i<length;i+=2) { DM_DAT = data[i] | (data[i+1]<<8); } /*啟動發送*/ dm9000_reg_write(DM9000_TCR, TCR_TXREQ); /*等待發送結束*/ while(1) { u8 status; status = dm9000_reg_read(DM9000_TCR); if((status&0x01)==0x00) break; } /*清除發送狀態*/ dm9000_reg_write(DM9000_NSR,0x2c); /*開啟接收中斷*/ dm9000_reg_write(DM9000_IMR,0x81); }
3.11 接收數據包
接收是中斷處理的,接收到一個包就會產生中斷。在中斷處理的時候調用接收函數。
(1). 判斷是否產生中斷,是就繼續,否則退出接收函數
- 讀取ISR寄存器第0位即可。
(2). 清除中斷標志
- ISR寄存器第0位寫1即可。
(3).空讀
- 讀取MRCMDX寄存器
(4).讀取包的狀態和長度
- 讀取MRCMD寄存器得到狀態,此時地址端口的數據就是對應MRCMD的偏移量,所以可以直接讀取此時數據寄存器的值,不用再重新指定偏移量,就可以得到長度;
- 在長度后面會自動送入有效的數據,所以后面可以頁直接讀數據寄存器得到有效數據。
(5).讀取包的數據
- 在讀取數據之前應該對讀到的長度進行檢查,看是否小於以太網包的最大長度。然后利用for循環讀取數據,注意數據的組合方式。
/************************************************************************** * * Function : dm9000 網卡的接收 * *************************************************************************/ u16 dm9000_rx(u8 * data) { u16 i,len,status,tmp,ready; /*檢查是否有接收中斷並清除*/ if(!dm9000_reg_read(DM9000_ISR&0x01)) return 0; /*清除接收中斷標志*/ dm9000_reg_write(DM9000_ISR,0x01); /*空讀*/ ready = dm9000_reg_read(DM9000_MRCMDX); if(ready&0x01 != 0x01) { ready = dm9000_reg_read(DM9000_MRCMDX); if(ready&0x01 != 0x01) return 0; } /*讀取包的狀態和長度*/ status = dm9000_reg_read(DM9000_MRCMD); len = DM_DAT; /*讀取包的數據*/ if(len<DM9000_PKT_MAX) { for(i=0;i<len;i+=2) { tmp = DM_DAT; data[i] = tmp&0xff; data[i+1] = (tmp>>8)&0xff; } } return len; }
3.12 中斷處理函數
當DM9000發生接收數據中斷時,INT引腳觸發高電平,進入S3C2440中斷處理程序。中斷處理程序主要包含:
- 調用接收函數存放接收到的數據;
- 清除中斷標志(SRCPND,INTPND,EINTPND);
/************************************************************************* * * Function : 中斷源4 外部中斷4至7 DM9000接收中斷 * *************************************************************************/ void EINT4_7_IRQHandler() { packet_len = dm9000_rx(dm9000_buffer); printf('rec data %s, length%d',dm9000_buffer,packet_len); //清中斷 EINTPEND |= (1 << 7) ; /* 清中斷標志位 */ SRCPND |= BIT_EINT4_7; /* 清中斷標志位 */ INTPND |= BIT_EINT4_7; /* 清中斷標志位 */ }
四 ARP協議實現
4.1 ARP定義
這里只對ARP協議進行簡單的介紹,更多相關信息需要去學習計算機網絡相關知識。
ARP全稱Address Resolution Protocol,中文名為地址解析協議,它工作在數據鏈路層,在本層和硬件接口聯系,同時對上層提供服務。IP數據包常通過以太網發送,以太網設備並不識別32位IP地址,它們是以48位以太網地址傳輸以太網數據包。因此,必須把IP目的地址轉換成以太網目的地址。
在以太網中,一台主機要和另一台主機進行直接通信,必須要知道目標主機的MAC地址。但是這個目標MAC地址是如何獲得的呢?它就是通過地址解析協議獲得的。ARP協議用於將網絡中的IP地址解析成硬件地址(MAC地址),以保證通信的順利進行。
4.2 ARP工作原理
(1) 同一網段
在局域網中,每台主機都會在自己的ARP緩沖區建立一個ARP列表,以表示IP地址和MAC地址的對應關系。
- 當源主機需要將一個數據包發送到目標主機時,會首先檢查自己的ARP列表中是否存在該IP對應的MAC地址,如果有,就直接將數據包發送到這個MAC地址;
- 如果沒有,就向本段網絡發起一個ARP請求的廣播包,查詢此目的主機對應的MAC地址。此ARP請求數據包里包括源主機的IP、硬件地址、以及目標主機的IP地址;
- 網絡中所有的主機收到這個ARP請求后,會檢查數據包中的目的IP是否和自己的IP地址一致,如果不相同則忽略此數據包;
- 如果相同,該主機首先將發送端的MAC地址和IP添加到自己的ARP列表中,如果ARP列表中已經存在該IP的地址,則將其覆蓋,然后給源主機發送一個ARP響應數據包,告訴對方自己是它需要查找的MAC地址,源主機收到這個ARP響應數據包后,將得到的目標主機的IP地址和MAC地址添加到自己的ARP列表中,並利用此信息開始數據的傳輸;
- 如果源主機一直沒有收到ARP響應數據包,則表示ARP查詢失敗;
例如:
A的地址為:IP——192.168.10.1 ;MAC——AA-AA-AA-AA-AA-AA
B的地址為:IP——192.168.10.2 ;MAC——BB-BB-BB-BB-BB-BB
根據上面所講的原理,簡單說明這個過程:A要和B通信,A就需要知道B的以太網地址,於是A發送了一個ARP請求廣播(誰是192.168.10.2,請告訴192.168.10.1),當B收到該廣播時,就檢查自己,結果發現和自己的IP一致,然后向A發送一個ARP單播應答(192.168.10.2在BB-BB-BB-BB-BB-BB).
(2) 不同網段
當主機A和主機B不在同一網段時,主機A就會先向網關發出ARP請求,ARP請求報文中的目標IP地址為網關的IP地址。當主機A從收到的響應報文中獲得網關的MAC地址后,將報文封裝並發給網關。如果網關沒有主機B的ARP表項,網關會廣播ARP請求,目標IP地址為主機B的IP地址,當網關從收到的響應報文中獲得主機B的MAC地址后,就可以將報文發給主機B;如果網關已經有主機B的ARP表項,網關直接把報文發給主機B。
ARP一般可以用在主機掃描中,判斷一個主機是否存在,此外通過ARP協議也可以實現ARP欺騙,感興趣的自行了解。
4.3 ARP數據包
ARP報文結構:
- 幀類型:它的值為0x0800表示IP數據包,0x0806表示ARP包,0x8035表示RARP包;
- 硬件類型:表示硬件地址的類型,值為1表示以太網地址;
- 協議類型:表示要映射的協議地址類型,它的值為0x0800表示IP地址類型;
- 硬件地址長度和協議地址長度以字節為單位,對於以太網上的IP地址的ARP請求或應答來說,他們的值分別為6和4;
- 操作類型(op):1表示ARP請求,2表示ARP應答;
- 發送端MAC地址:發送方設備的硬件地址;
- 發送端IP地址:發送方設備的IP地址;
- 目標MAC地址:接收方設備的硬件地址;
- 目標IP地址:接收方設備的IP地址;
假設主機IP:192.168.0.155 MAC:08-00-3e-26-0a-5b,目標192.168.0.104,構建ARP請求數據包:
ff-ff-ff-ff-ff-ff 廣播MAC |
08-00-3e-26-0a-5b | 0x0806 | 0x0001 | 0x0800 | 06 | 04 | 0x0001 | 08-00-3e-26-0a-5b | 192.168.0.155 | 00-00-00-00-00-00 目標MAC未知 |
192.168.0.104 |
我們S3C2440運行在小端模式下,即低位字節數據在低地址,高位字節數據在高地址。比如數據0x12345678,在內存中存儲數據為:
0x78 | 0x56 | 0x34 | 0x12 |
低地址 | 高地址 |
然而網絡字節序采用的大端模式,網絡上傳輸的數據都是字節流,UDP/TCP/IP協議規定:把接收到的第一個字節當做高位字節看待,這就要求發送的第一個字節是高位字節。
4.4 ARP實現代碼
(1) 構建ARP請求包
(2) DM9000發送ARP數據包
arp.h文件:

/************************************************************************** * * FileName : arp.c * Function : ARP協議實現 * Author : zy * *************************************************************************/ #ifndef __ARP_H__ #define __ARP_H__ #include "type.h" #include "dm9000.h" /******************************************************************************************************************/ #define SWAP(n) ((((u16)n & 0xff) << 8) | ((((u16)n >> 8) & 0xff))) /* 以太網頭部結構體 */ typedef struct eth_header{ u8 d_mac[6]; u8 s_mac[6]; u16 frame_type; }ETH_HDR; /* ARP頭部結構體 */ typedef struct arp_header{ ETH_HDR ethhdr; u16 hw_type; u16 protocol; u8 hwadd_len; u8 protoc_len; u16 opcode; u8 smac[6]; u8 sipaddr[4]; u8 dmac[6]; u8 dipaddr[4]; }ARP_HDR; /* IP頭部結構體 */ typedef struct ip_hdr { ETH_HDR ethhdr; u8 vhl; u8 tos; u16 len; u16 ipid; u16 ipoffset; u8 ttl; u8 proto; u16 ipchksum; u8 srcipaddr[4]; u8 destipaddr[4]; }IP_HDR; /* UDP頭部結構體 */ typedef struct udp_hdr { IP_HDR iphdr; u16 sport; u16 dport; u16 len; u16 udpchksum; }UDP_HDR; /* TFTP數據包結構體 */ typedef struct tftp_package { u16 opcode; u16 blocknum; u8 data[0]; }TFTP_PAK; /*網絡協議類型*/ #define PROTO_ARP 0x0806 #define PROTO_IP 0x0800 #define PROTO_UDP 0x11 extern u8 host_mac_addr[6]; extern u8 mac_addr[6]; extern u8 ip_addr[4]; extern u8 host_ip_addr[4]; /* 函數聲明 */ extern void arp_request(); /* ARP請求數據包 */ extern u8 arp_respond(u8* buf,u32 len); /* ARP響應數據包 */ #endif
arp.c文件:
/************************************************************************** * * FileName : arp.c * Function : ARP協議實現 * Author : zy * *************************************************************************/ #include "arp.h" #include "stdio.h" #include "string.h" /************************************************************************** * * Function : ARP請求數據包 * *************************************************************************/ void arp_request() { /* ARP數據包 */ ARP_HDR arpbuf; u8 unkown[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; /* 構成ARP請求包 */ memcpy(arpbuf.ethhdr.d_mac,host_mac_addr,6); //以太網目的地址 memcpy(arpbuf.ethhdr.s_mac,mac_addr,6); //以太網源地址 arpbuf.ethhdr.frame_type = SWAP(PROTO_ARP); //幀類型 arpbuf.hw_type = SWAP(1); //硬件類型 arpbuf.protocol = SWAP(0x0800); //協議類型 arpbuf.hwadd_len = 6; //硬件地址長度 arpbuf.protoc_len = 4; //協議地址長度 arpbuf.opcode = SWAP(1); //操作碼 memcpy(arpbuf.smac,mac_addr,6); //發送端以太網地址 memcpy(arpbuf.sipaddr,ip_addr,4); //發送端IP地址 memcpy(arpbuf.dmac,unkown,6); //目的MAC地址 memcpy(arpbuf.dipaddr,host_ip_addr,4); //目的IP地址 /* 調用dm9000發送函數,發送請求包 */ dm9000_tx((u8*)&arpbuf,14+28); } /************************************************************************** * * Function : ARP響應數據包 * *************************************************************************/ u8 arp_respond(u8* buf,u32 len) { /* ARP數據包 */ ARP_HDR arpbuf; ARP_HDR* p = (ARP_HDR*)buf; u32 i = 0; if(len < 28) return 0; switch(SWAP(p->opcode)){ /* 對PC發到開發板的應答包解析 */ case 2: memcpy(host_ip_addr,p->sipaddr,4); printf("host ip is : "); for(i=0;i<4;i++) printf("%03d ",host_ip_addr[i]); printf("\n\r"); memcpy(host_mac_addr,p->smac,6); printf("host mac is : "); for(i=0;i<6;i++) printf("%02X ",host_mac_addr[i]); printf("\n\r"); break; /* 響應PC發到開發板的請求包 */ case 1: memcpy(arpbuf.ethhdr.d_mac,p->ethhdr.s_mac,6); //以太網目的地址 memcpy(arpbuf.ethhdr.s_mac,mac_addr,6); //以太網源地址 arpbuf.ethhdr.frame_type = SWAP(PROTO_ARP); //幀類型 arpbuf.hw_type = SWAP(1); //硬件類型 arpbuf.protocol = SWAP(0x0800); //協議類型 arpbuf.hwadd_len = 6; //硬件地址長度 arpbuf.protoc_len = 4; //協議地址長度 arpbuf.opcode = SWAP(2); //操作碼 memcpy(arpbuf.smac,mac_addr,6); // 發送端以太網地址,即以太網原地址 memcpy(arpbuf.sipaddr,ip_addr,4); //發送端IP地址 memcpy(arpbuf.dmac,p->smac,6); memcpy(arpbuf.dipaddr,p->sipaddr,4); //目的IP地址 /* 調用dm9000發送函數,發送請求包 */ dm9000_tx((u8*)&arpbuf,14+28); break; default: break; } return 1; }
需要注意的是目標主機和開發板的IP地址設置,需要在同一個網段:
u8 host_mac_addr[6]={0xff,0xff,0xff,0xff,0xff,0xff}; /* 以太網目的地址 */ u8 host_ip_addr[4] = {192,168,0,104}; /* 目標ip*/ u8 mac_addr[6] ={0x08,0x00,0x3E,0x26,0x0A,0x5B}; /* 發送者mac地址 */ u8 ip_addr[4] = {192,168,0,155}; /* 發送者ip */ u16 packet_len; /* 接收到的數據長度 */ u8 dm9000_buffer[DM9000_PKT_MAX] = {0}; /* 數據緩沖區 */
五、代碼下載
Young / s3c2440_project[11.dm9000】
參考文章
[2]DM9000中文文檔