搜索
bottom↓
回复: 0

【正点原子FPGA连载】第三十五章基于lwip的tftp server实验--摘自【正点原子】领航者 ZYNQ 之嵌入式开发指南

[复制链接]

出0入234汤圆

发表于 2020-8-19 16:57:32 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-24 11:01 编辑

1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
4)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
QQ群头像.png
5)关注正点原子公众号,获取最新资料


100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第三十五章基于lwip的tftp server实验


文件传输是网络环境中的一项基本应用,其作用是将一台电子设备中的文件传输到另一台可能相距很远的电子设备中。TFTP作为TCP/IP协议族中的一个用来在客户机与服务器之间进行文件传输的协议,常用于无盘工作站、路由器以及远程测控设备从主机上获取引导配置文件,实现远程升级。由于TFTP简单且易实现,本实验我们使用lwip协议栈实现TFTP Server的功能。本章包括以下几个部分:
3535.1简介
35.2实验任务
35.3硬件设计
35.4软件设计
35.5下载验证


35.1简介
一、TFTP简介(基于RFC1350版本)
简单文件传输协议TFTP (Trivial File Transfer Protocol) 是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输,基于UDP实现的应用层协议,提供不复杂、开销不大的文件传输服务,端口号为 69。为了保证文件可靠传输TFTP有自己的差错改正措施。TFTP 只支持文件传输、不支持交互、没有庞大的命令集,也没有目录列表功能,以及不能对用户进行身份鉴别。
与常用的文件传送协议 FTP (File Transfer Protocol) 相比,FTP基于TCP协议,提供交互式的访问,允许客户指明文件的类型与格式、允许执行对目录和文件的访问,并且可以完成特定类型的目录操作以及需要进行身份验证。
可以说FTP是完整的、面向会话、常规用途的文件传输协议,而TFTP相当于用作特殊目的简化版的FTP。
TFTP的主要优点有两个。
第一,TFTP可用于UDP环境。例如,当需要将程序或文件同时向许多机器下载时就往往需要使用TFTP。
第二,TFTP代码所占的内存较小。这对较小的计算机或某些特殊用途的设备(如无盘工作站等)是很重要的。这些设备不需要硬盘,只需要固化了TFTP、UDP和IP的小容量只读存储器即可。当接通电源后,设备执行只读存储器中的代码,在网络上广播一个TFTP请求。网络上的TFTP服务器就发送响应,其中包括可执行二进制程序。设备收到此文件后将其放入内存,然后开始运行程序。这种方式增加了灵活性,也减少了开销。
TFTP的主要特点如下:
(1)每次传送的数据报文中有512字节的数据,但最后一次可不足512字节。
(2)数据报文按序编号,从1开始。
(3)支持ASCII码或二进制传送。
(4)可对文件进行读或写。
(5)使用很简单的首部。
(6)实现简单而不是高的系统吞吐量
二、TFTP的五种报文
TFTP的报文格式如图 35.1.1所示,可以看到TFTP有五种报文,每种报文有不同的操作码,这五种报文分别是:RRQ、WRQ、DATA、ACK和ERROR报文。下面我们简单的介绍下这五种报文。
RRQ/WRQ报文
模式字段中,包含两种字符串中的一种,"netascii"表示ASCII文件,"octet"表示二进制文件。对于RRQ,客户向TFTP服务器发送读请求后,服务器返回一个块编号为1的DATA报文。而对于WRQ,客户向TFTP服务器发送写请求后,服务器返回的是块编号为1的ACK报文。总之,不管是RRQ还是WRQ,接收DATA数据的一方发送ACK确认,而发送DATA数据的一方只负责发送数据。
阿莫论坛发帖领航者专用11388.png

图 35.1.1 TFTP报文格式

a)DATA报文
发送方用于传送数据块。所有的块都用数字顺序编码,从1开始。在所有的DATA报文中,这个块必须准确地等于512Byte,但最后一个块可以小于或等于512Byte。当发送的DATA报文中数据部分的长度小于512Byte,表示DATA报文发送完毕,所以小于数据部分512Byte的DATA数据报可以作为文件结束的标志。特殊的情况是,当文件中的数据正好是512Byte的整数倍时,那么发送端必须再发送一个具有数据部分为0Byte的额外的DATA数据块以表示传输的结束。数据可以采用ASCII码或二进制来传送。
b)ACK报文
块号表示它所收到的块号(不是下一个期待的块号,这与TCP中的ACK序号不同)。特殊情况是,当客户向服务器发送一个WRQ请求后,服务器返回给客户的是一个块号为0的ACK报文,表示服务器已经准备好了接收来自客户的数据报。
c)EEROR报文(差错报文)
ERROR报文既可以由客户发送,也可以由服务器发送,当一条连接(如读连接或写连接)不能建立或在数据传输中出现问题时使用。差错码定义了差错的类型,差错信息是一个可变字节,包含原文中的差错数据。
从上面的报文格式中可以看出,TFTP报文没有差错检验和字段,所以接收端检验数据是否出现差错的唯一方法是通过该TFTP数据报的UDP首部中的检验和字段。
三、TFTP传输过程
以TFTP客户端向 TFTP 服务器发送写请求为例,说明整个过程。
1)服务器使用默认端口号69被动打开连接;
2)客户主动打开连接,向服务器进程发送WRQ报文,报文中包含写入文件的文件名;
3)TFTP服务器进程选择一个新的端口和TFTP客户进程进行通信,并向TFTP客户进程发送块编号为0的的ACK报文;
4)客户端收到服务器的ACK报文后发送DATA报文,数据段为512Byte,少于512Byte表明是文件的最后的数据,块编号逐次递增;
5)TFTP服务器校验收到的DATA报文的块编号,如果校验正确则将数据写入文件,并发送ACK报文表明已接收到数据,ACK报文的块编号为本次接收的DATA报文的块编号。另外还判断数据段长度是否小于512 Byte,小于则表明文件传输完成,关闭连接,如果等于512Byte,则重复步骤4-5,直到所有请求的数据发送完毕。
从上面的传输过程可以看出,TFTP 是一种类似于停止等待协议(不是真正的停止等待协议,在停止等待协议中,接收方发送的 ack 表示期望收到的下一个分组,而在 TFTP 的 ACK 报文中,ACK的块号表示的是本次成功收到的数据块,而不是下一个期望的下一个数据块)。TFTP 客户端只有收到服务器的确认报文ACK后才会接着向服务器发送新的数据。
另外需要注意的是TFTP 协议中,用于读文件的连接和用于写文件的连接的建立方式不同:建立读连接的时候,客户首先向服务器发送 RRQ 读报文,服务器收到该报文后,直接发回给该客户 DATA 报文,并且包含第一个数据块(块号为 1)。而建立写连接的时候,客户首先先服务器发送 WRQ 写报文,服务器收到该报文后,则发回给客户 ACK 报文,使用的块号为 0;当然上面两种情况如果遇到请求报文出错时,均会发回 ERROR 报文作为响应。
35.2实验任务
本章的实验任务是使用LWIP协议栈搭建TFTP服务器,PC电脑上的客户端可以从TFTP服务器读取文件也可向TFTP服务器写入文件,文件存放在SD卡中。
35.3硬件设计
根据实验任务我们可以画出本次实验的系统框图,如下图所示:
阿莫论坛发帖领航者专用12920.png

图 35.3.1 系统框图

在图 5.3.1中,UART用于打印程序相关的信息,LWIP通过以太网传输数据,SD用于存放文件,包括服务器创建的文件和客户端写入的文件。
step1:创建Vivado工程
本次实验的硬件设计可以在《LWIP echo server》实验的基础上添加SD卡。
1-1 我们先打开《LWIP echo server》实验的Vivado工程,打开后将工程另存为 “lwip_tftp_server”工程,然后点击“OK”按钮。
step2:使用IP Integrator创建Processing System
2-1 在Vivado界面左侧的Flow Navigator中,点击IP INTEGRATOR下的Open Block Design以打开Diagram窗口。
2-2 在打开的下图Diagram窗口,双击打开ZYNQ7 Processing System重定义窗口。
阿莫论坛发帖领航者专用13407.png

图 35.3.2 重定义ZYNQ7 Processing System

2-3 在下图所示的重定义窗口,如同《SD卡读写TXT文本实验》那样配置SD卡。点击左侧的MIO Configuration,在右侧的界面中展开“I/O Peripherals”,勾选“SD 0”,在“IO”列选择SD 0的IO为“MIO40…45”,如下图所示。
阿莫论坛发帖领航者专用13621.png

图 35.3.3 PS以太网接口配置界面

2-4 由于不需要添加其它IP,按Ctrl+S快捷键保存Diagram。此时我们的第二步完成,进入第三步
step3:生成顶层HDL
在sources面板中,右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。
step4:生成Bitstream文件并导出到SDK
由于本实验未用到PL部分,所以无需生成Bitstream文件,只需导出到SDK即可。如果使用到PL,则需要添加引脚约束以及对该系统进行综合、实现并生成Bitstream文件。
4-1 导出硬件。
在菜单栏中选择 File > Export > Export hardware。
并在弹出的对话框中,取消勾选“Include bitstream”,直接点击“OK”按钮。
因为是在前一工程的基础上建立的,还保留着前一工程的结果,所以会弹出“Module Already Exported”对话框,我们点击“Yes”按钮。
4-2 硬件导出完成后,选择菜单File->Launch SDK,启动SDK开发环境。
35.4软件设计
下面步骤操作比较麻烦,实际意义也不大,可以直接使用我们提供的例程里的SDK软件工程。
此处我们删除《LWIP echo server》实验的应用工程,保留bsp工程。下面我们开始第五步——创建应用工程。下面我们开始第五步——创建应用工程
step5:在SDK中创建应用工程
5-1在菜单栏中选择“File->New->Application Project”,
在弹出的界面中,输入工程名“lwip_tftp_server”,然后选择“Next >”,在下一界面选择“Empty Application”,然后点击“Finish”按钮。
5-2 在Project Explorer中,鼠标右键点击“lwip_tftp_server _bsp”,在弹出的菜单中选择“Board Support Package Settings”,如下图所示:
弹出对BSP的设置界面,勾选“lwip202”和“xilffs”以启用lwip和文件系统,如图 35.4.1所示。
如果没有开启DHCP服务可以开启DHCP服务,点击standalone下的lwip202,在右侧界面中到“dhcp_options”,将其下的两个选项的“Value”设置为“true”,如图 35.4.2所示。
阿莫论坛发帖领航者专用14806.png

图 35.4.1 BSP的设置界面


图 35.4.2 开启DHCP
5-3 由于Xilinx提供的lwip例程里有TFTP server的源代码,所以我们无需自己手动编写,直接添加即可。
双击打开“lwip_tftp_server”目录下的system.mss文件。在system.mss文件的底部单击“Import Example”,如下图所示。
阿莫论坛发帖领航者专用14869.png

图 35.4.3 Import lwip Example

5-4 在弹出的下图所示界面中,点击下方的“Examples Directory”。
阿莫论坛发帖领航者专用15071.png

图 35.4.4 platform_config.h文件内容

5-5 打开例程所在文件的目录,里面有Xilinx关于lwip的全部例程源文件。我们选择本次实验需要的源文件,如图 35.4.6所示,并单击鼠标右键选择复制。复制完成后,在打开的图 35.4.5界面中,点击“Cancel”退出。
阿莫论坛发帖领航者专用15189.png

图 35.4.6 例程所在文件的目录

5-6 单击SDK软件的lwip_tftp_server/src目录,按下粘贴快捷键“Ctrl-v”,将复制的文件粘贴到该src目录下,如下图所示。
阿莫论坛发帖领航者专用15448.png

图 35.4.7 src目录

5-7 为了方便分析,我们将刚才复制到src目录的源文件重命名,主要是删除不需要的前缀,其中“lwip_example_tftpserver_common.h”改为“lwip_tftp_server.h”,如下图所示:
阿莫论坛发帖领航者专用15587.png

图 35.4.8 删除不相关文件后的src文件夹内容

5-8 修复错误。
由于重命名了“lwip_example_tftpserver_common.h”,所以需要将lwip_tftp_server.c源文件的 #include "lwip_tftpserver_common.h"修改为#include "lwip_tftp_server.h",如下图所示:
阿莫论坛发帖领航者专用15983.png

图 35.4.9 修改为#include "lwip_tftp_server.h"

此处为了方便显示,将其注释,实际在文件内直接修改第34行即可。
打开platform_fs.c源文件,添加BYTE work[FF_MAX_SS](第9行),修改f_mkfs函数的调用,第15行,修改后的内容如下:
  1. 1  #include "ff.h"
  2. 2  #include "xil_printf.h"
  3. 3  
  4. 4  int platform_init_fs()
  5. 5  {
  6. 6      static FATFS fatfs;
  7. 7      FRESULT Res;
  8. 8      TCHAR *Path = "0:/";
  9. 9      BYTE work[FF_MAX_SS];
  10. 10
  11. 11     /* Try to mount FAT file system */
  12. 12     Res = f_mount(&fatfs, Path, 1);
  13. 13     if (Res != FR_OK) {
  14. 14         xil_printf("Volume is not FAT formated; formating FAT\r\n");
  15. 15         Res = f_mkfs(Path, FM_FAT32, 0, work, sizeof work);
  16. 16         if (Res != FR_OK) {
  17. 17             xil_printf("Unable to format FATfs\r\n");
  18. 18             return -1;
  19. 19         }
  20. 20
  21. 21         Res = f_mount(&fatfs, Path, 1);
  22. 22         if (Res != FR_OK) {
  23. 23             xil_printf("Unable to mount FATfs\r\n");
  24. 24             return -1;
  25. 25         }
  26. 26     }
  27. 27     xil_printf("File system initialization successful\r\n");
  28. 28
  29. 29     return 0;
  30. 30 }
复制代码

该文件在初始化平台时由init_platform函数调用,用于挂载SD卡,挂载不成功就将SD卡格式化成FAT32,格式化成功后再尝试挂载。
5-9 现在我们打开main.c文件,为了方便分析源代码,在main.c文件中将带有下图箭头所指的预编译指令删除。
阿莫论坛发帖领航者专用17137.png

图 35.4.10 删除不需要的预编译指令

删除不适用的预编译指令后的main.c代码与我们《lwip echo server实验》的main.c代码基本相同,区别在于本次TFTP server实验没有使用IPv6,所以没有IPv6的预编译指令,其他完全相同,main.c代码讲解见《lwip echo server实验》。
5-10本实验可以说是在《lwip echo server实验》的基础上增加了文件系统,然后将Echo server的实现文件echo.c文件改写成了TFTP Server的实现文件。因而本实验的主要代码是TFTP Server的实现,该实现在lwip_tftp_server.h和lwip_tftp_server.c中,由于这两个文件的总代码有近500行,因此我们挑选部分代码进行讲解。此处以客户端写文件为例讲解lwip_tftp_server.c中的写文件实现源码。讲解以函数调用顺序进行。
首先我们看main函数中调用的start_application函数,该函数实现如下:
  1. 342 void start_application()
  2. 343 {
  3. 344     struct udp_pcb *pcb;
  4. 345     err_t err;
  5. 346
  6. 347     //创建测试文件用于客户端读取
  7. 348     err = tftp_create_test_file();
  8. 349     if (err) {
  9. 350         xil_printf("Unable to create test file\r\n");
  10. 351         return;
  11. 352     }
  12. 353
  13. 354     //创建新的UDP PCB
  14. 355     pcb = udp_new();
  15. 356     if (!pcb) {
  16. 357         xil_printf("Error creating PCB. Out of Memory\r\n");
  17. 358         return;
  18. 359     }
  19. 360
  20. 361     //绑定端口
  21. 362     err = udp_bind(pcb, IP_ADDR_ANY, TFTP_PORT);
  22. 363     if (err != ERR_OK) {
  23. 364         xil_printf("Unable to bind to port %d; err %d\r\n",
  24. 365                 TFTP_PORT, err);
  25. 366         udp_remove(pcb);
  26. 367         return;
  27. 368     }
  28. 369     //设置接收回调函数
  29. 370     udp_recv(pcb, (udp_recv_fn) tftp_server_recv_cb, NULL);
  30. 371 }
复制代码

可以看到该函数首先通过调用tftp_create_test_file函数创建了测试文件,用于tftp客户端读取tftp服务器的文件数据,测试文件名为sample#.txt,其中“#”为数字1、2、3中的任一值,其文件内容为“----- This is a test file for TFTP server application -----”。如果不执行客户端的读取文件请求,可删除该函数的调用及其实现。
由于TFTP基于UDP协议,从start_application函数可以看到lwip中使用UDP协议很简单。首先通过udp_new函数创建一个新的UDP PCB,然后调用udp_bind函数绑定端口号,IP_ADDR_ANY表明为任意本地地址,TFTP_PORT是在lwip_tftp_server.h宏定义的端口号,其值为69,即TFTP的默认端口。最后调用udp_recv函数设置接收回调函数就完成了UDP服务的创建,服务端的功能几TFTP协议由回调函数实现。回调函数代码如下:
  1. 260 //UDP接收回调函数
  2. 261 static void tftp_server_recv_cb(void *arg, struct udp_pcb *upcb, struct pbuf *p,
  3. 262         ip_addr_t *ip, u16_t port)
  4. 263 {
  5. 264     tftp_opcode op = tftp_get_opcode(p->payload);
  6. 265     char fname[512];
  7. 266     struct udp_pcb *pcb;
  8. 267     err_t err;
  9. 268
  10. 269     pcb = udp_new();
  11. 270     if (!pcb) {
  12. 271         xil_printf("Error creating PCB. Out of Memory\r\n");
  13. 272         goto cleanup;
  14. 273     }
  15. 274
  16. 275     //绑定到端口0以接收下一个可用的空闲端口
  17. 276     err = udp_bind(pcb, IP_ADDR_ANY, 0);
  18. 277     if (err != ERR_OK) {
  19. 278         xil_printf("Unable to bind to port %d; err %d\r\n", port, err);
  20. 279         goto cleanup;
  21. 280     }
  22. 281
  23. 282     switch (op) {
  24. 283     case TFTP_RRQ:
  25. 284         //从payload中获取文件名
  26. 285         strcpy(fname, p->payload + FIL_NAME_OFFSET);
  27. 286         printf("TFTP RRQ (read request): %s\r\n", fname);
  28. 287         tftp_process_read(pcb, ip, port, fname);
  29. 288         break;
  30. 289     case TFTP_WRQ:
  31. 290         strcpy(fname, p->payload + FIL_NAME_OFFSET);
  32. 291         printf("TFTP WRQ (write request): %s\r\n", fname);
  33. 292         tftp_process_write(pcb, ip, port, fname);
  34. 293         break;
  35. 294     default:
  36. 295         //发送访问冲突消息
  37. 296         tftp_send_error_packet(pcb, ip, port, TFTP_ERR_ILLEGALOP);
  38. 297         printf("TFTP unknown request op: %d\r\n\r\n", op);
  39. 298         udp_remove(pcb);
  40. 299         break;
  41. 300     }
  42. 301
  43. 302 cleanup:
  44. 303     pbuf_free(p);
  45. 304 }
复制代码

当TFTP客户端发起写入或读取文件的请求后,lwip协议栈调用回调函数tftp_server_recv_cb。该回调函数通过tftp_get_opcode宏获取客户端发送报文的操作码,不同的操作码执行该函数switch分支中的不同的case,如对于写入文件请求,则执行“case TFTP_WRQ”分支语句,该分支语句调用TFTP处理写文件请求函数tftp_process_write,该函数实现如下:
  1. 223 //TFTP处理写文件请求
  2. 224 static int tftp_process_write(struct udp_pcb *pcb, ip_addr_t *ip, int port,
  3. 225         char *fname)
  4. 226 {
  5. 227     tftp_connection_args *conn;
  6. 228     FIL w_fil;
  7. 229     FRESULT Res;
  8. 230
  9. 231     Res = f_open(&w_fil, fname, FA_CREATE_ALWAYS | FA_WRITE);
  10. 232     if (Res) {
  11. 233         xil_printf("Unable to open file %s for writing %d\r\n", fname,
  12. 234                Res);
  13. 235         tftp_send_error_packet(pcb, ip, port, TFTP_ERR_DISKFULL);
  14. 236         udp_remove(pcb);
  15. 237         return -1;
  16. 238     }
  17. 239
  18. 240     conn = mem_malloc(sizeof *conn);
  19. 241     if (!conn) {
  20. 242         xil_printf("Unable to allocate memory for tftp conn\r\n");
  21. 243         tftp_send_error_packet(pcb, ip, port, TFTP_ERR_DISKFULL);
  22. 244         udp_remove(pcb);
  23. 245         return -1;
  24. 246     }
  25. 247
  26. 248     memcpy(&conn->fil, &w_fil, sizeof(w_fil));
  27. 249     conn->block = 0;
  28. 250
  29. 251     //为该pcb设置接收回调
  30. 252     udp_recv(pcb, (udp_recv_fn) tftp_server_write_req_recv_cb, conn);
  31. 253
  32. 254     //通过发送第一个ACK来启动传输
  33. 255     tftp_send_ack_packet(pcb, ip, port, conn->block);
  34. 256
  35. 257     return 0;
  36. 258 }
复制代码

该函数首先在文件系统中创建一个文件,文件名为客户端写入的文件名,然后为新创建的UDP PCB设置接收回调函数,用于处理后面接收客户端传入的文件,最后发送块编号为0的ACK报文以应答客户端启动传输。TFTP写入请求的接收回调函数实现如下:
  1. 181 //TFTP写入请求的接收回调函数
  2. 182 static void tftp_server_write_req_recv_cb(void *_args, struct udp_pcb *upcb,
  3. 183         struct pbuf *p, ip_addr_t *addr, u16_t port)
  4. 184 {
  5. 185     ip_addr_t ip = *addr;
  6. 186     tftp_connection_args *args = (tftp_connection_args *)_args;
  7. 187
  8. 188     if (p->len != p->tot_len) {
  9. 189         xil_printf("TFTP_WRQ: Tftp server does not support "
  10. 190                 "chained pbufs\r\n");
  11. 191         pbuf_free(p);
  12. 192         return;
  13. 193     }
  14. 194
  15. 195     //确保数据块是我们所期望的
  16. 196     if ((p->len >= TFTP_PACKET_HDR_LEN) &&
  17. 197         (tftp_get_block_value(p->payload) == (u16_t) (args->block + 1))) {
  18. 198         //将接收的数据写入文件
  19. 199         unsigned int n;
  20. 200         f_write(&args->fil, p->payload + TFTP_PACKET_HDR_LEN,
  21. 201                 p->len - TFTP_PACKET_HDR_LEN, &n);
  22. 202         if (n != p->len - TFTP_PACKET_HDR_LEN) {
  23. 203             xil_printf("TFTP_WRQ: Write to file error\r\n");
  24. 204             tftp_send_error_packet(upcb, &ip, port,
  25. 205                         TFTP_ERR_DISKFULL);
  26. 206             pbuf_free(p);
  27. 207             return tftp_cleanup(upcb, args);
  28. 208         }
  29. 209         args->block++;
  30. 210     }
  31. 211
  32. 212     tftp_send_ack_packet(upcb, &ip, port, args->block);
  33. 213
  34. 214     //如果接收到的数据段长度小于指定的字节数,则表明已经接收了整个文件,因此可以退出
  35. 215     if (p->len < TFTP_DATA_PACKET_MSG_LEN) {
  36. 216         xil_printf("TFTP_WRQ: Transfer completed\r\n\r\n");
  37. 217         return tftp_cleanup(upcb, args);
  38. 218     }
  39. 219
  40. 220     pbuf_free(p);
  41. 221 }
复制代码

从该回调函数可以看到,TFTP服务端对客户端发送的数据报文的块编号进行校验,如果不是我们期望的块编号就重发上一次发送的ACK报文,如果是期望的块编号,就将数据写入文件中,然后递增块编号,并发送ACK报文给客户端以确认收到数据。
在该函数的最后判断接收到的数据段长度是否小于指定的字节数TFTP_DATA_PACKET_MSG_LEN,如果是,则表明已经接收了整个文件,因此可以结束连接。TFTP_DATA_PACKET_MSG_LEN在lwip_tftp_server.h宏定义为512。
以上大概的讲解了TFTP Server接收客户端写入文件的实现。下面我们进行实际操作,看看TFTP客户端是否能向服务器写入文件。
35.5下载验证
首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将USB UART接口与电脑连接,用于串口通信。使用网线一端连接领航者开发板的以太网接口,另一端与电脑或路由器连接。连接完成后,在开发板上插入SD 卡或者插入带卡套(适配器)的 TF 卡(SD 卡插槽位于开发板背面)。最后连接开发板的电源,并打开电源开关。如下图所示:
阿莫论坛发帖领航者专用113658.png

图 35.5.1领航者ZYNQ开发板实物图

现在进入最后一步。
step6:板级验证
6-1 在SDK软件的下方的SDK Terminal窗口中点击右上角的加号连接串口。
6-2 下载程序。下载完成后,可以看到串口打印的结果如下:
阿莫论坛发帖领航者专用113819.png

图 35.5.2 显示打印结果

其中“File system initialization successful”表明SD卡可以正常工作。打印的最后一句表明了该实验如何使用。由于是TFTP服务器实验,所以我们需要TFTP客户端,可以从网上下载,也可以使用Windows系统的CMD命令行界面,如果开启了TFTP客户端,开启方法见步骤6-6。
6-3 下面我们先创建一个文件用来传输到TFTP服务器。文件存放位置任意,文件内容任意。
我们在Vivado工程目录新建一个名为“test”的文件夹,里面新建一个名为testfile.txt的文件,文件内容为“这只是一个测试文件。”,如下图所示:
阿莫论坛发帖领航者专用114159.png

图 35.5.3 新建一个名为test_file.txt的文件

6-4 我们打开电脑的CMD(按win+r键后输入cmd),然后输入命令“cd /D F:\ZYNQ\Embedded_System\lwip_tftp_server\test”切换到 “F:\ZYNQ\Embedded_System\lwip_tftp_server\test”目录下,如下图所示:
阿莫论坛发帖领航者专用114388.png

图 35.5.4 切换到上传文件所在的目录

然后输入“tftp -i 192.168.1.10 PUT testfile.txt”命令,回车,会显示传输成功字样,如下图所示:
   阿莫论坛发帖领航者专用114522.png

图 35.5.5 进行tftp连接

此时SDK串口终端也会打印如下信息:
阿莫论坛发帖领航者专用114606.png

图 35.5.6 串口终端打印写入完成信息

如果回车后出现像下图所示界面所示“tftp不是内部或外部命令,也不是可运行的程序或批处理文件”,则表明未开启Windows的tftp客户端功能,开启方式见6-5。
阿莫论坛发帖领航者专用114756.png

图 35.5.7 未启用tftp客户端时的界面

向服务器写入文件刚才测试完成了,现在测试从服务器端读取文件,可以读取刚才写入的文件,也可以读取服务器程序创建的测试文件。下面我们以读取服务器程序创建的测试文件为例,进行读取文件测试。
在CMD中输入“tftp -i 192.168.1.10 GET sample1.txt”命令,然后回车,会显示传输成功字样,如下图所示:
   阿莫论坛发帖领航者专用114988.png

图 35.5.8 输入读取文件命令

此时SDK串口终端也会打印如下信息:
阿莫论坛发帖领航者专用115071.png

图 35.5.9 读取成功

此时我们打开test文件夹,会看到其中新增了sample1.txt,双击打开,其内容如下:
阿莫论坛发帖领航者专用115176.png

图 35.5.10 读取的sample1.txt文件

可以看到读取文件测试成功。现在我们把SD卡插到电脑上,查看其内容如下:
阿莫论坛发帖领航者专用115285.png

图 35.5.11 SD卡上的文件

可以看到客户端上传给TFTP服务器的文件确实写到SD卡中。
6-5 下面我们介绍一下如何开启Windows的tftp客户端功能。在Win10或Win7系统中,按“Win+r”快捷键后,在下图所示界面中输入“control”。
阿莫论坛发帖领航者专用115462.png

图 35.5.12 打开控制面板界面

进入下图所示控制面板界面,将查看方式设置为“类别”,单击“程序”下的“卸载程序”,如下图所示:
阿莫论坛发帖领航者专用115575.png

图 35.5.13 点击进入“程序和功能”界面

在弹出的界面中,单击“启用或关闭Windows功能”,如下图所示:
阿莫论坛发帖领航者专用115678.png

图 35.5.14 点击“启用或关闭Windows功能”

在弹出的“Windows功能”界面中,找到“Tftp Client”,并勾选,如下图所示:
阿莫论坛发帖领航者专用115798.png

图 35.5.15 勾选tftp client

单击确定后,如果出现“Windows需要重启电脑才能完成安装所请求的更改”字样,重新启动电脑即可。现在 Windows的tftp客户端服务已启用。
至此,本实验完成。

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 14:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表