搜索
bottom↓
回复: 0

【正点原子FPGA连载】第三十七章基于UDP协议的远程更新QSPI Flash实验--摘自【正点原子】领航者 ZYNQ 之嵌入式开发指南

[复制链接]

出0入234汤圆

发表于 2020-8-19 17:11:29 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2020-10-26 17:25 编辑

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


第三十七章基于UDP协议的远程更新QSPI Flash实验



上一实验我们利用TCP协议实现了远程更新QSPI。为了满足不同的网络需求,本次实验我们将上一章实验使用的TCP协议替换成UDP协议。本章包括以下几个部分:
37.1简      介
37.2实验任务
37.3硬件设计
37.4软件设计
37.5下载验证


37.1简介
UDP由于本身的尽最大能力交付问题,即不稳定可靠,在传输文件上并不合适,在网络性能较好时,能够不丢失数据,当网络性能较差时,会面临数据丢失的问题,可靠性无法保证。UDP更适合于传输音视频这种对实时性要求高而又能容忍丢失数据的场合。当然了,也可以在UDP协议之上,编写一个能够确保可靠性的应用层协议,如TFTP协议。
本实验只是将《基于TCP协议的远程更新QSPI Flash实验》中的TCP协议实现改为UDP协议实现,了解如何使用UDP协议实现远程更新QSPI。如果在实际需求中确实需要使用UDP协议进行远程更新,可以在该实验的基础上增加确认重传机制,同时需要编写一个上位机使该确认重传机制能够正常工作;或者结合《基于lwip的TFTP服务器实验》使用TFTP协议以确保文件传输的可靠性。
37.2实验任务
本章的实验任务是使用LWIP协议栈的UDP协议实现远程更新QSPI的功能,当输入“update”命令时更新QSPI并反馈信息,当输入“clear”命令时之前传输的数据无效。
37.3硬件设计
本次实验的硬件设计与《基于TCP协议的远程更新QSPI Flash实验》相同。
37.4软件设计
上一章的实验的软件设计部分,为了提高数据传送的效率,我们对lwip进行相应设置。其实官方提供的模板中有优化好的设置,我们上一章的设置就是参考官方的设置。本章我们使用官方优化好的设置,避免自己手动优化。
我们删除上一实验的应用工程和BSP工程,新建一个名为“qspi_update_udp”的工程,如图 37.4.1所示。点击“Next >”,在选择模板界面中,选择“lwip UDP Perf Server”,如图 37.4.2所示:
阿莫论坛发帖领航者专用1933.png

图 37.4.1 新建应用工程

阿莫论坛发帖领航者专用1995.png

图 37.4.2 选择“lwip UDP Perf Server”

我们将应用工程“qspi_update_udp”的src目录下所有的.c和.h文件删除,只保留lscript.ld、README.txt和Xilinx.spec三个文件即可。因为我们只需要其BSP工程已经优化好的设置,应用工程用我们自己设计好的源文件。从提供的例程中拷贝SDK的源文件,需拷贝的文件如下:
阿莫论坛发帖领航者专用11227.png

图 37.4.3 源文件

以上拷贝的源文件相对于《基于TCP协议的远程更新QSPI Flash实验》只是修改了qspi_remote_update.c文件,其他文件无特殊需求可保持不变。
现对qspi_remote_update.c文件中修改的函数简单的做个讲解。
使用UDP协议则需要创建UDP服务,所以需要将start_application()中的TCP服务的创建改写成UDP服务的创建。创建UDP服务的start_application()实现如下:
  1. 151 void start_application()
  2. 152 {
  3. 153     struct udp_pcb *pcb;
  4. 154     err_t err;
  5. 155
  6. 156     //Qspi初始化
  7. 157     err = qspi_init();
  8. 158     if (err != XST_SUCCESS) {
  9. 159         xil_printf("QSPI init Failed\r\n");
  10. 160     }
  11. 161     xil_printf("Successfully init QSPI\r\n");
  12. 162
  13. 163     //创建新的UDP PCB
  14. 164     pcb = udp_new();
  15. 165     if (!pcb) {
  16. 166         xil_printf("Error creating PCB. Out of Memory\r\n");
  17. 167         return;
  18. 168     }
  19. 169
  20. 170     //绑定端口
  21. 171     err = udp_bind(pcb, IP_ADDR_ANY, SER_PORT);
  22. 172     if (err != ERR_OK) {
  23. 173         xil_printf("Unable to bind to port %d; err %d\r\n",
  24. 174                 SER_PORT, err);
  25. 175         udp_remove(pcb);
  26. 176         return;
  27. 177     }
  28. 178     //设置接收回调函数
  29. 179     udp_recv(pcb, (udp_recv_fn) recv_callback, NULL);
  30. 180
  31. 181     xil_printf("UDP server started @ port %d\n\r", SER_PORT);
  32. 182 }
复制代码

代码第157行首先对QSPI进行了初始化,随后调用的三个函数便完成了UDP服务的创建。从start_application函数可以看到lwip中使用UDP协议很简单。首先通过udp_new函数创建一个新的用于UDP 的PCB,然后调用udp_bind函数绑定端口号和本地IP地址,IP_ADDR_ANY表明为任意本地地址,SER_PORT是在qspi_remote_update.h宏定义的端口号,其值为6789,即UDP服务的默认端口。最后调用udp_recv函数设置接收回调函数就完成了UDP服务的创建,服务端的功能由回调函数实现。回调函数代码如下:
  1. 120 //UDP接收回调函数
  2. 121 static void recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p,
  3. 122         ip_addr_t *ip, u16_t port)
  4. 123 {
  5. 124     struct pbuf *q;
  6. 125     q = p;
  7. 126     upcb->remote_ip = *ip;
  8. 127     upcb->remote_port = port;
  9. 128     c_pcb = upcb;
  10. 129
  11. 130     if (q->tot_len == 6 && !(memcmp("update", p->payload, 6))) {
  12. 131         start_update_flag = 1;
  13. 132         sent_msg("Start QSPI Update\r\n");
  14. 133     } else if (q->tot_len == 5 && !(memcmp("clear", p->payload, 5))) {
  15. 134         start_update_flag = 0;
  16. 135         total_bytes = 0;
  17. 136         sent_msg("Clear received data\r\n");
  18. 137         xil_printf("Clear received data\r\n");
  19. 138     } else {
  20. 139         while (q->tot_len != q->len) {
  21. 140             memcpy(&rxbuffer[total_bytes], q->payload, q->len);
  22. 141             total_bytes += q->len;
  23. 142             q = q->next;
  24. 143         }
  25. 144         memcpy(&rxbuffer[total_bytes], q->payload, q->len);
  26. 145         total_bytes += q->len;
  27. 146     }
  28. 147
  29. 148     pbuf_free(p);
  30. 149 }
复制代码

代码第130~146行的主要部分与TCP协议的无差别。有差别的第126~128行用于UDP的发送包文函数udp_send,以向远程客户端发送包文,该函数在sent_msg()函数中调用。
  1. 101 //向客户端回送信息
  2. 102 void sent_msg(const char *msg)
  3. 103 {
  4. 104     static struct pbuf *pbuf2sent;
  5. 105
  6. 106     pbuf2sent = pbuf_alloc(PBUF_TRANSPORT, strlen(msg), PBUF_POOL);
  7. 107     if (!pbuf2sent)
  8. 108         xil_printf("Error allocating pbuf\r\n");
  9. 109
  10. 110     memcpy(pbuf2sent->payload, msg, strlen(msg));
  11. 111
  12. 112     //发送报文
  13. 113     if (udp_send(c_pcb, pbuf2sent) != ERR_OK)
  14. 114         xil_printf("UDP send error\r\n");
  15. 115
  16. 116     //释放pbuf
  17. 117     pbuf_free(pbuf2sent);
  18. 118 }
复制代码

该函数的主要作用就是实时的向客户端回送更新进度信息和命令应答信息。以上就是我们使用UDP协议时需要修改的三个函数。
如果想查看模板为提高数据传送的效率而进行的优化设置,可右键点击bsp工程qspi_update_udp_bsp,在弹出的菜单中选择“Board Support Package Settings”。
在打开的界面中,点击standalone下的lwip202,查看右侧界面的选项设置。
以lwip_memory_options选项为例。可以看到mem_size已经设置为524288; memp_n_pbuf已经设置为1024,与我们在上一章设置的相同,如下图所示。
阿莫论坛发帖领航者专用14516.png

图 37.4.4 lwip_memory_options的设置选项

37.5下载验证
首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将USB UART接口与电脑连接,用于串口通信。使用网线一端连接领航者开发板的以太网接口,另一端与电脑或路由器连接。最后连接开发板的电源,并打开电源开关。
step6:板级验证
6-1 在SDK软件的下方的SDK Terminal窗口中点击右上角的加号连接串口。
6-2 下载程序。下载完成后,可以看到串口打印的结果如下:
阿莫论坛发帖领航者专用14815.png

图 37.5.1 显示打印结果

如果接到路由器,因为有DHCP服务器,可自动获取IP 给开发板;如果没有DHCP 服务器,则当领航者开发板DHCP超时时使用默认IP 地址:192.168.1.10,端口号为设置的6789。图 36.5.1中红框圈起来的,表示QSPI初始化成功。
6-3 远程更新QSPI
打开网络调试助手,在网络调试助手发送区设置里选择“启用文件数据源”,选择需要发送的BOOT.bin 文件,这里我们选择《程序固化实验》生成的BOOT.bin 文件,然后点击发送,如下图所示:
阿莫论坛发帖领航者专用15133.png

图 37.5.2 加载BOOT.bin 文件

传输完成后,输入更新QSPI命令“update”。输入更新QSPI命令“update”后,启动QSPI更新,更新信息实时通过网络传送回发送方,显示在网络调试助手中,如下图所示:
阿莫论坛发帖领航者专用15290.png

图 37.5.3 输入更新QSPI命令“update”

通过传送回的文件大小,可以了解到传送过程中有没有丢包。更新进度信息中的Elapsed time表明每个操作(擦除、写入、校验)所花费的时间。
此时,接收方也会通过串口实时输出更新信息,如下图所示:
阿莫论坛发帖领航者专用15462.png

图 37.5.4 接收方通过串口实时输出更新信息

校验成功后,关闭电源开关。将领航者核心板上的启动模式开关左边拨到上面(置为1),右边拨到下面(置为0),即设置为由QSPI Flash启动,然后再次打开电源开关。
电源开关打开后,核心板上PL配置完成的指示灯点亮。然后每次按下底板上PL_KEY0,可以改变核心板上LED2的显示状态,说明远程更新QSPI成功,本次实验在领航者ZYNQ开发板上面下载验证成功。

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

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-3-29 03:05

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

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