ZYNQ实验 基于LWIP的UDP传输实验

这篇具有很好参考价值的文章主要介绍了ZYNQ实验 基于LWIP的UDP传输实验。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

实验介绍

  LWIP是嵌入式设备中较为常用的TCP/IP协议栈,本文将使用UDP协议传输较大的txt文件并写入PS端的DDR中,实验对文件传输的速率和准确率要求不高因此调用简单的UDP协议即可。
实验难点:

  • LWIP的pbuf的理解。
  • 对UDP接收回调函数的使用。

实验基本设置

如果不知道如何创建和使用SDK可以参考该文章:如何创建PS-PL工程

1.Vivado中搭建硬件环境,启用UART和以太网外设,UART也是需要的将打印一些提示信息。
这个要根据自己使用的板子选择
sdk lwip和uart,ZYNQ学习笔记,udp,单片机,网络协议
2.SDK设置
工程中的需要使用支持lwip的BSP包。这个BSP包可以是重新生成也可以添加lwip到已有的BSP包中。
sdk lwip和uart,ZYNQ学习笔记,udp,单片机,网络协议
如果需要配置lwip可以在以下界面中设置,这里只说一下api_modle,lwip支持3种api接口(接口区别在本文参考资料中有写),这里只能选择前两种API接口。

  • RAW/Callback API
  • Socket API
  • NETCONN API
    sdk lwip和uart,ZYNQ学习笔记,udp,单片机,网络协议

SDK代码

工程配置好后需要添加4个代码文件才能使用udp
sdk lwip和uart,ZYNQ学习笔记,udp,单片机,网络协议

  • lwIP需要启动中断系统,需要sys_intr.c与sys_intr.h
  • UDP使用则需要添加一些初始化和回调函数包含在udp.process.c与udp.process.h
    这4个文件我附在了最后的完整代码中

主要代码介绍

main.c

  • 设置开发板MAC地址
  • 开启中断系统
  • 设置本地IP地址
  • 初始化lwIP
  • 添加网络接口 设置默认网络接口
  • 启动网络
  • 初始化UDP连接
  • 进行数据传输
#include "sys_intr.h"
#include "udp_process.h"
#include "xil_printf.h"

/* 基本参数设置 */
#define MAX_LEN    2500
u8 UDPsentBuffer[MAX_LEN]={0};
u8 UDPrecvBuffer[MAX_LEN]={0};
//udp传输来的指令存放数组
u8 PC2PScmd[MAX_LEN];
u8 PS2PCcmd[MAX_LEN];
//收到的数据长度
u16 revnum=0;

extern unsigned udp_connected_flag;
static  XScuGic Intc;   //GIC 中断管理

int main(void)
{
/* UDP init*/
struct netif *netif, server_netif;
ip_addr_t ipaddr, netmask, gw;

/*  开发板MAC地址  */
unsigned char mac_ethernet_address [] ={0x00, 0x0a, 0x35, 0x00, 0x01, 0x02};
/*  开启中断系统  */
Init_Intr_System(&IntcInstPtr);
Setup_Intr_Exception(&IntcInstPtr);
/*  添加本机IP地址,远端设备IP在udp.process.c中设置  */
netif = &server_netif;
IP4_ADDR(&ipaddr,  192, 168,   1, 30);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw,      192, 168,   1, 1);

lwip_init();   //初始化lwIP库

/* 添加网络接口并将其设置为默认接口 */
if (!xemac_add(netif, &ipaddr, &netmask, &gw, mac_ethernet_address, XPAR_XEMACPS_0_BASEADDR)) {
		xil_printf("Error adding N/W interface\r\n");
		return -1;
}
netif_set_default(netif);
netif_set_up(netif);        //启动网络
user_udp_init();            //初始化UDP

while (1)
{
	/*  将MAC队列中的包传输的LwIP/IP栈中   */
	xemacif_input(netif);
	revnum=udp_ReadData(UDPrecvBuffer);
	/*  接收到的数据PC2PScmd即存在其中   */
	memcpy(PC2PScmd,UDPrecvBuffer,revnum);
	/*  将值通过udp发送回去   */
	if(revnum>0)
	{
		memcpy(UDPsentBuffer,PC2PScmd,revnum);
		udp_SentData(revnum,UDPsentBuffer);
	}
}
return 0;
}

udp_recv_callback函数

该函数是重要的接收回调函数

void udp_recv_callback(void *arg,struct udp_pcb *tpcb,struct pbuf *p, ip_addr_t *addr, u16_t port)
{
	struct pbuf *p_r;

    xil_printf("Received from %d.%d.%d.%d port %d\r\n", (addr->addr) & 0xFF,
    			(addr->addr>>8) & 0xFF, (addr->addr>>16) & 0xFF, (addr->addr>>24) & 0xFF, port);

    /* Tell the client that we have accepted it */
    //memcpy(RxBuffer,(unsigned char*)p->payload,p->len);
    //xil_printf("Received:%d,len=%d",RxBuffer,p->len);
    if(p != NULL)
	 {
	 		//默认内存块为530字节左右,接收数据超过后会被存到多个内存块中这里将读取所有的内存块读出完整的数据
			for(p_r = p; p_r != NULL; p_r = p_r->next) 
			{
				 memcpy(RxBuffer,(unsigned char*)p_r->payload,p_r->len);
				 RxCount += p_r->len;
			}
	  }
    /* Free the p buffer */
    pbuf_free(p);
}

实验效果

设置网络调试助手发送hello world,ZYNQ返回hello world。
主机地址端口和远端地址端口要与代码写的一致,PC主机的地址在网络中心中可以设置
sdk lwip和uart,ZYNQ学习笔记,udp,单片机,网络协议

参考资料

学会Zynq(14)UDP发送Hello World
STM32 LWIP UDP3000字节接收
STM32以太网通信-LWIP简介

完整代码

sys_intr.c

#include "sys_intr.h"
void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{
	/* Enable interrupts from the hardware */
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			(void *)IntcInstancePtr);

	Xil_ExceptionEnable();
}

int Init_Intr_System(XScuGic * IntcInstancePtr)
{
	int Status;

	XScuGic_Config *IntcConfig;
	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

sys_intr.h

#ifndef SYS_INTR_H_
#define SYS_INTR_H_

#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"

#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID
int Init_Intr_System(XScuGic * IntcInstancePtr);
void setup_Intr_Exception(XScuGic * IntcInstancePtr);
#endif

udp.process.c

#include "udp_process.h"
//---------------------------------------------------------
//                    变量定义
//---------------------------------------------------------
struct udp_pcb *connected_pcb = NULL;
static struct pbuf *pbuf_to_be_sent = NULL;

static unsigned local_port = 9000;      //本地端口
static unsigned remote_port = 9000;  //远程端口
volatile unsigned udp_connected_flag = 0;  //连接标志

#define MAX_LEN    2500
//缓冲数组
uint8_t TxBuffer[MAX_LEN] = {0};
uint8_t RxBuffer[MAX_LEN] = {0};
uint16_t RxCount = 0;

void udp_recv_callback(void *arg,struct udp_pcb *tpcb,struct pbuf *p, ip_addr_t *addr, u16_t port)
{
	struct pbuf *p_r;

    xil_printf("Received from %d.%d.%d.%d port %d\r\n", (addr->addr) & 0xFF,
    			(addr->addr>>8) & 0xFF, (addr->addr>>16) & 0xFF, (addr->addr>>24) & 0xFF, port);

    /* Tell the client that we have accepted it */
    //memcpy(RxBuffer,(unsigned char*)p->payload,p->len);
    //xil_printf("Received:%d,len=%d",RxBuffer,p->len);
    if(p != NULL)
	 {
				for(p_r = p; p_r != NULL; p_r = p_r->next)
			{
				 memcpy(RxBuffer,(unsigned char*)p_r->payload,p_r->len);
				 RxCount += p_r->len;
			}
	  }
    /* Free the p buffer */
    pbuf_free(p);
}
//---------------------------------------------------------
//                  UDP连接初始化函数
//---------------------------------------------------------
int user_udp_init(void)
{
	struct udp_pcb *pcb;
	ip_addr_t ipaddr;
	err_t err;
	udp_connected_flag = 0;

	/*  创建UDP控制块   */
	pcb = udp_new();
	if (!pcb) {
		xil_printf("Error Creating PCB.\r\n");
		return -1;
	}
	/*  绑定本地端口   */
	err = udp_bind(pcb, IP_ADDR_ANY, local_port);
	if (err != ERR_OK) {
		xil_printf("Unable to bind to port %d\r\n", local_port);
		return -2;
	}
	/*  连接远程地址   */
	IP4_ADDR(&ipaddr, 192, 168, 1, 28);
	err = udp_connect(pcb, &ipaddr, remote_port);
	if (err != ERR_OK) {
		xil_printf("Unable to connect remote port.\r\n");
		return -3;
	}
	else {
		xil_printf("Connected Success.\r\n");
		connected_pcb = pcb;
		udp_connected_flag = 1;
	}

	udp_recv(pcb, udp_recv_callback, NULL);  //设置接收回调函数

	return 0;
}
//---------------------------------------------------------
//                   UDP接收数据函数
//---------------------------------------------------------
uint16_t udp_ReadData(uint8_t *buff)
{
	uint16_t len = RxCount;
	if(len > 0)
		memcpy(buff,RxBuffer,len);
	memset(RxBuffer,0,len); //memset过大的重置内存块会对UDP会有异常
	RxCount = 0;
	return len;
}
//---------------------------------------------------------
//                   UDP发送数据函数
//---------------------------------------------------------
void udp_SentData(uint32_t num, u8 * send_buff)
{
	err_t err;
	struct udp_pcb *tpcb = connected_pcb;
		if (!tpcb) {
			xil_printf("error connect.\r\n");
		}
		/*  申请pbuf资源  */
		pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, num, PBUF_POOL);
		memset(pbuf_to_be_sent->payload, 0, num);
		memcpy(pbuf_to_be_sent->payload, (u8 *)send_buff, num);
		/*  发送字符串  */
		err = udp_send(tpcb, pbuf_to_be_sent);
		if (err != ERR_OK) {
			xil_printf("Error on udp send : %d\r\n", err);
			pbuf_free(pbuf_to_be_sent);
			return;
		}
		pbuf_free(pbuf_to_be_sent);  //释放pbuf
}

udp.process.h文章来源地址https://www.toymoban.com/news/detail-766168.html

#ifndef SRC_USER_UDP_H_
#define SRC_USER_UDP_H_

#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwip/init.h"
#include "lwipopts.h"
#include "lwip/err.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "xil_printf.h"

int user_udp_init(void);
void udp_SentData(uint32_t num, u8 * send_buff);
uint16_t udp_ReadData(uint8_t *buff);

#endif /* SRC_USER_UDP_H_ */

到了这里,关于ZYNQ实验 基于LWIP的UDP传输实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RT-Thread 组件-网络组件-Lwip UDP说明①

    1.1 协议简介 UDP (User Datagram Protocol):用户数据报协议,是一种简单、无连接、不可靠的传输协议。 无需建立连接、没有提供任何流量控制、拥塞控制机制,收到的报文也没有确认,因此 UDP 的传输速度快,但不能保证数据到达目的地。 与我们熟知的 TCP 协议一样,都属于 OS

    2024年02月22日
    浏览(31)
  • 【lwip】14-TCP协议之可靠传输的实现(TCP干货)

    ‍ 前面章节太长了,不得不分开。 这里已源码为主,默认读者已知晓概念或原理,概念或原理可以参考前面章节,有分析。 参考:李柱明博客:https://www.cnblogs.com/lizhuming/p/17438743.html ‍ lwip的时钟机制可以翻看前面章节。 lwip的TCP可靠传传输的实现离不开两个时钟处理函数:

    2024年02月06日
    浏览(33)
  • 9.物联网LWIP,ip数据报,udp数据报,tcp数据报

    一。ip协议原理(网络层) 1.网络地址转换NAT         我们上网是通过运营商向我们提供的IP地址来上网的,并不是自身的IP地址,所以这就需要网络地址转换NAT的帮助。即内网访问外网所需要的ip转换装置。 2.ip数据报 (1)版本          占据4bit空间,定义IPv4与ipv6,对应的

    2024年02月10日
    浏览(26)
  • GD32F470之网络lwip+UDP配置+lan8720芯片

    先申明,本栏目用的都是GD32F470芯片240M,软件用的是keil,编写用的是C++(其实和C没有区别). 和STM32的lwip配置大致一样,主要不一样的地方在于 PHY的配置顺序问题,下面会讲到. 我用的是lan8720,所以头文件要修改一下,在gd32f4xx_enet.h中。 把PHY_TYPE改为LAN8700, PHY_ADDRESS改为0, 这是

    2023年04月09日
    浏览(35)
  • 【lwip】14-TCP协议分析之TCP协议之可靠传输的实现(TCP干货)

    ‍ 前面章节太长了,不得不分开。 这里已源码为主,默认读者已知晓概念或原理,概念或原理可以参考前面章节,有分析。 参考:李柱明博客:https://www.cnblogs.com/lizhuming/p/17438743.html ‍ lwip的时钟机制可以翻看前面章节。 lwip的TCP可靠传传输的实现离不开两个时钟处理函数:

    2024年02月06日
    浏览(42)
  • LwIP系列(3):以太网帧、IP、TCP、UDP、IGMP、ICMP帧格式详解

    TCP/IP 本质上是软件协议,而LwIP也是对软件协议进行解析处理,所以我们有必要了解下以太网帧、IP、TCP、UDP、IGMP、ICMP帧格式,这样在代码中,才能有的放矢。 以太网帧是最底层的原始数据,帧框架如下图所示: 其中【前同步码】和【以太网尾部】我们在抓包的时候,并不

    2024年02月14日
    浏览(36)
  • Artix7 Microblaze下调试SDK官方lwIP RAW Mode TCP Server Application例程(详细说明)

    Vivado 2019.1 FPGA: Artix7 XC7A100T DDR3: MT41K256M16TW-107 PHY: RTL8211F(商业级) 为加快进入application,设置如下: 1.禁用autodetect, phy_link_speed设为100Mbps(此时autonegotiation被禁止,大大加快进入程序) 2.禁用dhcp, 使用默认IP地址设置(不用等待dhcp配置,加快速度) 先对SDK作简单的调整: 1.关闭

    2024年02月09日
    浏览(28)
  • 【正点原子FPGA连载】第三十一章基于lwip的echo server实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

    随着物联网的兴起,万物互联需要一个强大而又灵活的协议体系,TCP/IP协议得天独厚,而在嵌入式网络设备中,由于硬件资源的限制,需要特殊的实现方式。LWIP作为TCP/IP协议的一种轻量级实现方式,满足了这一要求。本章我们利用VITIS软件自带的lwIP Echo Server例程模板,初步了

    2024年02月14日
    浏览(36)
  • 【正点原子FPGA连载】 第三十三章基于lwip的tftp server实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

    文件传输是网络环境中的一项基本应用,其作用是将一台电子设备中的文件传输到另一台可能相距很远的电子设备中。TFTP作为TCP/IP协议族中的一个用来在客户机与服务器之间进行文件传输的协议,常用于无盘工作站、路由器以及远程测控设备从主机上获取引导配置文件,实现

    2024年02月12日
    浏览(29)
  • STM32F4-ETH通信(lwip)——学习笔记

    一、关键知识点: 1、国际标准组织将整个以太网通信结构制定了 OSI 模型,总共分层七个层,分别 为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层,每个层功能不同,通信 中各司其职,整个模型包括硬件和软件定义。OSI 模型是理想分层,一般的网络系

    2024年02月03日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包