DIY_DE2之DM9000A網卡調試系列例程(四)——基於NicheStack協議棧的TCP/IP實現


一、摘要

  Altera軟件NIOS II高版本(7.2版本以上,本例程中使用的是9.0版本)中實現TCP/IP所用的協議棧為NicheStack,常用的例程有2個,web_server和simple_socket_server,這篇文章只敘述simple_socket_server例程實現的過程。這里DM9000A的驅動和上篇博文中基於LWIP的驅動不同。

 

二、實驗平台

軟件平台:Quartus II 9.0 + Nios II 9.0

硬件平台:DIY_DE2

 

三、實驗內容——>實現simple_socket_server

1、采用SOPC定制軟核

定制軟核的詳細步驟不再贅述,以上為定制的軟核。

cpu_0需要設置的地方:

Reset Vector:cfi_flash_0、

Exception Vector:sram_16bit_512k_0

必須要添加sys_timer_0,供uC/OS系統所使用

第二個標簽頁:Data Master處,Data Cache設置為None

之后分配地址,分配中斷號,生成即可。

2、硬件電路

采用原理圖的形式,創建頂層文件。

(1)添加生成的軟核;

(2)調用鎖相環IP核;

(3)連線、分配管腳;

(4)編譯、綜合,生成配置文件。

最后原理圖如下圖所示。

需要注意的問題:

(1)軟核程序在SDRAM里面運行,為了使軟核的速度提升,因此SDRAM的頻率和cpu的頻率都設置為100M。cpu時鍾clk_100和sdram操作時鍾clk_50都接PLL的c0,100M,無相位偏移;SDRAM的時鍾管腳SDRAM_CLK連接PLL的c1,100M,偏移-3ns。

(2)DM9000A的時鍾管腳接50M,直接連接晶振的輸入端即可。

(3)復位管腳接高電平VCC即可。

(4)CFI_FLASH的復位管腳FLASH_RESET接高電平VCC即可。

3、軟件方面

(1)打開NIOS II,新建工程,調用simple_socket_server工程模板。

(2)添加DM9000A驅動:dm9000a.h和dm9000a.c,將上述兩個文件復制到上步建立的工程文件夾下。

(3)打開network_utilities.c文件,將附錄代碼覆蓋原始代碼,這里采用的是使用靜態IP的方法(IP的值將在后面給出說明),並且賦給MAC值。

(4)打開iniche_init.c文件,

添加頭文件#include"dm9000a.h",

添加DM9000A接口語句DM9000A_INSTANCE(DM9000A_0, dm9000a_0);

在函數void SSSInitialTask(void *task_data)中,

添加DM9000A的初始化語句DM9000A_INIT(DM9000A_0, dm9000a_0);

(5)編譯、下載、運行,之前要先將.sof的配置文件下載到FPGA內。在DOS下輸入ping命令:ping 192.168.2.1,如下圖所示,則可以正常ping通。

再輸入telnet命令:telnet 192.168.2.1,則得到如下圖所示:

在PC鍵盤輸入0-7數字,則DIY_DE2上的8個LED就會相應的亮或者滅。至此,說明,telnet正常。

4、工程文件解讀

(1)alt_error_handler.h、alt_error_handler.c:錯誤類型句柄文件;

(2)dm9000a_regs.h、dm9000a.h、dm9000a.c:DM9000A的驅動;

(3)network_utilities.h、network_utilities.c:設置IP,設置MAC;

(4)simple_socket_server.h、simple_socket_server.c:工程的主體程序,包括任務調度優先級、缺省IP設置、套接字、各種任務調度等等工作;

(5)led.c:LED、七段數碼管顯示程序;

(6)iniche_init.c:程序主函數。

 

四、實驗結果分析

NIOS II運行結果:

稍過2分鍾后,得到如下結果:

  實驗現象,程序一開始運行,先賦給靜態IP,這時候ping能夠跑通,但telnet卻不能跑通。稍過2分鍾之后(這個默認時間在LWIP協議棧實現的時候可以調整,但在NicheStack協議棧中不能調整,至少在工程文件里是這樣),出現上面第二幅結果圖的時候,能夠ping正常,telnet正常。

  分析可得,雖賦予靜態IP,但是系統仍是先通過DHCP獲取IP,獲取超時,使用缺省IP,缺省IP的設置在simple_socket_server.h中。而真正能夠ping正常,telnet正常的卻是事先賦予的靜態IP。

 

注:取消DHCP的方法同上一篇博文。

 

五、實驗的幾點說明

1、IP值設置:

  因為是采用局域網通信,所以要將PC和DIY_DE2的IP的前3位設置為相同,最后一位不同。

2、MAC值設置:

  直接采用程序設定即可,或者是將MAC值存儲在FLASH中,上電讀取即可。本例采用的是前一種方法。

3、端口設定:

  telnet的時候,需要偵聽端口,當偵聽的端口號和DIY_DE2中設定的相同的時候,才能正常通信。方法:telnet 192.168.2.1時,會有一個專用的端口23,將DIY_DE2中設定的端口號改為23即可(在文件simple_socket_server.h中#define SSS_PORT 23)。

4、關於這個例程在NIOS II方面:

  關於Software Components這個按鈕下Lightweight TCP/IP Stack下選項為灰色的原因,其實這個不必理他。這一點也得到了友晶科技的證實。如果用LAN91c111這個網卡,上述位置的選項則可以正常使用,這說明NIOS II軟件只認SOPC中原裝的器件。

 

 

 

附錄:

network_utilities.c文件

 

#include <alt_types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <sys/alt_flash.h>
#include "includes.h"
#include "io.h"
#include "simple_socket_server.h"
 
#include <alt_iniche_dev.h>
 
#include "ipport.h"
#include "tcpport.h"
#include "network_utilities.h"
 
#define IP4_ADDR(ipaddr, a,b,c,d) ipaddr = \
    htonl((((alt_u32)(a & 0xff) << 24) | ((alt_u32)(b & 0xff) << 16) | \
          ((alt_u32)(c & 0xff) << 8) | (alt_u32)(d & 0xff)))
 
/*
* get_mac_addr
*
* Read the MAC address in a board specific way
*
*/
static unsigned char macaddr[6] = { 0x00, 0x07, 0xed, 0xff, 0x06, 0x00 };
 
int get_mac_addr(NET net, unsigned char mac_addr[6])
{
  int rv = -1;
 
  /* first 3 bytes are altera's vendor id */
  /* last 3 bytes are picked from serial number sticker */
  mac_addr[0] = macaddr[0];
  mac_addr[1] = macaddr[1];
  mac_addr[2] = macaddr[2];
  mac_addr[3] = macaddr[3];
  mac_addr[4] = macaddr[4];
  mac_addr[5] = macaddr[5];
 
  /* return the mac address in the array */
  rv = 0;
 
  return rv;
}
 
/*
 * get_ip_addr()
 *
 * This routine is called by InterNiche to obtain an IP address for the
 * specified network adapter. Like the MAC address, obtaining an IP address is
 * very system-dependant and therefore this function is exported for the
 * developer to control.
 *
 * In our system, we are either attempting DHCP auto-negotiation of IP address,
 * or we are setting our own static IP, Gateway, and Subnet Mask addresses our
 * self. This routine is where that happens.
 */
int get_ip_addr(alt_iniche_dev *p_dev,
                ip_addr* ipaddr,
                ip_addr* netmask,
                ip_addr* gw,
                int* use_dhcp)
{
 
    IP4_ADDR(*ipaddr, 192, 168, 2, 1);
    IP4_ADDR(*gw, 192, 168, 2, 1);
    IP4_ADDR(*netmask, 255, 255, 255, 0);
 
#ifdef DHCP_CLIENT
    *use_dhcp = 1;
#else /* not DHCP_CLIENT */
    *use_dhcp = 0;
 
    printf("Static IP Address is %d.%d.%d.%d\n",
        ip4_addr1(*ipaddr),
        ip4_addr2(*ipaddr),
        ip4_addr3(*ipaddr),
        ip4_addr4(*ipaddr));
#endif /* not DHCP_CLIENT */
 
    /* Non-standard API: return 1 for success */
    return 1;
}
 

 

 

 

 

 


免責聲明!

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



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