• zcu106 lwip搭建以太网配置寄存器


    实验一
    1.配置网口GEM3

    image-20221130154415671

    2.导出xsa文件,在vitis中创建工程,选择freertos10_xilinx的操作系统来使用

    image-20221130190131167

    3.配置lwip211,选择SOCKET API的模式

    image-20221130161930948

    4.创建工程 选择FreeRTOS Iwip TCP Perf Server模板

    image-20221130163247489

    5.代码分析
    main.c

    配置服务器端的ip地址 掩码 网关

    #define DEFAULT_IP_ADDRESS "192.168.137.11"  //IP
    #define DEFAULT_IP_MASK "255.255.255.0"    //掩码
    #define DEFAULT_GW_ADDRESS "192.168.1.1"   //网关
    
    • 1
    • 2
    • 3

    main函数使用sys_thread_new新建了一个线程调用了main_thread,使用vTaskStartScheduler启动任务调度。

    int main()
    {
    	main_thread_handle = sys_thread_new("main_thread", main_thread, 0,
    			THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
    	vTaskStartScheduler();
    	while(1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    main_thread函数调用其他线程network_thread

    void main_thread(void *p)
    {
    #if ((LWIP_IPV6==0) && (LWIP_DHCP==1))
    	int mscnt = 0;
    #endif
    
    #ifdef XPS_BOARD_ZCU102
    	IicPhyReset();
    #endif
    	/* initialize lwIP before calling sys_thread_new */
    	lwip_init();   /* 初始化lwip */
    
    	/* any thread using lwIP should be created using sys_thread_new */
    	sys_thread_new("nw_thread", network_thread, NULL,
    			THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
    	/* 申请线程network_thread  */
    	/* Suspend Task until auto-negotiation is completed */
    	if (!complete_nw_thread)
    		vTaskSuspend(NULL);
    
    #if LWIP_IPV6==0
    #if LWIP_DHCP==1   /* 默认不开启DHCP */
    	while (1) {
    		vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
    		if (server_netif.ip_addr.addr) {
    			xil_printf("DHCP request success\r\n");
    			break;
    		}
    		mscnt += DHCP_FINE_TIMER_MSECS;
    		if (mscnt >= 10000) {
    			xil_printf("ERROR: DHCP request timed out\r\n");
    			assign_default_ip(&(server_netif.ip_addr),
    						&(server_netif.netmask),
    						&(server_netif.gw));
    			break;
    		}
    	}
    
    #else
    	assign_default_ip(&(server_netif.ip_addr), &(server_netif.netmask),
    				&(server_netif.gw));
    #endif
    
    	print_ip_settings(&(server_netif.ip_addr), &(server_netif.netmask),
    				&(server_netif.gw));   /* 打印IP的有关信息 */
    #endif /* LWIP_IPV6 */
    
    	xil_printf("\r\n");
    
    	/* print all application headers */
    	print_app_header();  /* 打印连接的端口,打印提示*/
    	xil_printf("\r\n");
    
    	/* start the application*/
    	start_application(); /* 运行应用 */
    
    	vTaskDelete(NULL);
    	return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    network_thread函数配置lwip网络连接

    void network_thread(void *p)
    {
    #if ((LWIP_IPV6==0) && (LWIP_DHCP==1))
    	int mscnt = 0;
    #endif
    
    	/* the mac address of the board. this should be unique per board */
    	u8_t mac_ethernet_address[] = { 0x00, 0x0a, 0x35, 0x00, 0x01, 0x02 };
    	/* 配置MAC地址 */
    
    	xil_printf("\n\r\n\r");
    	xil_printf("-----lwIP Socket Mode TCP Server Application------\r\n");
    
    	/* Add network interface to the netif_list, and set it as default */
    	if (!xemac_add(&server_netif, NULL, NULL, NULL, mac_ethernet_address,
    		PLATFORM_EMAC_BASEADDR)) {
    		xil_printf("Error adding N/W interface\r\n");
    		return;
    	}
    	/* 将mac地址加入netif_list */
    
    #if LWIP_IPV6==1
    	server_netif.ip6_autoconfig_enabled = 1;
    	netif_create_ip6_linklocal_address(&server_netif, 1);
    	netif_ip6_addr_set_state(&server_netif, 0, IP6_ADDR_VALID);
    	print_ipv6("\n\rlink local IPv6 address is:",&server_netif.ip6_addr[0]);
    #endif /* LWIP_IPV6 */
    
    	netif_set_default(&server_netif);
    
    	/* specify that the network if is up */
    	netif_set_up(&server_netif);   /* 设置为默认的network */
    
    	/* start packet receive thread - required for lwIP operation */
    	sys_thread_new("xemacif_input_thread",
    			(void(*)(void*))xemacif_input_thread, &server_netif,
    			THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
    
    	/* 开启packet的接受线程xemacif_input_thread */
    	complete_nw_thread = 1;
    
    	/* Resume the main thread; auto-negotiation is completed */
    	vTaskResume(main_thread_handle);
    	/* 恢复主线程,自动协商恢复 */
    
    #if ((LWIP_IPV6==0) && (LWIP_DHCP==1))
    	dhcp_start(&server_netif);
    	while (1) {
    		vTaskDelay(DHCP_FINE_TIMER_MSECS / portTICK_RATE_MS);
    		dhcp_fine_tmr();
    		mscnt += DHCP_FINE_TIMER_MSECS;
    		if (mscnt >= DHCP_COARSE_TIMER_SECS*1000) {
    			dhcp_coarse_tmr();
    			mscnt = 0;
    		}
    	}
    #else
    	vTaskDelete(NULL);
    #endif
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    freertos_tcp_perf_server.c

    start_application函数是执行时的数据传输

    void start_application(void)
    {
    	int sock, new_sd;
    #if LWIP_IPV6==1
    	struct sockaddr_in6 address, remote;
    #else
    	struct sockaddr_in address, remote;
    #endif /* LWIP_IPV6 */
    	int size;
    
    	/* set up address to connect to */
            memset(&address, 0, sizeof(address));
    #if LWIP_IPV6==1
    	if ((sock = lwip_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
    		xil_printf("TCP server: Error creating Socket\r\n");
    		return;
    	}
    	address.sin6_family = AF_INET6;
    	address.sin6_port = htons(TCP_CONN_PORT);
    	address.sin6_len = sizeof(address);
    #else
    	if ((sock = lwip_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    		xil_printf("TCP server: Error creating Socket\r\n");
    		return;
    	}
    	address.sin_family = AF_INET;
    	address.sin_port = htons(TCP_CONN_PORT);
    	address.sin_addr.s_addr = INADDR_ANY;
    	/* 设置socket的套接字网络连接 */
    #endif /* LWIP_IPV6 */
    
    	if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0) {
    		xil_printf("TCP server: Unable to bind to port %d\r\n",
    				TCP_CONN_PORT);
    		close(sock);
    		return;
    	}
    	/* bind函数 */
    
    	if (listen(sock, 1) < 0) {
    		xil_printf("TCP server: tcp_listen failed\r\n");
    		close(sock);
    		return;
    	}
    	/* listen监听函数实现 */
    
    	size = sizeof(remote);
    
    	while (1) {
    		if ((new_sd = accept(sock, (struct sockaddr *)&remote,
    						(socklen_t *)&size)) > 0)
    			sys_thread_new("TCP_recv_perf thread",
    				tcp_recv_perf_traffic, (void*)&new_sd,
    				TCP_SERVER_THREAD_STACKSIZE,
    				DEFAULT_THREAD_PRIO);
    			/* accept函数接受客户端网络连接,开启一个新的线程*/
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    tcp_recv_perf_traffic函数执行数据传输

    /* thread spawned for each connection */
    void tcp_recv_perf_traffic(void *p)
    {
    	char recv_buf[RECV_BUF_SIZE];
    	int read_bytes;
    	int sock = *((int *)p);
    
    	server.start_time = sys_now() * portTICK_RATE_MS;
    	server.client_id++;
    	server.i_report.last_report_time = 0;
    	server.i_report.start_time = 0;
    	server.i_report.total_bytes = 0;
    	server.total_bytes = 0;
    
    	print_tcp_conn_stats(sock);  /* 打印TCP*/
    
    	while (1) {
    		/* read a max of RECV_BUF_SIZE bytes from socket */
    		if ((read_bytes = lwip_recvfrom(sock, recv_buf, RECV_BUF_SIZE,
    						0, NULL, NULL)) < 0) {
    			u64_t now = sys_now() * portTICK_RATE_MS;
    			u64_t diff_ms = now - server.start_time;
    			tcp_conn_report(diff_ms, TCP_ABORTED_REMOTE);
    			break;
    		}
    		/* lwip_recvfrom接受1500字节的数据*/
    
    		/* break if client closed connection */
    		if (read_bytes == 0) {
    			u64_t now = sys_now() * portTICK_RATE_MS;
    			u64_t diff_ms = now - server.start_time;
    			tcp_conn_report(diff_ms, TCP_DONE_SERVER);
    			xil_printf("TCP test passed Successfully\n\r");
    			break;
    		}
    		/* 如果接受数据大小为0,说明TCP测试已经通过了 */
    
    		if (REPORT_INTERVAL_TIME) {
    			u64_t now = sys_now() * portTICK_RATE_MS;
    			server.i_report.total_bytes += read_bytes;
    			if (server.i_report.start_time) {
    				u64_t diff_ms = now - server.i_report.start_time;
    
    				if (diff_ms >= REPORT_INTERVAL_TIME) {
    					tcp_conn_report(diff_ms, INTER_REPORT);
    					server.i_report.start_time = 0;
    					server.i_report.total_bytes = 0;
    				}
    			} else {
    				server.i_report.start_time = now;
    			}
    		}
    		/* Record total bytes for final report */
    		/* 记录接受的总数据量大小 */
    		server.total_bytes += read_bytes;
    	}
    
    	/* close connection */
    	close(sock);
    	vTaskDelete(NULL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    freertos_tcp_perf_server.h

    服务器端使用的端口号是5001

    /* server port to listen on/connect to */
    #define TCP_CONN_PORT 5001
    
    • 1
    • 2
    6.流程梳理
    main_thread_handle
    -> main_thread(lwip_init) 
    	-> network_thread
    	-> start_application
    		->lwip_socket(bind listen accept)
    			-> tcp_recv_perf_traffic
    				->lwip_recvfrom
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    7.网络测试
    ping 192.168.137.11 -t  //循环ping目标
    
    iperf -c 192.168.137.10 -p 5001 -i 5 -t 30 -w 2M
    -c 客户端连接服务器的ip
    -p 服务端的端口号
    -i 打印带宽的时间间隔
    -t 测试带宽时间为30s
    -w 使用的包窗口大小
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20221130185725992

    从图中可见,网速大小可以达到85Mbits/sec左右,大概是百兆以太网的速度大小,可以在lwip那里修改一些参数去调大它。

    实验二
    1.配置block design

    AXI_HPM0 FPD interface 32位

    image-20221130215724334

    image-20221130221234812

    2.配置conf_list核,存放在lwip_tcp.ipdef/conf_reg_list下面

    在这里插入图片描述

    conf_list_v1_0_S00_AXI.v

    (
    		// Users to add ports here
            output reg[31:0] hdmi_bit_sel,
            output reg[31:0] img_width,
            output reg[31:0] img_high,
    		// User ports ends
    		// Do not modify the ports beyond this line
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    // Add user logic here
        always @(posedge S_AXI_ACLK) begin
             if ( S_AXI_ARESETN == 1'b0 ) begin
                hdmi_bit_sel <= 0;
                img_width <= 0;
                img_high <= 0;
             end
             else begin
                hdmi_bit_sel <= slv_reg0;
                img_width <= slv_reg1;
                img_high <= slv_reg2;
             end
         end
    	// User logic ends
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    conf_list_v1_0.v

    // Users to add ports here
            output wire[31:0] hdmi_bit_sel,
            output wire[31:0] img_width,
            output wire[31:0] img_high,
    		// User ports ends
    		// Do not modify the ports beyond this line
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    // Instantiation of Axi Bus Interface S00_AXI
    	conf_list_v1_0_S00_AXI # ( 
    		.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
    		.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
    	) conf_list_v1_0_S00_AXI_inst (
    	    .hdmi_bit_sel(hdmi_bit_sel),
    	    .img_width(img_width),
    	    .img_high(img_high),
    		.S_AXI_ACLK(s00_axi_aclk),
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    3.vitis开发

    lwip_send(int s, const void* dataptr, size_t size,int flags)

    其中s是socket,dataptr是数据,size是数据大小,flag默认为0

    需要判断收到的数据的前8位都是55,然后把对应地址的数据取出来放到对应的IP里面

    conf_list.h
    #include "Xil_io.h"
    
    #define CONF_LIST_mWriteReg(BaseAddress, RegOffset, Data) \
    Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data))
    
    #define CONF_LIST_mReadReg(BaseAddress, RegOffset) \
    Xil_In32((BaseAddress) + (RegOffset))
    
    void write_conf_list(u32 BaseAddr, u32 RegAddr, u32 Data);
    u32 read_conf_list(u32 BaseAddr, u32 RegAddr);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    conf_list.c
    #include "conf_list.h"
    
    void write_conf_list(u32 BaseAddr, u32 RegAddr, u32 Data)
    {
    	CONF_LIST_mWriteReg(BaseAddr, RegAddr<<2,Data); //RegAddr*4
    }
    
    u32 read_conf_list(u32 BaseAddr, u32 RegAddr)
    {
    	return CONF_LIST_mReadReg(BaseAddr, RegAddr<<2); //RegAddr*4
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    freertos_tcp_perf_server.c
    #include "conf_list.h"
    #include "Xil_io.h"
    #define REGBASEADDR 0X00A0000000
    
    u32 imagewidth;
    u32 imagehigh;
    u32 readback; //0表示写,1表示读
    
    void tcp_recv_perf_traffic(void *p) {
        
    //lwip_send(sock, recv_buf, 14, 0);
    		if(recv_buf[0] == 0x55 && recv_buf[1] == 0x55 && recv_buf[2] == 0x55 && recv_buf[3] == 0x55 && recv_buf[4] == 0x55 && recv_buf[5] == 0x55 && recv_buf[6] == 0x55 && recv_buf[7] == 0x55)
    		{
    		    u32 regaddr;
    		    u8 rwnflag;
    		    u32 regdata;
    		    regaddr = recv_buf[8];
    		    rwnflag = recv_buf[9];
    		    if(rwnflag == 0) {
    		        //write register
    		        regdata = recv_buf[10]<<24;
    		        regdata |= recv_buf[11]<<16;
    		        regdata |= recv_buf[12]<<8;
    		        regdata |= recv_buf[13]<<0;
    		        if(regaddr == 1)
    		            imagewidth = regdata;
    		        else if(regaddr == 2)
    		            imagehigh = regdata;
    		        else if(regaddr == 3)
    		            readback = regdata;
    		        write_conf_list(REGBASEADDR, regaddr, regdata);
    		        regdata = read_conf_list(REGBASEADDR, regaddr);
    		        recv_buf[10] = (regdata>>24) & 0XFF;
    		        recv_buf[11] = (regdata>>16) & 0XFF;
    		        recv_buf[12] = (regdata>>8) & 0XFF;
    		        recv_buf[13] = (regdata>>0) & 0XFF;
    		        if(lwip_send(sock,recv_buf,read_bytes,0) < 0)
    		        {
    		            xil_printf("%s: Send Error!\r\n", sock);
    		        }
    		    }
    		    else {
    		        //read register
    		        regdata = read_conf_list(REGBASEADDR, regaddr);
    		        recv_buf[10] = (regdata>>24) & 0XFF;
    		        recv_buf[11] = (regdata>>16) & 0XFF;
    		        recv_buf[12] = (regdata>>8) & 0XFF;
    		        recv_buf[13] = (regdata>>0) & 0XFF;
    		        if(lwip_send(sock,recv_buf,read_bytes,0) < 0)
    		        {
    		            xil_printf("%s: Send Error!\r\n", sock);
    		        }
    		    }
    		}
    if(read_byte == 0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    4.实验结果

    image-20221201170040853

    能够通过网口去修改hdmi_bit_sel,img_width以及img_high。

  • 相关阅读:
    【SpringBoot框架篇】28.使用JdbcTemplate操作数据库
    教程分享 | 如何获取港口网(全球船舶点和路径)的数据
    面试五 -bind 和 function
    矩阵知识补充
    6.2、Flink数据写入到Kafka
    数组扁平化 和 线性结构(数组)转换树结构
    移动端(Android、iOS)内存泄漏检测方法
    antd tree 懒加载+局部刷新
    一种非线性动态自适应惯性权重PSO算法-附代码
    拦截|篡改|伪造.NET类库中不限于public的类和方法
  • 原文地址:https://blog.csdn.net/qq_38863842/article/details/128135447