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 定制软核

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

定制软核的详细步骤不再赘述,以上为定制的软核。

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)编译、综合,生成配置文件。

最后原理图如下图所示。

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

需要注意的问题:

(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 通。

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

再输入 telnet 命令:telnet 192.168.2.1,则得到如下图所示:

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

在 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 运行结果:

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

稍过 2 分钟后,得到如下结果:

DIY_DE2之DM9000A网卡调试系列例程(四)——基于NicheStack协议栈的TCP/IP实现

实验现象,程序一开始运行,先赋给静态 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 #include #include #include #include #include "includes.h"
#include "io.h"
#include "simple_socket_server.h"
 
#include  
#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;
}

 

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/23.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2012年3月13日 23:25
下一篇 2012年3月15日 23:21

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注