实验介绍

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

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

实验基本设置

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

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

RAW/Callback APISocket APINETCONN API

SDK代码

工程配置好后需要添加4个代码文件才能使用udp

lwIP需要启动中断系统,需要sys_intr.c与sys_intr.hUDP使用则需要添加一些初始化和回调函数包含在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主机的地址在网络中心中可以设置

参考资料

学会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

#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_ */

好文推荐

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。