由于实验室项目需求开始学习ZYNQ7000系列开发板,了解zunq的udp通信实现,开发板的自带学习资料有 基于UDP的QSPI Flash bin文件网络烧写实验,该实验的基本原理如下:
首先,在 ZYNQ 的 ARM 中基于 LWIP 库建立一个 UDP,板卡通过网线与电脑连接。脑中通过网络调试助手以 UDP 模式与 ZYNQ 建立 UDP连接。然后,通过络调试助手将 BOOT.bin 文件以二进制形式发送至 ps端,并存储在 ZYNQ 所连接的 DDR 中。最后,当 ps端接收完 bin 文件所有的数据后,网络调试助手发送烧写启动命令,将 bin 文件的数据按顺序一一连续写入 QSPI Flash 中,随后再全部读出与所接收的 bin 文件进行一一比对检验。断电重启板卡,便可验证 bin 文件的更新。
由于我们的最终目的是在pc机上的上位机与zynq实现udp通信并互相发送指令和我们需要的数据,因此在原实验代码的基础上需要做出相应的改动,在此我们将代码改为:zynq的ps端和pc机建立udp连接之后,pc机发送“ start update"指令,zynq接收指令后向pc机发送10000字节大小的数据,(我们只是为了验证两者之间可以成功通信,至于发送的内容可以自己定义),每次发送1024字节,pc机接收数据后打印接收数据的大小,最后打印出所有数据的内容。
zynq端ps部分的相关代码:
/* udp_transmission.c
*
* Created on: 2017Äê1ÔÂ22ÈÕ
* www.osrc.cn
* www.milinker.com
* copyright by nan jin mi lian dian zi www.osrc.cn
*/
#include
#include
#include "lwip/err.h"
#include "lwip/udp.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "xqspips.h"
#include "xil_cache.h"
#include "xil_printf.h"
#include "sleep.h"
#include "udp_transmission.h"
#include "qspi_g128_flash.h"
#define FILE_BASE_ADDR 0x10000000
#define READ_BASE_ADDR 0x11000000
#define WRITE_BASE_ADDR 0x12000000
struct udp_pcb *connected_pcb = NULL;
static struct pbuf *pbuf_to_be_sent = NULL;
static unsigned local_port = 5010; /* server port */
static unsigned remote_port = 7;
volatile u32 file_length = 0;
u8 *file;
u8 *read_buffer;
u8 *write_buffer;
void udp_recv_callback(void *arg, struct udp_pcb *tpcb,
struct pbuf *p, struct ip_addr *addr, u16_t port)
{
struct pbuf *q;
u32 remain_length;
q = p;
xil_printf("get data:%s\r\n",(char *)q->payload);
if(q->tot_len == 12 && (!strcmp("start update", (char *)q->payload)))
{
xil_printf("flash update start!\r\n");
xil_printf("file length of BOOT.bin is %d Bytes\r\n", file_length);
pbuf_free(p);
//create an image that the size is 100*100
u8 *img = NULL;
img = (u8 *) malloc(sizeof(u8) * 10000);
for(int i = 0; i < 10000; i++)
{
if(i < 5000)
img[i] = 2;
if(i > 5000)
img[i] = 1;
}
udp_send_data(img,10000);
//udp_printf("flash update start!\r\n");
/*update flash*/
update_flash(file, read_buffer, write_buffer, file_length);
}
else
{
/*if received ip fragment packets*/
if(q->tot_len > q->len)
{
remain_length = q->tot_len;
while(remain_length > 0)
{
memcpy(file + file_length, q->payload, q->len);
file_length += q->len;
remain_length -= q->len;
/*go to next pbuf pointer*/
q = q->next;
}
}
/*if received no ip fragment packets*/
else
{
memcpy(file + file_length, q->payload, q->len);
file_length += q->len;
}
//xil_printf("udp data come in!%d, %d\r\n", p->tot_len, p->len);
pbuf_free(p);
}
return;
}
*int udp_recv_init()
{
struct udp_pcb *pcb;
struct ip_addr ipaddr;
err_t err;
file = (u8 *)FILE_BASE_ADDR;
read_buffer = (u8 *)READ_BASE_ADDR;
write_buffer = (u8 *)WRITE_BASE_ADDR;
/* create new UDP PCB structure */
pcb = udp_new();
if (!pcb) {
xil_printf("Error creating PCB. Out of Memory\r\n");
return -1;
}
/* bind to local port */
err = udp_bind(pcb, IP_ADDR_ANY, local_port);
if (err != ERR_OK) {
xil_printf("udp_recv_init: Unable to bind to port %d: err = %d\r\n", local_port, err);
return -2;
}
IP4_ADDR(&ipaddr, 192, 168, 1, 100);
err = udp_connect(pcb, &ipaddr, remote_port);
if (err != ERR_OK)
xil_printf("error on udp_connect: %x\n\r", err);
udp_recv(pcb, udp_recv_callback, NULL);
connected_pcb = pcb;
return 0;
}
void udp_printf(const char8 *ctrl1)
{
char * message;
u16 length;
int i;
err_t err;
struct udp_pcb *tpcb = connected_pcb;
if (!tpcb)
{
xil_printf("error return\r\n");
return;
}
message = (char *)ctrl1;
i = 0;
while(!(message[i] == '\n'))
{
i++;
}
length = i;
/*make sure the shortest data is 18 bytes(because shortest ip packet is 46 bytes)*/
if(length < 18)
{
pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 18, PBUF_POOL);
memset(pbuf_to_be_sent->payload, 0, 18);
}
else
{
pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_POOL);
}
memcpy(pbuf_to_be_sent->payload, (u8 *)message, length);
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);
}
void udp_send_data(const u8 *ctrl1, int length)
{
const u8 * message;
//u16 length;
//int i;
err_t err;
struct udp_pcb *tpcb = connected_pcb;
if (!tpcb)
{
xil_printf("error return\r\n");
return;
}
message = ctrl1;
// i = 0;
// while(!(message[i] == '\n'))
// {
// i++;
// }
// length = i;
/*make sure the shortest data is 18 bytes(because shortest ip packet is 46 bytes)*/
xil_printf("start send data\r\n");
while(length>0)
{
xil_printf("length: %d\r\n", length);
// if(length < 18)
// {
// pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 16, PBUF_POOL);
// memset(pbuf_to_be_sent->payload, 0, 16);
//
// }
// else
// {
if(length >= 1024)
{
pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT, 1024, PBUF_POOL);
memcpy(pbuf_to_be_sent->payload, message, 1024);
message += 1024;
}
else
{
pbuf_to_be_sent = pbuf_alloc(PBUF_TRANSPORT,length, PBUF_POOL);
memcpy(pbuf_to_be_sent->payload, message, length);
message += length;
}
//}
//message += length;
err = udp_send(tpcb, pbuf_to_be_sent);
//sleep(3000);
if (err != ERR_OK)
{
xil_printf("Error on udp_send: %d\r\n", err);
pbuf_free(pbuf_to_be_sent);
return;
}
length -= 1024;
//sleep(3);
}
pbuf_free(pbuf_to_be_sent);
}
**************************************************************分割线***************
main.c
/*
*
* www.osrc.cn
* www.milinker.com
* copyright by nan jin mi lian dian zi www.osrc.cn
*
*
*/
#include "sys_intr.h"
#include "qspi_g128_flash.h"
#include "xqspips.h"
#include "lwip/err.h"
#include "lwipopts.h"
#include "netif/xadapter.h"
#include "lwipopts.h"
#include "xil_cache.h"
#include "udp_transmission.h"
static XScuGic Intc; //GIC
XQspiPs QspiInstance;
#define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID
extern void lwip_init(void);
void init_intr_sys(void)
{
Init_Intr_System(&Intc); // initial interrupt system
Setup_Intr_Exception(&Intc);
}
int main(void)
{
int Status;
struct netif *netif, server_netif;
struct ip_addr ipaddr, netmask, gw;
/* the mac address of the board. this should be unique per board */
unsigned char mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
/* Flush the Data Cache*/
Xil_DCacheFlush();
/* Disable Data Cache */
Xil_DCacheDisable();
// Xil_DCacheEnable();
Status = Init_qspi(&QspiInstance, QSPI_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("QSPI init Failed\r\n");
return XST_FAILURE;
}
init_intr_sys();
netif = &server_netif;
IP4_ADDR(&ipaddr, 192, 168, 1, 10);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
/*lwip library init*/
lwip_init();
/* Add network interface to the netif_list, and set it as default */
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);
/* specify that the network if is up */
netif_set_up(netif);
/* initialize tcp pcb */
udp_recv_init();
xil_printf("udp_start\r\n");
while (1)
{
/*receive input packet from emac*/
xemacif_input(netif);//将MAC队列里的packets传输到你的LwIP/IP stack里
}
return 0;
}
PC端的代码(环境是vs2013)
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#pragma comment(lib, "ws2_32.lib")
using
namespace cv;
using
namespace std;
int main(int argc, char* argv[])
{
int serlen = 0;
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 2);
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (serSocket == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
//SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//if (sclient == INVALID_SOCKET)
//{
// printf("socket error !");
// return 0;
//}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(7);
serAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.100");//pc de ip
int ser_len = sizeof(serAddr);
if (bind(serSocket, (sockaddr *)&serAddr, ser_len) == SOCKET_ERROR)
{
printf("bind error !");
closesocket(serSocket);
return 0;
}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(5010);
sin.sin_addr.S_un.S_addr = inet_addr("192.168.1.10");//板子的ip
//sin.
int len = sizeof(sin);
char sendData[] = "start update";
//sendto(sclient, sendData, 4, 0, (sockaddr *)&sin, len);
char recvData[1024] = { 0 };
unsigned char *r_data = NULL;
r_data = (unsigned char *)malloc(sizeof(unsigned char) * 10000);
memset(r_data, 0, 10000);
sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&sin, len);
int r_data_len=0;
while (r_data_len < 10000)
{
int ret = recvfrom(serSocket, recvData, 1024, 0, (sockaddr *)&sin, &len);
for (int i = 0; i < ret; i++)
{
//putchar(r_data[i]);
printf("%d", (int)recvData[i]);
}
//printf("接受到一个连接:%s \r\n", inet_ntoa(sin.sin_addr));
printf("已接收到的数据长度为:%d 字节\n", r_data_len);
memcpy(r_data + r_data_len, recvData, ret);
r_data_len += ret;
}
//printf("收到的数据是:%s ", *r_data);
printf("接收到的数据长度为:%d字节\n ", r_data_len);
for (int i = 0; i < 10000; i++)
{
//putchar(r_data[i]);
printf("%d",(int)r_data[i]);
}
closesocket(serSocket);
WSACleanup();
getchar();
return 0;
}
本实验中zynq的ps端的ip地址为192.168.1.10 端口号为5010,pc端的ip地址为192.168.1.100,端口号为7。
本实验比较简单,后期需要将pl端的图像数据通过DMA方式传给ps的DDR中,然后通过网络传给上位机中并进行算法的实现。
希望也在做相关工作的小伙伴能够一起交流学习。