Mini2440裸機開發之DM9000


網絡對於嵌入式系統來說必不可少。可是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 IRegister)

名稱

默認值

描述

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
View Code

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】

參考文章

[1]S3C2440裸機程序【3】DM9000A

[2]DM9000中文文檔

[3]DM9000裸機驅動及ARP實現

[4]dm9000aep芯片介紹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM