s5pv210 uboot——移植DM9000網卡驅動


1:DM9000原理分析

s5pv210接DM9000 底板圖:

重要的引腳有:IOR、IOW、AEN、CMD、INT、RST 以及數據引腳 SD0-SD15

看數據手冊這些引腳的作用:

IOR:讀選擇引腳,低電平有效,即低電平是讀;

IOW:寫選擇引腳,低電平有效,即低電平寫;

CS (chip select)片選信號,s5pv210中有6個外加srom接口 bank0-bank5 CS引腳可以接 CS0-CS5代表與這6個bank中其中一個相連

cmd寄存器是命令/數據切換引腳,低電平時讀寫命令操作,高電平時讀寫數據操作其中。地址引腳配合AEN引腳來選通該網卡芯片,對於大多數的應用來說沒有意義,

因為在我們的應用中一般只用一個網卡芯片,而這些地址引腳主要用於在多網卡芯片環境下選擇其中之一。DM9000工作的默認基地址為0x300,這里我們按照默認地址選擇,

將SA9、SA8接高電平,SA7-DA4接低電平。

 上面這段話很關鍵:dm9000芯片數據總線16根,地址總線只連接了1根,連接的ADDR2,dm9000中的寄存器尋址是通過數據總線來尋址的,並不是通過地址總線尋址;

連接這個地址總線的作用是配合cs總線進行片選,來選擇網卡芯片;比如說有兩個網卡芯片的可以在用一個cs線和地址線連接另外一個網卡芯片;

當addr2為低電平時,data總線發送的是地址,前面提到了9、8地址線為1,4-7地址線為0,所以基地址是0x8800_0300 ,當addr2為0

即0x8800_0300地址中的值為地址,這個地址中的值對應的是dm9000芯片中的寄存器,而addr2為1即0x8800_0304這個地址對應的位數據。

總結一下:0x8800_0300 加上一定的偏移量 用來選擇dm9000中的寄存器,而0x8800_0304這個寄存器用來給dm9000中的寄存器讀寫值;

在配合IOW、IOR兩個命令總線,我們就可以讀取和寫入dm9000寄存器,從而進行對寄存器的操控。

這里內容參考http://blog.csdn.net/googlemi/article/details/8887871這篇博客;

  在DM9000中,只有兩個可以直接被處理器訪問的寄存器,這里命名為CMD端口和DATA端口。事實上,DM9000中有許多控制和狀態寄存器(這些寄存器在上一篇文章中有詳細的使用說明),

但它們都不能直接被處理器訪問,訪問這些控制、狀態寄存器的方法是:

(1)、將寄存器的地址寫到CMD端口;

(2)、從DATA端口讀寫寄存器中的數據;

    1、讀、寫寄存器

    其實,INDEX端口和DATA端口的就是由芯片上的CMD引腳來區分的。低電平為INDEX端口,高電平為DATA端口。所以,要想實現讀寫寄存器,就必須先控制好CMD引腳。

    若使用總線接口連接DM9000的話,假設總線連接后芯片的基地址為0x800300(24根地址總線),只需如下方法:

#define _REG_DM_ADDR    (*(volatile unsigned short *)0x800300)

#define _REG_DM_DATA    (*(volatile unsigned short *)0x800304)

 

DM9000寄存器寫函數:

 void dm9k_reg_write(u16 reg, u16 data)

{

  udelay(20);    //延時20um

  _REG_DM_ADDR = reg;

  udelay(20);    //延時20um

  _REG_DM_DATA = data;

}

這個函數即可把data中的值寫入dm9000相應的寄存器中;

unsigned int dm9k_reg_read(u16 reg)

{

  udelay(20);    //延時20um 

  _REG_DM_ADDR = reg;

  udelay(20);

  return _REG_DM_DATA ;

}

下圖為dm9000中的寄存器對應基地址的偏移量,可以看出dm9000中的寄存器都是8bit的;

 

 

以上兩個圖是s5pv210 datamunu的網卡讀寫時序

 

下面我們來初始化dm9000網卡:

首先,初始化srom控制器:

SROM_BW寄存器用來選擇bank以及設置數據位寬

 

void cs_init()

     /*設置bank1為16bit 其他位為0*/

  SROM_BW &= (~(0xf<<4));

  SROM_BW |=  (0x1<<4);

  /*設置時序*/

  SROM_BC1 =(0<<0)|(0x2<<4)|(0x2<<8)|(0x2<<12)|(0x2<<16)|(0x2<<24)|(0x2<<28);

}

/*dm9000的復位代碼*/

 void dm9k_reset(void)

{ 

 dm9000_reg_write(GPCR, 0x01);//設置 GPCR(1EH) bit[0]=1,使DM9000的GPIO3為輸出。

    dm9000_reg_write(GPR, 0x00);//GPR bit[0]=0 使DM9000的GPIO3輸出為低以激活內部PHY。

    udelay(5000);//延時2ms以上等待PHY上電。

    dm9000_reg_write(NCR, 0x03);//軟件復位

    udelay(30);//延時20us以上等待軟件復位完成

    dm9000_reg_write(NCR, 0x00);//復位完成,設置正常工作模式。

    dm9000_reg_write(NCR, 0x03);//第二次軟件復位,為了確保軟件復位完全成功。此步驟是必要的。

    udelay(30);

    dm9000_reg_write(NCR, 0x00);

}

void dm9k_clear(void)

{  

  dm9000_reg_write(NSR, 0x2c);//清除各種狀態標志位

  dm9000_reg_write(ISR, 0x3f);//清除所有中斷標志位

}

void dm9k_conreg_init(void)

{

   dm9k_reg_write(RCR, 0x39);//接收控制

    dm9k_reg_write(TCR, 0x00);//發送控制

    dm9k_reg_write(BPTR, 0x3f);

    dm9k_reg_write(FCTR, 0x3a);

    dm9k_reg_write(RTFCR, 0xff);

    dm9k_reg_write(SMCR, 0x00);

/*以上是功能控制,具體功能參考上一篇文章中的說明,或參考數據手冊的介紹*/

}

void dm9k_mac_init(void)

{

  int i = 0;

  unsigned char mac_addr[] = {0x44, 0x45, 0x53, 0x54, 0x00, 0x00};

  for (i=0; i<6; i++)

   dm9000_reg_write(PAR + i, mac_addr[i]);//6個字節的MAC地址

}

void dm9k_enalbe(void)

{

  

  dm9000_reg_write(IMR, 0x81);

/*中斷使能(或者說中斷屏蔽),即開啟我們想要的中斷,關閉不想要的,這里只開啟的一個接收中斷*/

}

 void dm9k_init(void)

{

  cs_init();    //片選、時序

  dm9k_reset();  //dm9000重啟  

  dm9k_clear();  //清中斷、清標志位

  dm9k_conreg_init();  //控制寄存器初始化

  dm9k_mac_init();    //mac地址初始化

  dm9k_enalbe();     //dm9000使能

}

 

     3、發送、接收數據包

    同樣,以程序為例,通過注釋說明。

//發送數據包

//參數:datas為要發送的數據緩沖區(以字節為單位),length為要發送的數據長度(兩個字節)。

void sendpacket(unsigned char *datas, unsigned int length)

{
    unsigned int len, i;
    
    dm9000_reg_write(IMR, 0x80);//先禁止網卡中斷,防止在發送數據時被中斷干擾
    
    len = length;

    dm9000_reg_write(TXPLH, (len>>8) & 0x0ff);

    dm9000_reg_write(TXPLL, len & 0x0ff);

/*這兩句是將要發送數據的長度告訴DM9000的寄存器*/

    DM_ADD = MWCMD;//這里的寫法是針對有總線接口的處理器,沒有總線接口的處理器要注意加上時序。

    for(i=0; i<len; i+=2)//16 bit mode

    {

        udelay(20);

        DM_CMD = datas[i] | (datas[i+1]<<8);

    }

/*上面是將要發送的數據寫到DM9000的內部SRAM中的寫FIFO中,注意沒有總線接口的處理器要加上適當的時序*/

/*只需要向這個寄存器中寫數據即可,MWCMD是DM9000內部SRAM的DMA指針,根據處理器模式,寫后自動增加*/

    dm9000_reg_write(TCR, 0x01);//發送數據到以太網上

    while((dm9000_reg_read(NSR) & 0x0c) == 0);//等待數據發送完成

    udelay(20);

    dm9000_reg_write(NSR, 0x2c);//清除狀態寄存器,由於發送數據沒有設置中斷,因此不必處理中斷標志位

    dm9000_reg_write(IMR, 0x81);//DM9000網卡的接收中斷使能

}

    以上是發送數據包,過程很簡單。而接收數據包確需要些說明了。DM9000從網絡中接到一個數據包后,會在數據包前面加上4個字節,分別為“01H”、“status”(同RSR寄存器的值)、“LENL”(數據包長度低8位)、“LENH”(數據包長度高8位)。所以首先要讀取這4個字節來確定數據包的狀態,第一個字節“01H”表示接下來的是有效數據包,若為“00H”則表示沒有數據包,若為其它值則表示網卡沒有正確初始化,需要從新初始化。

    如果接收到的數據包長度小於60字節,則DM9000會自動為不足的字節補上0,使其達到60字節。同時,在接收到的數據包后DM9000還會自動添加4個CRC校驗字節。可以不予處理。於是,接收到的數據包的最小長度也會是64字節。當然,可以根據TCP/IP協議從首部字節中出有效字節數,這部分在后面講解。下面為接收數據包的函數。

//接收數據包

//參數:datas為接收到是數據存儲位置(以字節為單位)

//返回值:接收成功返回數據包類型,不成功返回0

unsigned int receivepacket(unsigned char *datas)

{

    unsigned int i, tem;

    unsigned int status, len;

    unsigned char ready;

    ready = 0;//希望讀取到“01H”

    status = 0;//數據包狀態

     len = 0; //數據包長度

/*以上為有效數據包前的4個狀態字節*/

    if(dm9000_reg_read(ISR) & 0x01)

    {

        dm9000_reg_write(ISR, 0x01);

    }

/*清除接收中斷標志位*/

/***********************************************************************************/

/*這個地方遇到了問題,下面的黑色字體語句應該替換成成紅色字體,也就是說MRCMDX寄存器如果第一次讀不到數據,還要讀一次才能確定完全沒有數據。

在做 PING 實驗時證明:每個數據包都是通過第二次的讀取MRCMDX寄存器操作而獲知為有效數據包的,對初始化的寄存器做了多次修改依然是此結果,但是用如下方法來實現,絕不會漏掉數據包。*/

    ready = dm9000_reg_read(MRCMDX); // 第一次讀取,一般讀取到的是 00H

    if((ready & 0x0ff) != 0x01)

    {

        ready = dm9000_reg_read(MRCMDX); // 第二次讀取,總能獲取到數據

        if((ready & 0x01) != 0x01)

         {

            if((ready & 0x01) != 0x00) //若第二次讀取到的不是 01H 或 00H ,則表示沒有初始化成功

            {

                 dm9000_reg_write(IMR, 0x80);//屏幕網卡中斷

                 DM9000_init();//重新初始化

                 dm9000_reg_write(IMR, 0x81);//打開網卡中斷

            }

            retrun 0;

         }

    }

/* ready = dm9000_reg_read(MRCMDX); // read a byte without pointer increment

    if(!(ready & 0x01))

    {

         return 0;

    }*/

/***********************************************************************************/

/*以上表示若接收到的第一個字節不是“01H”,則表示沒有數據包,返回0*/

    status = dm9000_reg_read(MRCMD);

    udelay(20);

    len = DM_CMD;

    if(!(status & 0xbf00) && (len < 1522))

    {

        for(i=0; i<len; i+=2)// 16 bit mode

        {

            udelay(20);

            tem = DM_CMD;

            datas[i] = tem & 0x0ff;

            datas[i + 1] = (tem >> 8) & 0x0ff;

        }

    }

    else

    {
        return 0;

    }

/*以上接收數據包,注意的地方與發送數據包的地方相同*/

    if(len > 1000) return 0;

    if( (HON( ETHBUF->type ) != ETHTYPE_ARP) &&

        (HON( ETHBUF->type ) != ETHTYPE_IP) )

    {

        return 0;

    }

    packet_len = len;

/*以上對接收到的數據包作一些必要的限制,去除大數據包,去除非ARP或IP的數據包*/
    
      
    return HON( ETHBUF->type ); //返回數據包的類型,這里只選擇是ARP或IP兩種類型

}

    注意:上面的函數用到了一些宏定義,已經在頭文件中定義過(補充在本文結尾處),這里說明一下:其中uint16定義為兩個字節的變量,根據C編譯器進行定義。

unsigned char Buffer[1000];//定義了一個1000字節的接收發送緩沖區

uint16 packet_len;//接收、發送數據包的長度,以字節為單位。

struct eth_hdr //以太網頭部結構,為了以后使用方便

{

unsigned char d_mac[6];   //目的地址

unsigned char s_mac[6];   //源地址

uint16 type;     //協議類型

};

struct arp_hdr //以太網頭部+ARP首部結構

{

struct eth_hdr ethhdr;    //以太網首部

uint16 hwtype;     //硬件類型(1表示傳輸的是以太網MAC地址)

uint16 protocol;    //協議類型(0x0800表示傳輸的是IP地址)

unsigned char hwlen;     //硬件地址長度(6)

unsigned char protolen;    //協議地址長度(4)

uint16 opcode;     //操作(1表示ARP請求,2表示ARP應答)

unsigned char smac[6];    //發送端MAC地址

unsigned char sipaddr[4];    //發送端IP地址

unsigned char dmac[6];    //目的端MAC地址

unsigned char dipaddr[4];    //目的端IP地址

};

struct ip_hdr //以太網頭部+IP首部結構

{

struct eth_hdr ethhdr;    //以太網首部

unsigned char vhl,      //4位版本號4位首部長度(0x45)

           tos;     //服務類型(0)

   uint16 len,      //整個IP數據報總字節長度

         ipid,           //IP標識

         ipoffset;     //3位標識13位偏移

unsigned char ttl,             //生存時間(32或64)

          proto;         //協議(1表示ICMP,2表示IGMP,6表示TCP,17表示UDP)

uint16 ipchksum;    //首部校驗和

unsigned char srcipaddr[4],    //源IP

             destipaddr[4];   //目的IP

};

 

#define ETHBUF ((struct eth_hdr*)(&Buffer[0]))

#define ARPBUF ((struct arp_hdr*)(&Buffer[0]))

#define IPBUF ((struct ip_hdr *)(&Buffer[0]))

    以上定義的三種首部結構,是根據TCP/IP協議的相關規范定義的,后面會對ARP協議進行詳細講解。

【上半部分完】

。。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。

 

 4、驗證初始化中的各個函數。

    下面我們來看一下,上面所寫的初始化函數是否可用。以上我們寫好了三個函數,分別為

DM9000_init(),sendpacket()和receivepacket(),保存並命名為dm9000.c。既然我們要進行調試,當

然要有結果輸出,根據自己的處理器的情況寫一個串口程序,這些函數是學某個單片機的基礎,這里不

做詳細介紹,用到是時候會在函數里注釋一下。

    接下來我們來寫個主函數,新建C文件,命名為mian.c,填寫如下函數:

void main(void)

{

    unsigned int i;

    unsigned char c;

    uart0_init();//初始化串口,調試時用到

    DM9000_init();//初始化網卡

    print_regs();/*通過串口,將DM9000中的寄存器打印出來,顯示在超級終端上。此函數根據自己

的處理器進行修改,功能僅僅是讀DM9000寄存器dm9000_reg_read(),再通過串口打印出來而已*/

}

    函數寫好,保存文件,連接硬件,連接網線到電腦上或局域網上,運行結果如下圖所示: 

圖4 顯示寄存器值

    這里首先檢查,各個控制寄存器是否是自己寫進去的值,在檢查狀態寄存器是否正確,其中主要要

看NSR寄存器的bit[6]是否為“1”,該位表示是否連接成功。本例中NSR的值為40H,括號里的數為對應

的十進制數。

    下面我們將主函數改進一下,增加個中斷接收函數,查看是否能接收到數據。

void main(void)

{

    unsigned int i;

    unsigned char c;

    uart0_init();//初始化串口,調試時用到

    DM9000_init();//初始化網卡

/********************************************************************************/

/*這一部分要根據自己的處理器情況,將DM9000的INT引腳連接到處理器的外部中斷上,打開中斷*/

/********************************************************************************/

    sendpacket(60);/*我事先已經在Buffer[]中存儲了ARP請求數據包,這里就直接發送了,以便接收

ARP應答包。大家可以先參考后面講的ARP協議,根據自己機器的情況,將數據事先存到Buffer[]中*/

    while(1);//等待中斷

}

void int_issue(void) //中斷處理函數,需要根據自己的處理器進行設置

{

    unsigned int i;

    i = receivepacket(Buffer);//將數據讀取到Buffer中。

int_again :

    if(i == 0)

    {

        return;

    }

     else

     {

        print_buffer();//將接收到的所有數據打印出來

         while(1);//停止在這里等待觀察,注意:實際應用中是不允許停止在中斷中的。

     }

/************************************************************************************/

/*這里加上這一段,目的是判斷中斷期間是否接收到其它數據包。有則加以處理。不加也完全可以*/

/* 根據自己的處理器,判斷處理器是否還處在中斷狀態,若是則進行如下操作,不是則跳過該段。*/

    i = receivepacket(Buffer);

    if(i != 0)

    {

        goto int_again;

    }

/************************************************************************************/

}

    編譯調試,運行結果如下: 

圖5 接收數據包中的數據

    這是一個ARP應答包,包含了我電腦上的MAC地址和局域網內的IP地址。反正我也不是啥重要人物,

這里就不保密了,呵呵。

    如果一些順利,到這里對DM9000網卡芯片的初始化工作就完成了。如果出現問題,首先要

檢查寄存器的值是否正確。可以將DM9000中的寄存器打印出來,查看到底是哪里的問題。如果打印出的

值很混亂,在確保串口程序無誤的前提下,查看硬件連接,以及寄存器讀寫時序是否正確,重復調試幾

次查找原因。

    三、ARP協議的實現

    1、ARP協議原理簡述

    ARP協議(Address Resolution Protocol 地址解析協議),在局域網中,網絡中實際傳輸的是“

幀”,幀里面有目標主機的MAC地址。在以太網中,一個注意要和另一個主機進行直接通信,必須要知

道目標主機的MAC地址。這個MAC地址就是標識我們的網卡芯片唯一性的地址。但這個目標MAC地址是如

何獲得的呢?這就用到了我們這里講到的地址解析協議。所有“地址解析”,就是主機在發送幀前將目

標IP地址轉換成MAC地址的過程。ARP協議的基本功能就是通過目標設備的IP地址,查詢目標設備的MAC

地址,以保證通信的順利進行。所以在第一次通信前,我們知道目標機的IP地址,想要獲知目標機的

MAC地址,就要發送ARP報文(即ARP數據包)。它的傳輸過程簡單的說就是:我知道目標機的IP地址,

那么我就向網絡中所有的機器發送一個ARP請求,請求中有目標機的IP地址,請求的意思是目標機要是

收到了此請求,就把你的MAC地址告訴我。如果目標機不存在,那么此請求自然不會有人回應。若目標

機接收到了此請求,它就會發送一個ARP應答,這個應答是明確發給請求者的,應答中有MAC地址。我接

到了這個應答,我就知道了目標機的MAC地址,就可以進行以后的通信了。因為每次通信都要用到MAC地

址。

    ARP報文被封裝在以太網幀頭部中傳輸,如圖為ARP請求報文的頭部格式。 

圖6 用於以太網的ARP請求或應答分組格式

    注意,以太網的傳輸存儲是“大端格式”,即先發送高字節后發送低字節。例如,兩個字節的數據

,先發送高8位后發送低8位。所以接收數據的時候要注意存儲順序。

    整個報文分成兩部分,以太網首部和ARP請求/應答。下面挑重點講述。

“以太網目的地址”字段:若是發送ARP請求,應填寫廣播類型的MAC地址FF-FF-FF-FF-FF-FF,意思是

讓網絡上的所有機器接收到;

“幀類型”字段:填寫08-06表示次報文是ARP協議;

“硬件類型”字段:填寫00-01表示以太網地址,即MAC地址;

“協議類型”字段:填寫08-00表示IP,即通過IP地址查詢MAC地址;

“硬件地址長度”字段:MAC地址長度為6(以字節為單位);

“協議地址長度”字段:IP地址長度為4(以字節為單位);

“操作類型”字段:ARP數據包類型,1表示ARP請求,2表示ARP應答;

“目的以太網地址”字段:若是發送ARP請求,這里是需要目標機填充的。


    2、ARP的處理程序

    ARP協議原理很簡單,下面我們來編寫ARP協議的處理函數。新建文件命名為arp.c,填寫如下函數

unsigned char mac_addr[6] = {*,*,*,*,*,*};

unsigned char ip_addr[4] = { 192, 168, *, * };

unsigned char host_ip_addr[4] = { 192, 168, *, * };

unsigned char host_mac_addr[6]={ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

unsigned char Buffer[1000];

uint16 packet_len;

/*這些全局變量,在前面將的文件中有些已經有過定義,這里要注意在前面加上“extern”關鍵字。“

*”應該根據自己的機器修改*/

#define ARPBUF ((struct arp_hdr*)(&Buffer[0]))

#define HON(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

/*此宏定義是將小端格式存儲的字(兩個字節)轉換成大端格式存儲*/

void arp_request(void) //發送ARP請求數據包

{

//以太網首部

memcpy(ARPBUF->ethhdr.d_mac, host_mac_addr, 6);

/*字符串拷貝函數,文件要包含<string.h>頭文件。參數依次是,拷貝目標指針,拷貝數據源指針,拷

貝字符數*/

memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6);

ARPBUF->ethhdr.type = HON( 0x0806 );

/*小端格式的編譯器,可以用HON()宏來轉換成大端格式,如果你的編譯器是大端格式,直接填寫

0x0806即可*/

/*就是簡單的按照協議格式填充,以下同*/

//ARP首部

ARPBUF->hwtype = HON( 1 );

ARPBUF->protocol = HON( 0x0800 );

ARPBUF->hwlen = 6;

ARPBUF->protolen = 4;

ARPBUF->opcode = HON( 1 );

memcpy(ARPBUF->smac, mac_addr, 6);

memcpy(ARPBUF->sipaddr, ip_addr, 4);

memcpy(ARPBUF->dipaddr, host_ip_addr, 4);

packet_len = 42;//14+28=42

sendpacket( Buffer, packet_len );

}

注釋:ARPBUF的宏定義和ARP首部結構,在前面已經講過。同時注意執行該函數時中斷的處理。這里沒

作處理。

    看上去很easy吧,下面函數實現接收ARP請求或接收ARP應答的處理。

unsigned char arp_process(void)//ARP接收函數,成功返回1,否則返回0

{

//簡單判斷ARP數據包有無損壞,有損壞則丟棄,不予處理

if( packet_len < 28 )//ARP數據長度為28字節為無效數據

{

return 0;

}

switch ( HON( ARPBUF->opcode ) )

{

   case 1    : //處理ARP請求

         if( ARPBUF->dipaddr[0] == ip_addr[0] &&

             ARPBUF->dipaddr[1] == ip_addr[1] &&

             ARPBUF->dipaddr[2] == ip_addr[2] &&

             ARPBUF->dipaddr[3] == ip_addr[3] )//判斷是否是自己的IP,是否向自己詢問MAC地址

         { 
             ARPBUF->opcode = HON( 2 );//設置為ARP應答

             memcpy(ARPBUF->dmac, ARPBUF->smac, 6);

             memcpy(ARPBUF->ethhdr.d_mac, ARPBUF->smac, 6);

             memcpy(ARPBUF->smac, mac_addr, 6);

             memcpy(ARPBUF->ethhdr.s_mac, mac_addr, 6);

             memcpy(ARPBUF->dipaddr, ARPBUF->sipaddr, 4);

             memcpy(ARPBUF->sipaddr, ip_addr, 4);

             ARPBUF->ethhdr.type = HON( 0x0806 );

             packet_len = 42;

             sendpacket( Buffer, packet_len );//發送ARP數據包

             return 1;

         }

         else

         {

             return 0;

         }

         break;

   case 2    : //處理ARP應答

         if( ARPBUF->dipaddr[0] == ip_addr[0] &&

             ARPBUF->dipaddr[1] == ip_addr[1] &&

             ARPBUF->dipaddr[2] == ip_addr[2] &&

             ARPBUF->dipaddr[3] == ip_addr[3] )//再次判斷IP,是否是給自己的應答

         {

          memcpy(host_mac_addr, ARPBUF->smac, 6);//保存服務器MAC地址

          return 1;

         }

         else

         {

             return 0;

         }

         break;

default     ://不是ARP協議

         return 0;

}

}

    根據ARP協議格式看這兩個函數並不困難。於是我們又得到兩個函數:arp_request()和

arp_process()。

    3、ARP程序調試

    下面我們修改主函數和中斷處理函數。

    將mian()函數中的“sendpacket(60);”語句換成“arp_request();”語句。

void int_issue(void) //中斷處理函數,需要根據自己的處理器進行設置

{

    unsigned int i;

    i = receivepacket(Buffer);//將數據讀取到Buffer中。

    if(i == 0)

    {

        return;

    }

     else

     {

         i = arp_process();

         if(i == 1)//判斷是否是ARP協議

             print_hostmacaddr();//打印目標機的MAC地址,就是用串口打印host_mac_addr[]中的6

個字節

     }

}

    保存運行調試。 

圖7 主機MAC地址

    至此,關於DM9000的調試過程就完成了。之后我還調試了UDP通訊、TCP通訊等,主要是關於協議的

處理了,這里就不介紹了。有興趣的朋友可以參看《TCP/IP協議》第一卷,將會有很大幫助。希望這些

調試過程能為讀者或多或少的提供些有用的信息,也歡迎大家和我一起討論。

我的Email:

補充:增加了udp實現 http://hi.baidu.com/firstm25/blog/item/d22f3443e373781f73f05d9b.html

 


免責聲明!

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



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