完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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 5)关注正点原子公众号,获取最新资料 第三十六章基于TCP协议的远程更新QSPI Flash实验 在《程序固化实验》中,我们了解了如何通过SDK软件将BOOT.bin文件固化到QSPI中,这种现场通过SDK软件固化的方式很常用,重新固化也很方便。然而在实际应用中,通过SDK软件固化或重新固化QSPI并不一定可行,如产品量产发布后进入维护升级阶段,若需要修改、更新QSPI中的BOOT.bin文件,遇到产品安放在高危环境中或产品整合到大型机械内部,或产品生产时没有预留JTAG口,而是预先将程序固化到QSPI中等情况,使用SDK软件现场重新固化就不可行。此时通过网络远程更新QSPI的方式将显得极其重要和方便。本章我们将介绍如何使用TCP协议实现远程更新QSPI。本章包括以下几个部分: 3636.1简介 36.2实验任务 36.3硬件设计 36.4软件设计 36.5下载验证 36.1简介 在《程序固化实验》中我们可以看到,将生成的BOOT.bin文件烧写到QSPI中就完成了程序固化,其实质是将BOOT.bin文件的数据写入到QSPI中。将数据写入到QSPI中的方式有多种,通过SDK软件工具使用JTAG接口写入是一种常用的方式。除此之外,我们在《QSPI读写实验》通过调用相关函数操作QSPI向QSPI中写入数据也是一种常用的方式。显然,远程更新QSPI使用的是后一种方式。 远程更新QSPI就是将BOOT.bin文件通过网络协议如常用的TCP、UDP协议传给远端联网的文件接收端即领航者开发板。接收端将文件暂存在DDR3中,当文件传输完成后,接收端接收到更新命令后将调用相关函数将文件数据写入到QSPI中,写入完成后为了防止写入出错,需要将写入到QSPI中的数据读出以进行校验。校验成功后就可以重新以QSPI启动的方式启动,完成远程更新。 从上述可以看出,接收端的领航者开发板作为服务端,发送端作为客户端将BOOT.bin文件数据上传给服务端是一个较好的客户/服务器模型。有一个特别需要注意的地方是,当客户端上传完文件后,作为服务端的领航者开发板如何知道文件传输完成并启动更新呢。 有两种方式可以解决。一是客户端传输完成后,关闭连接,服务端知道客户端关闭连接后知道文件传输完成,更新QSPI。此种方式弊端很多,如不能知道后续的更新情况,若发生写入到QSPI错误,不能及时修复,以及不能避免因环境问题导致的网络误关闭。另一种是当客户端传输文件完成后,向服务端发送更新命令,服务端接收到更新命令后启动更新。为了防止传错文件等意外情况,也可以添加清除命令,使之前传送的数据无效。 由于TCP协议的稳定可靠,本章我们选择TCP协议作为网络传输协议。领航者开发板利用lwip协议栈开启TCP服务作为服务端,可以写一个TCP客户端的上位机或使用网络调试助手开启TCP客户端传送BOOT.bin文件。 最后我们比较下通过SDK软件更新(使用JTAG接口方式)和网络更新方式的优缺点。 表 36.1.1 更新方式比较 36.2实验任务 本章的实验任务是使用LWIP协议栈的tcp协议实现远程更新QSPI的功能,当输入“update”命令时更新QSPI并反馈信息,当输入“clear”命令时之前传输的数据无效。 36.3硬件设计 根据实验任务我们可以画出本次实验的系统框图,如下图所示: 图 36.3.1 系统框图 在图 5.3.1中,UART用于打印程序相关的信息,LWIP通过以太网传输文件数据,传输的BOOT.bin文件数据写入到QSPI中。 step1:创建Vivado工程 本次实验的硬件设计只需在《LWIP echo server》实验的基础上添加QSPI即可。 1-1 我们先打开《LWIP echo server》实验的Vivado工程,打开后将工程另存为 “qspi_update_tcp”工程。 step2:使用IP Integrator创建Processing System 2-1 在Vivado界面左侧的Flow Navigator中,点击IP INTEGRATOR下的Open Block Design以打开Diagram窗口。然后在右侧打开的Diagram界面中双击ZYNQ Processing System模块修改其配置,即使能QSPI,如下图所示: 图 36.3.2 使能QSPI Flash控制器 2-3 配置完成后点击“OK”。然后在Diagram窗口空白处右击,然后选择“Validate Design”验证设计。验证完成后弹出对话框提示“Validation Successful”表明设计无误,点击“OK”确认。最后按快捷键“Ctrl + S”保存设计。 step3:生成顶层HDL 在Source面板中,右键点击Block Design设计文件“system.bd”,然后执行“Generate Output Products”。 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开发环境。 36.4软件设计 本次实验的软件设计与《LWIP echo server》实验无本质差别,程序框架保持不变,主要是将《LWIP echo server》实验的echo.c文件实现的功能改写成需求的远程更新QSPI功能,可在《LWIP echo server》实验的基础上修改,但为了方便程序的管理,此处我们删除《LWIP echo server》实验的应用工程,保留bsp工程。下面我们开始第五步——创建应用工程。 step5:在SDK中创建应用工程 5-1 在菜单栏中选择File->New->Application Project, 新建一个SDK空应用工程。 在弹出的界面中,输入工程名“qspi_update_tcp”,注意Board Support Package选择“Use existing”,然后选择“Next >”,如下图所示,在下一界面选择“Empty Application”。 图 36.4.1 新建SDK应用工程 5-2 大家可以从提供的例程中拷贝SDK的源文件,需拷贝的文件如下: 图 36.4.2 源文件 main.c文件和平台相关文件platform.h、platform_config.h、platform_zynq.c与《LWIP echo server》实验中的相同,是使用lwip的通用源码文件,剩下的三个源文件是我们本实验的主要功能文件。其中qspi_driver.c是QSPI的驱动文件,主要包括QSPI的初始化和更新QSPI功能、qspi_remote_update.c是程序的核心文件,实现TCP服务器功能并接收客户端发送来的文件以及响应客户端的命令、qspi_remote_update.h是联系qspi_remote_update.c与qspi_driver.c的头文件。下面我们对主要内容进行讲解。 5-2 主要内容讲解 首先我们来看qspi_remote_update.h头文件,其内容如下:
代码第10行的宏定义的SER_PORT为TCP服务器端口号,可以看到我们使用的TCP服务器端口号为6789,可以根据需要进行修改。第12行宏定义的MAX_FLASH_LEN表示写入QSPI文件的最大字节数。虽然我们领航者开发板使用的QSPI为32MB,但一般使用时不会超过16MB,因为BOOT.bin文件一般只有4MB左右,此处我们定义为16MB(16*1024*1024),可以根据实际需求进行修改,但不能低于需要传送的BOOT.bin文件的大小。 代码第14行起为函数声明,其中qspi_init()为QSPI初始化函数,在创建TCP服务的start_application()函数中调用。 qspi_update(u32 total_bytes, const u8 *flash_data)是QSPI更新函数,形参flash_data为TCP服务器接收的BOOT.bin文件数据,total_bytes为BOOT.bin文件的大小,该函数主要实现的功能如下: 调用FlashErase函数擦除FLASH(QSPI),并反馈擦除进度及花费的时间 调用FlashWrite函数向FLASH中写入BOOT.bin文件数据,并反馈写入进度及花费的时间 调用FlashRead函数从FLASH中读出数据并与flash_data进行校验,反馈校验进度及花费的时间 QSPI的初始化以及上述函数的使用可参考《QSPI读写实验》。 process_print(u8 percent)为进度打印函数,打印QSPI更新时擦除、写入和校验的进度信息。 sent_msg(const char *msg)函数用于向发送方发送信息,以实时反馈更新进度。 get_time_s()为获取系统当前时间(单位秒sec)的函数,用于计时QSPI更新时擦除、写入和校验所花费的时间。 现在我们来看程序的核心文件qspi_remote_update.c。由于该源文件较长,我们取两个重要函数进行讲解。相比较于《LWIP echo server》实验中的echo.c文件只是实现了echo功能,将客户端发送给服务端的数据原封不动的发送回去,qspi_remote_update.c实现了接收客户端发送来的文件以及响应客户端的命令的功能。该功能由接收回调函数recv_callback实现,代码如下:
代码第126~145行是我们实现的功能。当接收到的数据长度为6且内容为“update”时,表明发送方发送完数据且准备更新QSPI,此时程序将开始更新QSPI标志位start_update_flag置1并向发送方发送“Start QSPI Update”信息。当接收到的数据长度为5且内容为“clear”时,表明发送方想清除先前发送的数据,此时将统计接收数据总字节数变量total_bytes置为0。对于除此之外接收到的信息,将写入到rxbuffer中,rxbuffer是一个大小为MAX_FLASH_LEN的数组,用于存放发送方发送的BOOT.bin文件数据。 这里涉及到一个重要的结构体,数据包结构体pbuf,其定义如下:
next指针指向下一个pbuf结构,因为实际发送或接收的数据包可能很大,而每个pbuf能够管理的数据有限,所以,存在需要多个pbuf结构才能完全描述一个数据包的情况。此时,所有描述同一个数据包的pbuf需要连接在一个链表上,称之为pbuf链表,这一点用next实现。 payload是数据指针,指向该pbuf管理的数据起始地址,这里,数据起始地址可以是紧跟在pbuf结构之后的RAM空间中,也可能处在ROM中的某个地址上,而决定这点的是当前pbuf的类型,即type字段的值。 len字段表示当前pbuf中的有效数据长度,而tot_len表示当前pbuf和其后所有pbuf的有效数据的总长度。显然,tot_len字段是len字段与pbuf链表中下一个pbuf的tot_len字段之和;pbuf链表中第一个pbuf的tot len字段表示整个数据包的长度,而最后一个pbuf的tot_len字段必同len字段相等(只有在很特殊的情况下,才可能存在一条pbuf链表上保存多个数据包的情况)。 type字段表示pbuf的类型。 flags字段在源代码中并未被使用到,在初始化一个pbuf的时候,该字段的值通常被设为0,而在其他地方也未使用到该字段。 最后ref字段表示该pbuf被引用的次数。引用表示有其他指针指向当前pbuf,这里的指针可以是其他pbuf的next指针,也可以是其他任何形式的指针。初始化一个pbuf的时候,ref字段值被设置为1(因为该pbuf的地址一定会被返回给一个指针变量)。
在《LWIP echo server》实验的echo.c文件中我们并没有用上transfer_data()函数,此处我们将transfer_data()函数用做更新QSPI的起始函数。当发送方发送“update”更新命令时,程序将开始更新标志start_update_flag置1,从而使transfer_data()函数得以调用qspi_update()函数更新QSPI。transfer_data()函数在main函数的while(1)循环中被调用。 5-11 lwip设置 为了提高数据传送的效率,我们对lwip进行相应设置。右键点击bsp工程lwip_server_bsp,在弹出的菜单中选择“Board Support Package Settings”,如下图所示: 图 36.4.3 打开BSP设置 在打开的界面中,点击standalone下的lwip202,设置右侧界面的选项。主要设置的选项如下: 设置lwip_memory_options选项。将mem_size设置为524288,增加可得到的总的堆空间;将memp_n_pbuf设置为1024,增加pbuf数;将memp_n_tcp_seg设置为1024,提高同时排队的TCP段数。如下图所示。 图 36.4.4 设置lwip_memory_options选项 设置pbuf_options选项。将pbuf_pool_size为pbuf池中的缓冲区数量。对于高性能系统,可以考虑将pbuf池大小增加到一个较高的值,此处设为16384,如下图所示。 图 36.4.5 设置pbuf_options选项 设置tcp_options选项,将tcp_snd_buf和tcp_wnd设为65535,增大tcp发送缓冲空间和窗口大小,如下图所示: 图 36.4.6 设置tcp_options选项 设置temac_adapter_options选项,将n_rx_descriptors 和n_tx_descriptors设置为512,以提高系统性能,如下图所示 图 36.4.7 设置temac_adapter_options选项 其余选项保持默认即可,无需修改。 36.5下载验证 首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将USB UART接口与电脑连接,用于串口通信。使用网线一端连接领航者开发板的以太网接口,另一端与电脑或路由器连接。最后连接开发板的电源,并打开电源开关。 现在进入最后一步。 step6:板级验证 6-1 在SDK软件的下方的SDK Terminal窗口中点击右上角的加号连接串口。 6-2 下载程序。下载完成后,可以看到串口打印的结果如下: 图 36.5.1 显示打印结果 如果接到路由器,因为有DHCP服务器,可自动获取IP 给开发板;如果没有DHCP 服务器,则当领航者开发板DHCP超时时使用默认IP 地址:192.168.1.10,端口号为设置的6789。图 36.5.1中红框圈起来的,表示QSPI初始化成功。 6-3 远程更新QSPI 打开网络调试助手,在网络调试助手发送区设置里选择“启用文件数据源”,选择需要发送的BOOT.bin 文件,这里我们选择《程序固化实验》生成的BOOT.bin 文件,然后点击发送,如下图所示: 图 36.5.2 加载BOOT.bin 文件 传输完成后,输入更新QSPI命令“update”,如下图所示: 图 36.5.3 输入更新QSPI命令“update” 输入更新QSPI命令“update”后,启动QSPI更新,更新信息实时通过网络传送回发送方,显示在网络调试助手中,如下图所示: 图 36.5.4 实时反馈的更新进度信息 通过传送回的文件大小,可以了解到传送过程中有没有丢包。更新进度信息中的Elapsed time表明每个操作(擦除、写入、校验)所花费的时间。 此时,接收方也会通过串口实时输出更新信息,如下图所示: 图 36.5.5 接收方通过串口实时输出更新信息 校验成功后,关闭电源开关。将领航者核心板上的启动模式开关左边拨到上面(置为1),右边拨到下面(置为0),即设置为由QSPI Flash启动,然后再次打开电源开关。 电源开关打开后,核心板上PL配置完成的指示灯点亮。然后每次按下底板上PL_KEY0,可以改变核心板上LED2的显示状态,说明远程更新QSPI成功,本次实验在领航者ZYNQ开发板上面下载验证成功。 |
|
相关推荐
|
|
787 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程介绍之烧写所需镜像
888 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-mfgtools烧录流程之烧写方法
608 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核编译之初次编译
905 浏览 0 评论
飞凌嵌入式ElfBoard ELF 1板卡-内核源代码的目录结构和文件说明
821 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 00:21 , Processed in 0.453964 second(s), Total 36, Slave 28 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号