
一、摘要
根据最近一段时间的工作,将DIY_DE2中的网卡DM9000A所涉及到的例程做了调试,接下来几篇博文将循序渐进的阐述这些例程的实现过程,涉及到的具体原理及理论将会另开博文叙述。本篇主要阐述一下调试例程前的准备工作。
二、准备工作
1、网线
经常接触的网线叫双绞线,双绞线有2种,直通线和交叉线,通常又把后者叫做双机互联线。前者用于连接计算机与交换机、HUB等,后者用于连接计算机与计算机,交换机与交换机等。
上图即是交叉线的制作方法,有时别人给制作并不是严格按照上图的对应颜色,但只要RJ-45水晶头满足1和3对调,2和6对调即可。
后续的几篇例程除了用到这种交叉线外,DM9000A自收发的例程还用到另外一种线,这种线也极为简单,只留网线的一边水晶头,另外一头剪掉,对照留下的那头的线序,将剪掉那头的线1和3连接,2和6连接,为了测试连线是否正常,可以将水晶头插入电脑RJ-45里面,若网口灯亮,则说明连接正常。定义该种网线为网线A,交叉线为网线B。
2、Altera不同版本软件的安装
NIOS II中有TCP/IP模板程序,根据Altera不同版本软件,实现TCP/IP所使用的协议栈却不同;低版本(7.2版本以下)使用的是LWIP协议栈,而高版本中摒弃了LWIP协议栈,使用的是NicheStack协议栈,前者不需要授权,而后者需要授权。
后续的几篇博文中,分别实现了LWIP协议栈和NicheStack协议栈,因此需要安装不同版本的Altera软件。Altera的软件,高版本兼容低版本。如果安装了6.0版本的,再安装了9.0版本的,则6.0版本的就不能用了。这里有个处理技巧:
(1)在安装完6.0版本之后,记录一下跟其相关的系统变量。
(2)之后安装9.0版本的软件,记录一下跟其相关的系统变量。
(3)使用9.0的时候,将系统变量的值修改成9.0的即可。
(4)使用6.0的时候,将系统变量的值修改成6.0的即可。
系统变量位置:右击我的电脑——>属性——>高级——>环境变量——>系统变量。
如下是我安装6.0版本软件后的相关的系统变量:
6.0系统变量:
变量名:SOPC_KIT_NIOS2
变量值:c:\\altera\\kits\\nios2_60
变量名:SOPC_BUILDER_PATH_60
变量值:c:\\altera\\kits\\nios2_60
变量名:QESS_ROOTDIR
变量值:C:\\altera\\quartus60
变量名:QUARTUS_ROOTDIR
变量值:C:\\altera\\quartus60
另外,如果下载配置文件的时候提示没有USB-Blaster的话,重新找一下对应版本的驱动即可。一般情况下,配置驱动的情况一次就OK了!
3、硬件平台
这里仍使用的是自己制作的板子DIY_DE2。该系列博文所探讨的难点在于DM9000A的驱动,后续3篇博文中所用到的DM9000A的驱动各不相同,不能混用!
DIY_DE2之DM9000A网卡调试系列例程(二)——DM9000A测试、自收发、实现UDP
一、摘要
通过在SOPC中定制软核,在Quartus II中建立硬件工程,然后在NIOS II中建立3个工程,分别实现DM9000A测试、DM9000A自收发和基于DM9000A的UDP协议的例子。3个例子所使用的DM9000A的驱动是一样的。
二、实验平台
软件平台:Quartus II 9.0 + Nios II 9.0
硬件平台:DIY_DE2
三、实验内容1——>DM9000A测试
通过对DM9000A的初始化,测试DM9000A是否能够正常的初始化,能否正常的运行。该内容不需要使用网线。以下为实现步骤。
1、采用SOPC定制软核
定制软核的详细步骤不再赘述,以上为定制的软核。
cpu_0需要设置的地方:
Reset Vector:cfi_flash_0、
Exception Vector:sram_16bit_512k_0
第二个标签页: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,新建工程,调用一个空的工程模板。
(2)添加DM9000A驱动:dm9000a.h和dm9000a.c,将上述两个文件包括basic_io复制到上步建立的工程文件夹下。见附录。
(3)添加一个新的.c文件,命名为main.c。将下列代码复制到main.c内。
main.c文件
1.#include "basic_io.h"
2.#include "DM9000A.C"
3.int main()
4.{
5. unsigned int a;
6. a=DM9000_init();
7. DM9000_init(); // initialize DM9000 LAN chip //
8. if(!a)
9. {
10. printf("Success");
11.// TransmitPacket(unsigned char *data_ptr,unsigned int tx_len);
12.// ReceivePacket (unsigned char *data_ptr,unsigned int *rx_len);
13. }
14. else
15. printf("Failed");
16.
17.}
(4)编译、下载、运行,之前要先将.sof的配置文件下载到FPGA内。就可以看到RJ-45的黄色的灯和绿色的灯亮了起来。另外,在NIOS II的控制台Console中也能看到输出了 Success 。这时,说明DM9000A能正常运行,且初始化正常。
四、实验内容2——>实现DM9000A自收发
通过DM9000A将数据包发送出去,之后通过中断接收。需要使用到网线A。
不需要改动硬件系统,在上一步的基础上,直接在NOIS II中新建工程,添加main.c文件。
main.c文件内容如下:
1.#include "basic_io.h"
2.#include "DM9000A.C"
3.#include "altera_avalon_pio_regs.h"
4.
5.unsigned int aaa,rx_len,i,packet_num;
6.unsigned char RXT[68] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
7. 0x01,0x60,0x6E,0x11,0x02,0x0F,
8. 0x08,0x00,0x11,0x22,0x33,0x44,
9. 0x55,0x66,0x77,0x88,0x99,0xAA,
10. 0x55,0x66,0x77,0x88,0x99,0xAA,
11. 0x55,0x66,0x77,0x88,0x99,0xAA,
12. 0x55,0x66,0x77,0x88,0x99,0xAA,
13. 0x55,0x66,0x77,0x88,0x99,0xAA,
14. 0x55,0x66,0x77,0x88,0x99,0xAA,
15. 0x55,0x66,0x77,0x88,0x99,0xAA,
16. 0x00,0x00,0x00,0x20 };
17.
18.
19.void ethernet_interrupts()
20.{
21. packet_num++;
22. aaa=ReceivePacket (RXT,&rx_len);
23. if(!aaa)
24. {
25. printf("\\n\\nReceive Packet Length = %d",rx_len);
26. for(i=0;i 28. if(i%8==0) 29. printf("\\n"); 30. printf("0x%2X,",RXT[i]); 31. if(RXT[i] == 0x3f) 32. IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0xff); 33. } 34. } 35.} 36. 37.int main(void) 38.{ 39. unsigned char TXT[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 40. 0x01,0x60,0x6E,0x11,0x02,0x0F, 41. 0x08,0x00,0x11,0x22,0x33,0x44, 42. 0x55,0x66,0x77,0x88,0x99,0xAA, 43. 0x55,0x66,0x77,0x88,0x99,0xAA, 44. 0x55,0x66,0x77,0x88,0x99,0xAA, 45. 0x55,0x66,0x77,0x88,0x99,0xAA, 46. 0x55,0x66,0x77,0x88,0x99,0xAA, 47. 0x55,0x66,0x77,0x88,0x99,0xAA, 48. 0x55,0x66,0x77,0x88,0x99,0xAA, 49. 0x00,0x00,0x00,0x20 }; 50. DM9000_init(); 51. alt_irq_register( DM9000A_IRQ, NULL, (void*)ethernet_interrupts ); 52. packet_num=0; 53. while (1) 54. { 55. TransmitPacket(TXT,0x40); 56. msleep(500); 57. } 58. 59. return 0; 60.} 61.// 62.//------------------------------------------------------------------------- 编译、下载、运行。这时候将网线A插入DIY_DE2开发板的RJ-45,能够看到黄色的灯闪烁,绿色的灯一直亮,另外,在NIOS II控制台也能看到收到的数据。 五、简单UDP协议的实现 DM9000A与PC的简单通信,采用UDP协议,用B网线连接DIY_DE2与PC。FPGA内部产生递增数据,够一个数据包后,通过网络将数据传输给PC,PC也可以通过网络给FPGA发送数据,FPGA则通过中断接收数据。 同样,直接在NOIS II中新建工程,添加main.c文件。 可以使用Wireshark软件来捕捉数据包,并测试其传输速度。经过测试: cpu采用100MHz时, (1)cpu/e:SRAM运行,速度3Mbps; SDRAM运行,50MHz时,速度600Kbps; SDRAM运行,100MHz时,速度1.0Mbps; (2)cpu/f:SRAM运行,速度11Mbps。 main.c文件内容如下: 1.main.c文件 2.#include 3.#include 4.#include 5.#include 6.#include 7.#include "system.h" 8.#include "DM9000A.C" 9.unsigned int aaa,rx_len,i,counter; 10.unsigned char RXT[70]; 11. 12.unsigned int IPsource_1,IPsource_2,IPsource_3,IPsource_4; 13.unsigned int IPdestination_1,IPdestination_2,IPdestination_3,IPdestination_4; 14.unsigned int IPchecksum1,IPchecksum2,IPchecksum3,IPchecksum4,IPchecksum5; 15.unsigned int Mac_source1, Mac_source2, Mac_source3, Mac_source4, Mac_source5, Mac_source6; 16.unsigned int Mac_dest1, Mac_dest2, Mac_dest3, Mac_dest4, Mac_dest5, Mac_dest6; 17.unsigned int times, lenght_h, lenght_l; 18.unsigned int flenght, IPlenght_h, IPlenght_l, data_lenght, IPlenght; 19. 20./* 21.// Next step try to recieve packets. (not available now). 22.void ethernet_interrupts() 23.{ 24. aaa=ReceivePacket (RXT,&rx_len); 25. if(!aaa) 26. { 27. printf("\\n\\nReceive Packet Length = %d",rx_len); 28. for(i=0;i 30. if(i%8==0) 31. printf("\\n"); 32. printf("0x%2X,",RXT[i]); 33. } 34. } 35.} 36.*/ 37.int main(void) 38.{ 39. IPsource_1 = 0xC0; // Assign ie: 192.168.0.44 IP for the DE2 40. IPsource_2 = 0xA8; 41. IPsource_3 = 0x00; 42. IPsource_4 = 0x2C; 43. IPdestination_1 = 0xCA; // Insert your IP data here 44. IPdestination_2 = 0x76; 45. IPdestination_3 = 0xBB; 46. IPdestination_4 = 0x57; 47. Mac_dest1 = 0x00; // Insert your MAC address data here 48. Mac_dest2 = 0x0F; 49. Mac_dest3 = 0xEA; 50. Mac_dest4 = 0xFD; 51. Mac_dest5 = 0x9F; 52. Mac_dest6 = 0x96; 53. Mac_source1 = 0x01; // Assign an MAC address for DE2 54. Mac_source2 = 0x60; 55. Mac_source3 = 0x6E; 56. Mac_source4 = 0x11; 57. Mac_source5 = 0x02; 58. Mac_source6 = 0x0F; 59. 60. data_lenght = 1468; // Maximun Data lenght 1468 bytes 61. 62. flenght = data_lenght + 0x2E; //Total packet lenght 63. lenght_h = ((data_lenght+8) & 0xFF00)>>8; // Convert in H byte and L byte . lenght_l = ((data_lenght+8) & 0x00FF); 65. 66. IPlenght = data_lenght + 8 + 20; // IP Lenght for IP header 67. IPlenght_h = (IPlenght & 0xFF00)>>8; // Convert in H byte and L byte 68. IPlenght_l = (IPlenght & 0x00FF); 69. 70. // Calculating the IP checksum 71. IPchecksum1 = 0x0000C511 + (IPsource_1<<8)+IPsource_2+(IPsource_3<<8)+IPsource_4+ 72. (IPdestination_1<<8)+IPdestination_2+(IPdestination_3<<8)+(IPdestination_4)+ 73. (IPlenght_h<<8) + IPlenght_l; 74. IPchecksum2 = ((IPchecksum1&0x0000FFFF)+(IPchecksum1>>16)); 75. IPchecksum3 = 0x0000FFFF - IPchecksum2; 76. IPchecksum4 = (IPchecksum3 & 0xFF00)>>8; 77. IPchecksum5 = (IPchecksum3 & 0x00FF); 78. 79. unsigned char SND[flenght]; // Payload buffer 80. 81. unsigned char TXT[] = { Mac_dest1, Mac_dest2, Mac_dest3, Mac_dest4 ,Mac_dest5, Mac_dest6, 82. Mac_source1, Mac_source2, Mac_source3, Mac_source4, Mac_source5, Mac_source6, 83. 0x08, 0x00, 0x45, 0x00, IPlenght_h, IPlenght_l, 84. 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 85. IPchecksum4, IPchecksum5, IPsource_1, IPsource_2, IPsource_3, IPsource_4, 86. IPdestination_1, IPdestination_2, IPdestination_3, IPdestination_4, 0x04, 0x00, 87. 0x04, 0x00, lenght_h, lenght_l, 0x00, 0x00}; 88. . for (i = 0; i < 42; i++) // Load the TXT[] in the SND (ethernet packet). 90. SND[i] = TXT[i]; 91. 92. for (i = 42; i < flenght-4; i++) // generating the data to send. 93. SND[i] = i-42; 94. 95. SND[i++] = 0x35; // This checksum is not correct... but also the net recieve the packets correctly. 96. SND[i++] = 0x15; // To do, calculate checksum. 97. SND[i++] = 0xF0; 98. SND[i++] = 0x13; 99. 100. DM9000_init(); // Initialize the DM9000A. 101.// Next step try to recieve packets.(not available now). 102.// alt_irq_register( DM9000A_IRQ, NULL, (void*)ethernet_interrupts ); 103. 104. while (1) 105. { 106. TransmitPacket(SND,flenght); // Send repetitively 1468 bytes of data. 107.// printf("0x%2X,",ior(NSR)); // For check if 10Mbps or 100Mbps active, 0x80 = 10Mbps, 0x40 = 100Mbps. 108.// may happend an RX overflow buffer = 0x42 109.// msleep(500); 110. } 111. return 0; 112.} 113.//--------------------------------------------------------------- 六、说明 UDP属于无连接的通信,这里不必把本机和DE2的IP设置成同一网段,即可完成通信。 DIY_DE2之DM9000A网卡调试系列例程(三)——基于LWIP协议栈的TCP/IP实现 一、摘要 Altera软件NIOS II低版本(7.2版本以下,本例程中使用的是6.0版本)中实现TCP/IP所用的协议栈为LWIP,常用的例程有2个,web_server和simple_socket_server,这篇文章将叙述这2个例程实现的过程。这两个例程参考了友晶科技的DE2_WEB例程。 二、实验平台 软件平台:Quartus II 6.0 + Nios II 6.0 硬件平台:DIY_DE2 三、实验内容1——>实现web_server 1、采用SOPC定制软核 定制软核的详细步骤不再赘述,以上为定制的软核。 cpu_0需要设置的地方: Reset Vector:cfi_flash_0、 Exception Vector:sdram_0 必须要添加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,新建工程,调用web_server工程模板。 (2)添加DM9000A驱动:dm9000a.h和dm9000a.c,将上述两个文件复制到上步建立的工程文件夹下。 (3)打开文件network_utilities.c,赋予静态IP。 (4)编译、下载、运行,之前要先将.sof的配置文件下载到FPGA内。在DOS下输入ping命令:ping 192.168.2.1,如下图所示,则可以正常ping通。 如果事先将网页数据烧录到FLASH中,在PC打开浏览器,则可以在浏览器上看到FLASH中的网页内容。这个实验之前在DE2板子上做过,这里就不再重复了。 4、工程文件解读 (1)http.c、http.h:网页相关文件; (2)Dm9000a.h、dm9000a.c:DM9000A的驱动; (3)User.h:任务调度优先级、缺省IP设置等等; (4)network_utilities.c:设置IP,设置MAC; (5)Web_server:主函数所在文件。 四、实验内容2——>实现simple_socket_server 1、建立工程及文件解读 在上一步的基础上,直接在NIOS II中新建工程,调用simple_socket_server工程模板。添加DM9000A的驱动,将dm9000a.h、dm9000a.c添加到建立的工程文件夹下。工程文件主要包括以下几个: (1)alt_error_handler.h、alt_error_handler.c:错误类型句柄文件; (2)dm9000a.h、dm9000a.c:DM9000A的驱动; (3)network_utilities.c:设置IP,设置MAC; (4)simple_socket_server.h、simple_socket_server.c:工程的主体程序,包括任务调度优先级、缺省IP设置、套接字、各种任务调度等等工作; (5)led.c:LED、七段数码管显示程序; (6)lwip_init.c:程序主函数。 2、需要修改的地方 依照web_server例程,对simple_socket_server例程进行部分修改: (1)simple_socket_server.h文件, 添加分配DHCP优先级:#define DHCP_TMR_PRIO 8 添加语句:void die_with_error(char err_msg[]); 添加DHCP超时任务函数:void dhcp_timeout_task(); 添加语句:#define DIE_WITH_ERROR_BUFFER 256 (2)lwip_init.c文件 添加DM9000A驱动:#include "dm9000.h" 添加DM9000A接口语句:ALTERA_AVALON_DM9K_INSTANCE(DM9000A, dm9k); 添加语句:OS_EVENT *attained_ip_address_sem; 在static void init_done_func(void *arg)添加以下语句: //++sunev ALTERA_AVALON_DM9K_INIT(dm9k); /* * At this point lwIP has been initialized, but the Ethernet interface has * not; the lwip_devices_init() call does so, adding in MicroC-OS/II * threads for low-level Ethernet MAC interface and TCP protocol timer. */ //++sunev attained_ip_address_sem = OSSemCreate(1); if (!lwip_devices_init(LWIP_RX_ETHER_TASK_PRIORITY)) { alt_lwIPErrorHandler(EXPANDED_DIAGNOSIS_CODE, "[init_done_func] Fatal: lwip_devices_init failed, perhaps ethernet interface."); } //++sunev #if LWIP_DHCP == 1 if(!(IORD(0, 0) & (1<<17))) sys_thread_new(dhcp_timeout_task, NULL, DHCP_TMR_PRIO); /* * If DHCP is enabled, activate a thread for the 120-second long time period * that will set a static IP address if acquisistion via DHCP times out. */ //--sunev /* if (!sys_thread_new(NETUTILSDHCPTimeoutTask, NULL, NETUTILS_DHCP_TIMEOUT_TASK_PRIORITY)) { alt_lwIPErrorHandler(EXPANDED_DIAGNOSIS_CODE, "[init_done_func] Fatal: Can't add NETUTILSDHCPTimeoutTask!"); }*/ (3)将web_server中的network_utilities.c文件直接替换掉simple_socket_server中的network_utilities.c文件。 3、编译、下载、运行 之前要先将.sof的配置文件下载到FPGA内。在DOS下输入ping命令:ping 192.168.2.1,如下图所示,则可以正常ping通。 再输入telnet命令:telnet 192.168.2.1,则得到如下图所示: 在PC键盘输入0-7数字,则DIY_DE2上的8个LED就会相应的亮或者灭。至此,说明,telnet正常。 五、实验结果分析 这个实验结果分析,对上述2个实验内容均为一致。 解读上述程序,在network_utilities.c文件中,可以得知,设置IP的3种方法:第一种,程序设定静态IP;第二种,DHCP获得动态IP;第三种,缺省IP。其优先级及顺序如下: (1)当设定静态IP之后,DHCP能获得一个动态IP,但以设置的静态IP为有效IP。 (2)当未设定静态IP之后,DHCP则不能获得一个动态IP,但过了设定的DHCP超时时间后(以上2个例程中的超时时间为120s),使用的是缺省IP,缺省IP为有效IP。 设定静态IP时,NIOS II 运行结果 未设定静态IP时,需等待2分钟(DHCP超时可在simple_socket_server.h中设定),NIOS II 运行结果 注:可以在network_utilities.c文件中将 #if LWIP_DHCP == 1 *use_dhcp = 1; 中的 *use_dhcp = 1; 设置为 *use_dhcp = 0; 来取消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中原装的器件 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 #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; }
