0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ZYNQ - 以太网远程更新贴片SD卡/TF卡应用程序

深圳市雷龙发展有限公司 2023-06-16 09:12 次阅读

写在前面

对于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,产品说明如下:

image.php?url=YD_cnt_79_01NJ7ZgHaQnU

相比传统的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资源,

image.php?url=YD_cnt_79_01NJ7ZuPQFUx

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

image.php?url=YD_cnt_79_01NJ7ZscxpIB

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

image.php?url=YD_cnt_79_01NJ7ZriEkq6

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

image.php?url=YD_cnt_79_01NJ7ZqTVAjC

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

SDK软件部分

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

image.php?url=YD_cnt_79_01NJ7ZpJc75Z

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

image.php?url=YD_cnt_79_01NJ7ZoEZkth

编辑

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

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

image.php?url=YD_cnt_79_01NJ7ZoOZcq0

修改main.c文件

修改main.c文件为如下:

#include

#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();

//初始化lwIP

lwip_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==1

netif->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));

}

}

#else

assign_default_ip(&(netif->ip_addr), &(netif->netmask), &(netif->gw));

#endif

print_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

//服务器端口

#define SER_PORT 5678

//接收的最大文件大小16MB

#define MAX_FLASH_LEN 16*1024*1024

void sent_msg(const char *msg);

#endif

添加remote_update.c文件

#include "remote_update.h"

#include "xparameters.h"

#include "ff.h"

#include "string.h"

#include

#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);

} else

xil_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 PCB

pcb = 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文件,勾选加载文件数据源,点击发送。

image.php?url=YD_cnt_79_01NJ7ZnBel7P

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

image.php?url=YD_cnt_79_01NJ7ZmYmvMA

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

image.php?url=YD_cnt_79_01NJ7ZkVNnYW

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

image.php?url=YD_cnt_79_01NJ7Zja2nuZ

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

image.php?url=YD_cnt_79_01NJ7ZktuXOr

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SD卡
    +关注

    关注

    2

    文章

    564

    浏览量

    63889
  • NAND闪存
    +关注

    关注

    2

    文章

    219

    浏览量

    22750
  • 存储芯片
    +关注

    关注

    11

    文章

    896

    浏览量

    43133
  • Nand flash
    +关注

    关注

    6

    文章

    241

    浏览量

    39802
收藏 人收藏

    评论

    相关推荐

    tf与云存储的比较 tf的兼容性问题

    TF(通常指Micro SD)与云存储在数据存储领域各有其特点和优势,同时也存在一些差异。以下是两者之间的比较,以及关于TF
    的头像 发表于 12-19 15:24 163次阅读

    雷龙CS SD NAND:贴片TF体验与性能测试

    最近有幸获得了雷龙发展提供的贴片TF样品,收到的快递中包含两片 CS SD NAND 芯片和一个转接板。以下是芯片和转接板的实物照片: 产品简介 此次测试的芯片型号
    发表于 11-26 10:04

    Arduino程序:实现SD NAND(贴片sd)的读写功能

    []()   官方给的转接板上,没有相应的电容电阻,当TF测试的时候不需要焊接相应的电容电阻(大量的时候按官的电路);直接芯片焊上,插上贴片
    发表于 11-07 17:45

    使用TF的常见问题

    随着科技的发展,TF(TransFlash,也称为MicroSD)已经成为我们日常生活中不可或缺的存储工具。它们被广泛应用于智能手机、平板电脑、数码相机等设备中,用于扩展存储空间
    的头像 发表于 11-04 09:54 870次阅读

    TFSD的区别

    在数字时代,存储成为了我们生活中不可或缺的一部分。无论是手机、相机还是平板电脑,都需要存储来扩展存储空间。TFSD
    的头像 发表于 11-04 09:50 288次阅读

    这样设计SD/TF的PCB更高效、更可靠!

    ,例如数码相机、平板电脑和多媒体播放器等。 TF 是一种小型的SD,它可以通过SD转换使用
    的头像 发表于 09-03 17:05 647次阅读
    这样设计<b class='flag-5'>SD</b>/<b class='flag-5'>TF</b><b class='flag-5'>卡</b>的PCB更高效、更可靠!

    MK米客方德存储TFSD的详细解读

    在这个数字化时代,数据存储变得至关重要。TF(TransFlash)和SD(Secure Digital
    的头像 发表于 09-02 11:03 662次阅读
    MK米客方德存储<b class='flag-5'>卡</b>:<b class='flag-5'>TF</b><b class='flag-5'>卡</b>与<b class='flag-5'>SD</b><b class='flag-5'>卡</b>的详细解读

    贴片SD功能介绍【MK SD NAND】

    SDNAND,通常称为嵌入式SD贴片TFSD Flash、直接贴装
    的头像 发表于 07-05 17:03 772次阅读
    <b class='flag-5'>贴片</b>式<b class='flag-5'>SD</b><b class='flag-5'>卡</b>功能介绍【MK <b class='flag-5'>SD</b> NAND】

    什么是贴片TF

    贴片TF,也被称为贴片SDSD NAND,
    的头像 发表于 05-31 10:55 1111次阅读
    什么是<b class='flag-5'>贴片</b>式<b class='flag-5'>TF</b><b class='flag-5'>卡</b>?

    SD是什么?TF又是什么?它们两个有什么区别

    SD是什么?TF又是什么?它们两个有什么区别  SD
    的头像 发表于 01-30 14:36 1839次阅读

    sd是什么有什么用途 TFSD有什么区别

    SDTF都是一种可移动存储设备,用于存储数据和文件。它们在外观和使用方面有些许差异,但两者的用途和功能几乎相同。下面将详细介绍SD
    的头像 发表于 01-25 10:44 4983次阅读

    TFSD的区别有哪些?

    TFSD卡在物理尺寸和一些应用领域上存在差异,但在技术规格上,特别是MicroSD,它们之间的差异相对较小。选择TF
    的头像 发表于 01-18 09:17 1w次阅读
    <b class='flag-5'>TF</b><b class='flag-5'>卡</b>和<b class='flag-5'>SD</b><b class='flag-5'>卡</b>的区别有哪些?

    MicroSD如何转接成SD

    SD套主要用于将TF(MicroSD)转接成SD
    的头像 发表于 01-11 14:00 1430次阅读
    MicroSD<b class='flag-5'>卡</b>如何转接成<b class='flag-5'>SD</b><b class='flag-5'>卡</b>?

    什么是SD NAND存储芯片? SD NAND与TF的区别

    什么是SD NAND?它俗称贴片式T贴片TF贴片
    的头像 发表于 01-06 14:35 1773次阅读
    什么是<b class='flag-5'>SD</b> NAND存储芯片? <b class='flag-5'>SD</b> NAND与<b class='flag-5'>TF</b><b class='flag-5'>卡</b>的区别

    SD/TF的速度等级,如何读懂TF的速度标识

    SD/TF的速度等级下图是SD协会的速度等级图,从图中可以看出不同的符号对应的速度等级信息。如何读懂TF的丝印标识以MK-米客方德工业级
    的头像 发表于 01-02 16:38 1.1w次阅读
    <b class='flag-5'>SD</b>/<b class='flag-5'>TF</b><b class='flag-5'>卡</b>的速度等级,如何读懂<b class='flag-5'>TF</b>的速度标识