写在前面

对于ZYNQ系列的板卡固化,可以通过JTAG接口,使用SDK固化到FLASH中,或者可将SD卡取出将SD卡中保存的固化工程进行修改,但在很多情况下,离线更新会很不方便,本文借鉴网上常见的远程更新QSPI FLASH的相关示例,对表贴式SD卡的应用程序进行了在线更新的操作适配,便于ZYNQ设备进行远程更新保存在表贴式SD卡中的固化程序。

传统SD卡与表贴SD卡区别

对于传统SD卡,直接将SD卡取出,使用读卡器进行脱机更新很方便,但是由于SD卡插拔时容易损坏,对于一些需要SD卡设备,但需要高可靠性的应用场景,使用传统的SD卡托很容易造成卡托和TF卡的脱落,很难保持SD卡长时间的稳定读取。

相比传统的SD卡,使用表贴式的SD卡,将会增加系统的可靠性和稳定性,这里硬件方案选择雷龙公司的NAND Flash(贴片式TF卡)CSNP4GCR01-AMW,产品说明如下:

相比传统的SD卡,表贴式SD卡除了保留了SD卡大容量容易读写操作的特点外,在PCB板上的占用面积也相比传统表贴卡托的面积要小。对传统的SD卡的电路设计可实现快速替代。

程序简述说明

程序大体框架借鉴了正点原子的远程更新的例程架构,只对更新QSPI的部分进行改写替换,替换成对SD卡的固化程序进行更新的相关代码。本文使用的板卡为PYNQ-Z2,这里只是为了验证表贴SD卡的功能,使用转接板对传统的SD卡进行了替代。相关样片和转接板样品可在雷龙公司官网进行申请试用。

大致实现功能为:用 LWIP 协议栈的 tcp 协议实现远程更新 表贴SD卡的功能,当输入“ update”命令时更新 SD卡并反馈信息,当输入“ clear”命令时之前传输的数据无效。

硬件平台搭建

新建工程,创建 block design。添加ZYNQ7 IP,对zynq进行初始化配置,对应板卡配置勾选SD,UART以及ENET资源,

如使用相同型号的板卡,可设置该部分为相同配置。

勾选DDR,并设置为PYNQZ2板卡的DDR的信息,

取消勾选多余资源,点击OK,完成硬件设计。如下图:

然后我们进行generate output product 然后生成HDL封装。这里没有进行使用PL资源,也不需要进行综合布局,在导出硬件时也不用包含bit流文件。

SDK软件部分

打开SDK后,新建application project,这里为了方便lwip设置,可选用使用lwip的相关模板,这里选择lwip tcp回环测试模板,保存新建工程。

选中新建好的工程,选择右击选中设置板载支持包,除了勾选lwip的板级支持包外,还需勾选sd卡需要的文件模式支持包。

点击standalone下的xilffs,可以对文件系统进行配置,这里可以使能长文件名有效,改变勾选为true。

保留模板例程的中的platform配置文件,删除其余文件。

修改main.c文件

修改main.c文件为如下:

#include <stdio.h>
#include "xparameters.h"
#include "netif/xadapter.h"
#include "platform.h"
#include "platform_config.h"
#include "lwipopts.h"
#include "xil_printf.h"
#include "sleep.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/init.h"
#include "lwip/inet.h"#if LWIP_IPV6==1
#include "lwip/ip6_addr.h"
#include "lwip/ip6.h"
#else#if LWIP_DHCP==1
#include "lwip/dhcp.h"
extern volatile int dhcp_timoutcntr;
#endif
#define DEFAULT_IP_ADDRESS  "192.168.1.10"
#define DEFAULT_IP_MASK     "255.255.255.0"
#define DEFAULT_GW_ADDRESS  "192.168.1.1"
#endif /* LWIP_IPV6 */extern volatile int TcpFastTmrFlag;
extern volatile int TcpSlowTmrFlag;void platform_enable_interrupts(void);
void start_application(void);
void print_app_header(void);
int transfer_data();struct netif server_netif;#if LWIP_IPV6==1
static void print_ipv6(char *msg, ip_addr_t *ip)
{print(msg);xil_printf(" %s\n\r", inet6_ntoa(*ip));
}
#else
static void print_ip(char *msg, ip_addr_t *ip)
{print(msg);xil_printf("%d.%d.%d.%d\r\n", ip4_addr1(ip), ip4_addr2(ip),ip4_addr3(ip), ip4_addr4(ip));
}static void print_ip_settings(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{print_ip("Board IP:       ", ip);print_ip("Netmask :       ", mask);print_ip("Gateway :       ", gw);
}static void assign_default_ip(ip_addr_t *ip, ip_addr_t *mask, ip_addr_t *gw)
{int err;xil_printf("Configuring default IP %s \r\n", DEFAULT_IP_ADDRESS);err = inet_aton(DEFAULT_IP_ADDRESS, ip);if (!err)xil_printf("Invalid default IP address: %d\r\n", err);err = inet_aton(DEFAULT_IP_MASK, mask);if (!err)xil_printf("Invalid default IP MASK: %d\r\n", err);err = inet_aton(DEFAULT_GW_ADDRESS, gw);if (!err)xil_printf("Invalid default gateway address: %d\r\n", err);
}
#endif /* LWIP_IPV6 */int main(void)
{struct netif *netif;//设置开发板的MAC地址unsigned char mac_ethernet_address[] = {0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };netif = &server_netif;init_platform();print_app_header();//初始化lwIPlwip_init();//将网络接口添加到netif,并将其设置为默认值if (!xemac_add(netif, NULL, NULL, NULL, mac_ethernet_address,PLATFORM_EMAC_BASEADDR)) {xil_printf("Error adding N/W interface\r\n");return -1;}#if LWIP_IPV6==1netif->ip6_autoconfig_enabled = 1;netif_create_ip6_linklocal_address(netif, 1);netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID);print_ipv6("\n\rlink local IPv6 address is:", &netif->ip6_addr[0]);
#endif /* LWIP_IPV6 */netif_set_default(netif);//使能中断platform_enable_interrupts();//指定网络是否已启动netif_set_up(netif);#if (LWIP_IPV6==0)
#if (LWIP_DHCP==1)//创建新的DHCP客户端dhcp_start(netif);dhcp_timoutcntr = 2;while (((netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))xemacif_input(netif);if (dhcp_timoutcntr <= 0) {if ((netif->ip_addr.addr) == 0) {xil_printf("ERROR: DHCP request timed out\r\n");assign_default_ip(&(netif->ip_addr),&(netif->netmask), &(netif->gw));}}#elseassign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
#endifprint_ip_settings(&(netif->ip_addr), &(netif->netmask), &(netif->gw));
#endif /* LWIP_IPV6 *///启动应用程序start_application();while (1) {if (TcpFastTmrFlag) {tcp_fasttmr();TcpFastTmrFlag = 0;}if (TcpSlowTmrFlag) {tcp_slowtmr();TcpSlowTmrFlag = 0;}xemacif_input(netif);transfer_data();}cleanup_platform();return 0;
}

添加remote_update.h文件

#ifndef REMOTE_UPDATE_H_
#define REMOTE_UPDATE_H_#include "xparameters.h"
#include "xtime_l.h"
#include "xstatus.h"
#include <stdio.h>//服务器端口
#define SER_PORT            5678
//接收的最大文件大小16MB
#define MAX_FLASH_LEN       16*1024*1024void sent_msg(const char *msg);#endif

添加remote_update.c文件

#include "remote_update.h"
#include "xparameters.h"
#include "ff.h"
#include "string.h"
#include <stdio.h>
#include "lwip/err.h"
#include "lwip/tcp.h"
#include "xil_printf.h"u8 start_update_flag = 0;
u8 rxbuffer[MAX_FLASH_LEN];
u32 total_bytes = 0;
#define FILE_NAME "BOOT.bin"
struct tcp_pcb *c_pcb;
FATFS fs;
void print_app_header()
{xil_printf("-----SD remote update demo------\n");
}
//挂载sd卡
void sd_mount(){FRESULT status;BYTE work[FF_MAX_SS];//挂载sd卡,注册文件系统对象status=f_mount(&fs,"",1);if(status != FR_OK){printf("%d\n",status);printf("It isn't FAT format\n");f_mkfs("",FM_FAT32,0,work,sizeof work);f_mount(&fs,"",1);}
}
//写数据
void sd_write_data(u8 wr_dat[], u32 wr_len){FIL fil;UINT bw;//创建或者打开文件f_open(&fil,FILE_NAME,FA_CREATE_ALWAYS | FA_WRITE | FA_READ);//移动读写指针f_lseek(&fil, 0);//写数据f_write(&fil,wr_dat,wr_len,&bw);//关闭文件f_close(&fil);
}//将接收到的BOOT.bin文件写入到SD中
int transfer_data()
{char msg[60];if (start_update_flag) {xil_printf("\r\nStart SD Update!\r\n");xil_printf("file size of BOOT.bin is %lu Bytes\r\n", total_bytes);sprintf(msg, "file size of BOOT.bin is %lu Bytes\r\n",total_bytes);sent_msg(msg);sd_write_data(rxbuffer,total_bytes);xil_printf("SD Update finish!\n");total_bytes = 0;}start_update_flag = 0;return 0;
}//向客户端回送信息
void sent_msg(const char *msg)
{err_t err;tcp_nagle_disable(c_pcb);if (tcp_sndbuf(c_pcb) > strlen(msg)) {err = tcp_write(c_pcb, msg, strlen(msg), TCP_WRITE_FLAG_COPY);if (err != ERR_OK)xil_printf("tcp_server: Error on tcp_write: %d\r\n", err);err = tcp_output(c_pcb);if (err != ERR_OK)xil_printf("tcp_server: Error on tcp_output: %d\r\n", err);} elsexil_printf("no space in tcp_sndbuf\r\n");
}//接收回调函数
static err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{struct pbuf *q;if (!p) {tcp_close(tpcb);tcp_recv(tpcb, NULL);xil_printf("tcp connection closed\r\n");return ERR_OK;}q = p;if (q->tot_len == 6 && !(memcmp("update", p->payload, 6))) {start_update_flag = 1;sent_msg("\r\nStart SD Update\r\n");} else if (q->tot_len == 5 && !(memcmp("clear", p->payload, 5))) {start_update_flag = 0;total_bytes = 0;sent_msg("Clear received data\r\n");xil_printf("Clear received data\r\n");} else {while (q->tot_len != q->len) {memcpy(&rxbuffer[total_bytes], q->payload, q->len);total_bytes += q->len;q = q->next;}memcpy(&rxbuffer[total_bytes], q->payload, q->len);total_bytes += q->len;}tcp_recved(tpcb, p->tot_len);pbuf_free(p);return ERR_OK;
}err_t accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{xil_printf("tcp_server: Connection Accepted\r\n");c_pcb = newpcb;             //保存连接的客户端PCB//设置接收回调tcp_recv(c_pcb, recv_callback);tcp_arg(c_pcb, NULL);return ERR_OK;
}int start_application()
{struct tcp_pcb *pcb;err_t err;//挂载SD卡sd_mount();xil_printf("Successfully init SD\r\n");print_app_header();//创建TCP PCBpcb = tcp_new_ip_type(IPADDR_TYPE_ANY);if (!pcb) {xil_printf("Error creating PCB. Out of Memory\n\r");return -1;}//绑定端口号err = tcp_bind(pcb, IP_ANY_TYPE, SER_PORT);if (err != ERR_OK) {xil_printf("Unable to bind to port %d: err = %d\n\r", SER_PORT, err);return -2;}//此处不需要回调函数的任何参数tcp_arg(pcb, NULL);//侦听连接pcb = tcp_listen(pcb);if (!pcb) {xil_printf("Out of memory while tcp_listen\n\r");return -3;}//指定用于传入连接的回调tcp_accept(pcb, accept_callback);xil_printf("TCP server started @ port %d\n\r", SER_PORT);return 0;
}

完成代码编写后,进行烧写验证。

下载验证

打开网络调试助手,选择协议类型为TCP客户端,选择远程主机的IP地址和端口,选择需要加载的应用程序的bin文件,勾选加载文件数据源,点击发送。

发送完成后在发送框选择输入“update”更新SD卡的应用程序。

在串口终端中查看调试信息,表示SD卡程序更新完成。

使用读卡器查看贴片SD卡转接卡是否正常存储到SD卡中,读取文件可知已经正常写入。

将板卡启动模式调整至SD卡模式,上电重启板卡程序,观察到板卡程序成功启动。

ZYNQ - 以太网远程更新SD卡应用程序相关推荐

  1. 基于IAP实现的STM32F系列固件升级(远程升级 + SD卡升级)

    谈到STM32固件更新,首先就要了解一下固件的概念.固件是指下载到芯片里面去运行的二进制代码数据,是代码工程编译之后生成的,大家如果用的是MDK Keil的话,点了那个编译之后,就会生成固件,点击下载 ...

  2. zynq UltraScale+ MPSoC 测试SD卡的写入速度

    目录 一. PL端准备 二. PS端编程 1.main.c 2.platform_zynqmp.c 3.platform_config.h 三. 测试与总结 一. PL端准备 我的开发板只有一个SD卡 ...

  3. linux下SD卡烧录程序

    1.文件mkv210_image.c详解 分析启动过程可知: 210 启动后先执行内部iROM中的BL0,BL0执行完后会根据OMpin 的配置选择一个外部设备来启动(有很多,我们实际使用的有2个:u ...

  4. STM32利用SPI读写SD卡的程序详解

    STM32利用SPI读写SD卡的一些程序详解 关于SD卡的基础知识这里不做过多陈述,如果有对这方面感兴趣的朋友可以直接百度一下,有很多讲SD卡的文章,这里主要是针对SD卡的读写程序实现做一些详细说明. ...

  5. AB PLC, 如何用SD卡更新程序

    一天接到一个需求,一型设备共60台需要更新程序,突然想起能否用SD卡更新程序,省去反复插拔网线的功夫.原来,AB PLC早就具备这样的功能了. 1. 把PLC的控制模式切换为编程模式. 2. 在控制器 ...

  6. activiti高亮显示图片_【正点原子FPGA连载】第二十章SD卡读BMP图片HDMI显示实验领航者 ZYNQ 之嵌入式开发指南...

    1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...

  7. 基于FPGA的数据采集、通讯和存储系统设计(即FPGA+RTL8211千兆以太网+SD卡存储+RTC+Uart+AD7606数模转换+电流放大采集等硬件设计及程序验证)

    本文主要介绍了学生期间自己做的一个小项目,便于学习初期对fpga的整体把握,涉及了很多常见.常用.常考和面试常问的知识点. 可以作为入门后的拓展学习和应对一些找工作的项目面试. 下面对硬件及软件代码进 ...

  8. 应用程序安装在sd卡还是内存选择及设置

    点击打开链接 主要内容是介绍如何使得自己开发的android程序安装到外置储存设备(如sd卡),安装到外置储存设备(如sd卡)的程序有哪些特别的地方.兼容性.哪些软件最好安装在内存中,哪些最好安装在外 ...

  9. 基于FPGA的SD卡写数据Verilog程序开发

    1.仿真预览 操作步骤,先格式化.设置如下: 注意,格式化之后,使用容量如下: 假如我在文档中保存一个数据 里面数据为1 此时容量使用变为: 根据这个信息,我们最后来验证写入的数据量是否正确. 然后使 ...

最新文章

  1. sosoApi 环境搭建
  2. INNODB 热备工具试验与总结
  3. python分别统计男女人数_python实现爬虫统计学校BBS男女比例(一)
  4. Java黑皮书课后题第5章:*5.15(显示ASCII码字符表)编写一个程序,打印ASCII字符表从‘!‘到‘~‘的字符。每行打印10个字符。ASCII码表如附录B所示。数字之间用一个空格字符隔开
  5. dubbo 消费者也要暴露端口吗_一文详细解读 Dubbo 中的 http 协议
  6. XCopy命令实现增量备份
  7. 计算机软件基础第四版,《计算机软件技术基础》徐士良(第4版)课后习题答案详解|复习笔记...
  8. 黑龙江职业学院校赛第二场题解
  9. c# mysql datetime 判断为空 dbnull_转:SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究...
  10. DBCS和UCS编码相关
  11. 对代码更有信心--单元测试工具Mockito简单介绍
  12. [Java Web]敏感词过滤算法
  13. 电脑端如何截屏网页全部内容|网页截长图
  14. 液晶显示屏的分辨率详解?
  15. linux 字幕制作工具,Aegisub下载、安装和使用:Ubuntu字幕编辑软件
  16. Linux 应用调试神器- ASan
  17. win10锁屏壁纸保存方法
  18. 企业拼团APP商城开发流程6步曲
  19. javascript实现的淘宝五星评价(版本2)
  20. 大学生兼职平台设计思路

热门文章

  1. 计算机科学与技术杨晓静,杨晓静
  2. FCN 和 U-net
  3. [230516] TPO71 | 2022年托福阅读真题第4/36篇 | Electrical Energy from the Ocean | 11:50
  4. 使用Konva操纵HTML5画布:第3部分,复杂的形状和精灵
  5. 2022-2028年中国环境污染处理专用药剂材料行业市场深度分析及未来趋势预测报告
  6. Unity中游戏多种武器旋转方式
  7. JavaScript内存泄露的4种方式及如何避免
  8. js 内存泄漏 简单
  9. ubuntu玩转freenode irc
  10. 如何将带有图像的PDF转换为可编辑的Word文档