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 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 udelay(20); tem = DM_CMD; datas[i] = tem & 0x0ff; datas[i + 1] = (tem >> 8) & 0x0ff; } } else { } /*以上接收數據包,注意的地方與發送數據包的地方相同*/ if(len > 1000) return 0; if( (HON( ETHBUF->type ) != ETHTYPE_ARP) && (HON( ETHBUF->type ) != ETHTYPE_IP) ) { return 0; } packet_len = len; /*以上對接收到的數據包作一些必要的限制,去除大數據包,去除非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首部結構
return 0;
return HON( ETHBUF->type ); //返回數據包的類型,這里只選擇是ARP或IP兩種類型
上一篇:用 S5PV210 學習 Linux (三) SD卡下載
下一篇:s5pv210移植Minigui3.0.12
推薦閱讀最新更新時間:2025-04-24 09:30




設計資源 培訓 開發板 精華推薦
- 用于 DSL 調制解調器的模擬放大器
- VM801P50A-PL,FT801 顯示系統的嵌入式視頻引擎 Plus 開發模塊,ATMEG328P at 5V/16MHz,Micro-SD 插座,5.0 - 480x272 分辨率 TFT LCD,帶電容式觸摸屏,珍珠殼
- 使用 Infineon Technologies AG 的 OMR9602SF 的參考設計
- SG1843交直流開關轉換器典型應用電路
- 具有關斷功能的 LT1086IT-5 5V 穩壓器的典型應用
- 3.3V DC 至 DC 單路輸出手機電源
- 具有短路保護功能的 MC78M15ABDTRKG 15V 電流提升的典型應用
- AM6TW-2415SH35Z 15V 6瓦雙輸出DC-DC轉換器的典型應用
- 全球首款ARM核航空航天級芯片,SAMRH71F20-EK 評估套件(原理圖等)
- ADP222ACPZ 300mA 雙路輸出、低噪聲、高 PSRR 穩壓器的典型應用