请选择 进入手机版 | 继续访问电脑版
[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-20 基于LWIP UDP的网络摄像头方案

文档创建者:FPGA课程
浏览次数:191
最后更新:2024-10-10
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 2-SDK高级应用方案
本帖最后由 FPGA课程 于 2024-10-10 18:19 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1 概述
本实验通过 uifdma_dbuf + uifdma IP 实现 PL PS 的数据通路部分,把摄像头数据传输到 PS DDR. PS ARM
部分通过 lwip udp 方式把 DDR 中数据发送到上位机,并且显示。
实验目的:
1:掌握 uifdma_dbuf 配置成视频模式的情况下的参数设置
2:掌握 OV5640 摄像头数据如何通过 uifdma_dbuf 写入到 uifdma ip
3:ps 实现 uifdma_dbuf 中断到来,读取 DDR 缓存中的数据
4:设计基于 UDP 方式的摄像头传输方案
5:使用 lwip udp 方式把采集的摄像头数据从 DDR 中发送出去
6:可以通过上位机获取开发板发过来的相机数据,并且显示图像
2 系统构架
本方案中继续保留之前 HDMI 输出的部分,这部分功能没有用到,用户可以自己裁剪掉该功能
2a1e81814961411fb35b85e46985f269.jpg
3 硬件电路分析
本方案使用到了 FEP-GPIO-CEPX3 模块,以及 OV5640 摄像头,模块的介绍请阅读“附录 1”
4 搭建 SOC 系统工程
4.1PL 图形化编程
8094065c0e744676a42460d63d6a2654.jpg

上图中高亮部是 FDMA 的帧同步计数器,CAM0 的帧同步计数器提供给 CAM1 VDMA 输出 IP 使用。单
VDMA 输出 IP 工作于 SLAVE circle 模式,所以 CAM1 VDMA 输出都是从模式同步受控于 CAM0 的帧计数器,
这样可以确保视频不出现撕裂。(本方案中可以优化掉 VDMA 部分,因为不需要显示功能)
另外,我们对 CAM0 CAM1 IP BD 图像模块中做了层级封装,这样可以让复杂的 BD 图像设计,看起
来更加简洁,如下图所示。
986f204c3a9948a8b6be163504db1f61.jpg
这个技巧如下,选中需要层级封装的 IP,右击选择 Create Hierarchy
5b1cad90725740a598df77ec1afb394e.jpg
1:CAM0 中 FDMA IP 设置
关键设置:
1`WBaseaddr 0x10000000 设置缓存的起始地址
2`WDsizebits 设置缓存的大小,2^23 次方代表 8MB 大小
3`WBufsize 设置图像采用三缓存
4`WXsize 设置行像素 640
5`WXStride 设置行 Stride 参数为 1280,改参数用于 2 个视频在一个显存中显示
6`WYsize 设置场像素为 480
ea6b3ab1ab744621b8cabbea5c6e2101.jpg
2:CAM1 中 FDMA IP 设置
1`WBaseaddr 0x1012CA00 设置缓存的起始地址,通过设置该地址可以让图像在指定的偏移位置显示
2`WDsizebits 设置缓存的大小,2^23 次方代表 8MB 大小
3`WBufsize 设置图像采用三缓存
4`WXsize 设置行像素 640
5`WXStride 设置行 Stride 参数为 1280,改参数用于 2 个视频在一个显存中显示
6`WYsize 设置场像素为 480
ec05414707274b0295dac91716fcc9da.jpg
3:视频输出 VDMA IP 设置
f265954c9a034bdcb1c1893af533c2e3.jpg
以下设置视频输出 VDMA 为从模式,帧同步跟随主模式的 CAM0/uifdma_dbuf (本方案中可以优化掉 VDMA 部分,因为不需要显示功能)
16784663ce9e4bd78747ebd38a48ca65.jpg
4:多路视频同屏显示原理
6fcf521202e84f56a4d5f2d3541a484f.jpg
为了把 2 个图像显示到 1 个显示器,首先得搞清楚以下关系:
hsize:每 1 行图像实际在内存中占用的有效空间,以 32bit 表示一个像素的时候占用内存大小为 hsize*4
hstride:用于设置每行图像第一个像素的地址,32bit 表示一个像素的时候 h_cnt* hstride*4
vsize:有效的行
因此很容易得出 cam0 的每行第一个像素的地址也是 h_cnt* hstride*4
同理如果我们需要把 cam1 hsize vsize 空间的任何位置显示,我们只要关心 cam1 每一行图像第一个像素的地
址,可以用以下公式 h_cnt* hstride*4+offset
比如我们这里背景输出到显示器的分辨率为 1280*720,cam1 的分辨率是 640*480 需要移动上图的右下脚,
offset=(1280-640)*4*(720-480)
4.2 设置地址分配
sccb 方式初始化摄像头的地址空间截图
b72294f05cec4a3ea37d1ea685db85b5.jpg
4.3 添加 PIN 约束
1:选中 PROJECT MANAGERà Add SourcesàAdd or create constraints,添加 XDC 约束文件。
0d8d5de804da4a2bbbcfca286e93b683.jpg
2:打开提供例程,复制约束文件中的管脚约束到 XDC 文件,或者查看原理图,自行添加管脚约束,并保存。
以下是添加配套工程路径下已经提供的 pin 脚文件。配套工程的 pin 脚约束文件在 uisrc/04_pin 路径
4.4 编译并导出平台文件
1:单击 Block 文件à右键àGenerate the Output ProductsàGlobalàGenerate
2:单击 Block 文件à右键à Create a HDL wrapper(生成 HDL 顶层文件)àLet vivado manager wrapper and auto-
update(自动更新)
3:生成 Bit 文件。
4:导出到硬件: FileàExport HardwareàInclude bitstream
5:导出完成后,对应工程路径的 soc_hw 路径下有硬件平台文件:system_wrapper.xsa 的文件。根据硬件平台文件
system_wrapper.xsa 来创建需要 Platform 平台。

028fdbabd6174c1b9e7e5574fe6f1577.jpg
5 搭建 Vitis-sdk 工程
创建 soc_base sdk platform APP 工程的过程不再重复,如果不清楚请参考本章节第一个 demo
5.1 创建 SDK Platform 工程
f07f89884dbc4642b6f6326945240d6b.jpg
LWIP 库的修改:
1:新版本系列工业级开发板板载网口芯片是RTL8211FDI,由于默认的驱动不支持,需要手动自己修改库文件。我
们这里已经提供了修改好的库,解压到vivado的安装路径下的对于路径下:
修改好后,需要关闭vitis-sdk然后重新打开sdk,否则无法识别修改的库
2:为了创建lwip工程需要先对zu_base中的board support package简称bsp设置lwip库的支持
b2bf3832c6d445c3a5cc14982c5edacf.jpg
3:对lwip库参数修改以达到最佳性能。
本例程使用 RAW API,即函数调用不依赖操作系统。传输效率也比 SOCKET API 高,(具体可参考 xapp1026)
use_axieth_on_zynq use_emaclite_on_zynq 设为 0。如下图所示。
08accacd03f14bcfa194ba11027a8e7c.jpg
修改 lwip_memory_options 设置,将 mem_sizememp_n_pbufmem_n_tcp_pcbmemp_n_tcp_seg 4 个参数
值设大,这样会提高 TCP 传输效率。如下图所示。
be2288f3cf8c4068810378306f8f46d1.jpg
修改 pbuf_options 设置,将 pbuf_pool_size 设大,增加可用的 pbuf 数量,这样同样会提高 TCP 传输效率。如
下 图所示。
3ce7c1dd2cbb40ccb5b1ee23924677c2.jpg

修改 tcp_options 设置,将 tcp_snd_buftcp_wnd 参数设大,这样同样会提高 TCP 传输效率。如下图所示。
c9f88a4522404166ba0c3e16229900e7.jpg
修改 temac_adapter_options 设置,将 n_rx_descriptors n_tx_descriptors 参数设大。这样可以提高 zynq 内部 emac dma 的数据迁移效率,同样能提高 TCP 传输效率。如下图所示。
df8d37d7c62d43cf83b511f6854fcbc9.jpg
启用 DHCP 功能
97acc54c57ca4922a5c8eb9ace617a67.jpg
修改完成后重新编译 soc_base
5.2 创建 cam_lwip_tcp 工程
f29b7e90b7c94f57be632423301bff84.jpg
6SDK 程序分析
6.1FDMA 数据接收原理
4b9d3179715e4c9d8df4909af682ea55.jpg
每当 uifdmadbuf 发送的中断后,该函数被调用,通过读取 uifdmadbuf axi-lite 的寄存器,获取当前哪一个缓存
产生了中断(代表数据发送到 PS DDR )
为了增加数据的吞吐能力,在中断中,不宜进行数据搬运,我们设计了要给结构体,可以用于标记已经写入
DDR 的数据。
1:PS_RX_intr_Handler
  1. void PS_RX_intr_Handler(void *param)
  2. {
  3. fdma_buf.record[fdma_buf.circle_cnt]= Xil_In32((UINTPTR)FDMA_DBUF_BASE_ADDR);
  4. if(fdma_buf.circle_cnt<2)
  5. fdma_buf.circle_cnt ++ ;
  6. else
  7. fdma_buf.circle_cnt = 0;
  8. fdma_buf.pkg_done_cnt++;
  9. }
复制代码

6.2 数据包设计
Lwip ip 作为轻量级的协议栈,不能一次性发送所有的图像数据,因此需要对图像数据分多次传输。本文中,传输的图像大小为 1280*720*4 = 3600KB,数据设计为每包传输 1024*16 16KB。因此传输完所有数据需要经过 225 次。
  1. #define TCP_PACKEG_SIZE
  2. 1024*16
  3. #define IMG_SIZE
  4. 1280*720*4
  5. #define TCP_SEND_TIMES
  6. IMG_SIZE/TCP_PACKEG_SIZE
  7. #define TCP_SEND_LAST_SIZE
  8. IMG_SIZE-(TCP_PACKEG_SIZE*TCP_SEND_TIMES)
  9. #define TCP_FIRST_SEND_SIZE
  10. HEADER_SIZE + TCP_PACKEG_SIZE
复制代码

6.3 帧头设计
为了让上位机知道接收的数据的格式、大小、当前帧号、当前包号,设计了如下数据帧头:
  1. typedef struct packet_header
  2. {
  3. u32 ID0;//AA55AA55
  4. u32 ID1;//AA55AA55
  5. u16 framcnt;//1,2
  6. u16 hsize;//width
  7. u16 vsize;//height
  8. u16 offset;//
  9. u32 psize; //this packet saize
  10. u32 tsize; //total packet saize
  11. }packet_header;
复制代码


6.4 主程序分析
main 函数中完成中断资源的初始化,lwip 的初始化,并且通过一个 while 循环完成, tcp 连接监听、数据的接
收函数调用、数据的发送函数调用。本文的实验只需要,tcp 连接监听和数据的发送功能。
通过定时器,每间隔 250ms 会判断一次 request_pcb->state 的状态,如果以太网没有连接,则会创建一个新的
TCP 连接。
1:init_intr_sys()
该函数初始化中断,包括 PL 中断和以太网传输需要用到的定时器中断
7105730e02e14ed0934a22caac330aa7.jpg
其中 init_platform 函数会对以太网定时器中断部分以及回调函数进行初始化。
可以关键看下 platform_zynq.c 中被调用的相关函数:
  1. void
  2. timer_callback(XScuTimer * TimerInstance)
  3. {
  4. /* we need to call tcp_fasttmr & tcp_slowtmr at intervals specified
  5. * by lwIP. It is not important that the timing is absoluetly accurate.
  6. */
  7. static int odd = 1;
  8. #if LWIP_DHCP==1
  9. static int dhcp_timer = 0;
  10. #endif
  11. TcpFastTmrFlag = 1;
  12. odd = !odd;
  13. #ifndef USE_SOFTETH_ON_ZYNQ
  14. ResetRxCntr++;
  15. #endif
  16. if (odd) {
  17. TcpSlowTmrFlag = 1;
  18. #if LWIP_DHCP==1
  19. dhcp_timer++;
  20. dhcp_timoutcntr--;
  21. dhcp_fine_tmr();
  22. if (dhcp_timer >= 120) {
  23. dhcp_coarse_tmr();
  24. dhcp_timer = 0;
  25. }
  26. #endif
  27. }
  28. /* For providing an SW alternative for the SI #692601. Under heavy
  29. * Rx traffic if at some point the Rx path becomes unresponsive, the
  30. * following API call will ensures a SW reset of the Rx path. The
  31. * API xemacpsif_resetrx_on_no_rxdata is called every 100 milliseconds.
  32. * This ensures that if the above HW bug is hit, in the worst case,
  33. * the Rx path cannot become unresponsive for more than 100
  34. * milliseconds.
  35. */
  36. #ifndef USE_SOFTETH_ON_ZYNQ
  37. if (ResetRxCntr >= RESET_RX_CNTR_LIMIT) {
  38. xemacpsif_resetrx_on_no_rxdata(&server_netif);
  39. ResetRxCntr = 0;
  40. }
  41. #endif
  42. XScuTimer_ClearInterruptStatus(TimerInstance);
  43. }
  44. void platform_setup_timer(void)
  45. {
  46. int Status = XST_SUCCESS;
  47. XScuTimer_Config *ConfigPtr;
  48. int TimerLoadValue = 0;
  49. ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
  50. Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr,
  51. ConfigPtr->BaseAddr);
  52. if (Status != XST_SUCCESS) {
  53. xil_printf("In %s: Scutimer Cfg initialization failed...\r\n",
  54. __func__);
  55. return;
  56. }
  57. Status = XScuTimer_SelfTest(&TimerInstance);
  58. if (Status != XST_SUCCESS) {
  59. xil_printf("In %s: Scutimer Self test failed...\r\n",
  60. __func__);
  61. return;
  62. }
  63. XScuTimer_EnableAutoReload(&TimerInstance);
  64. /*
  65. * Set for 250 milli seconds timeout.
  66. */
  67. TimerLoadValue = XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 8;
  68. XScuTimer_LoadTimer(&TimerInstance, TimerLoadValue);
  69. return;
  70. }
  71. void platform_setup_interrupts(void)
  72. {
  73. /*
  74. * Connect the device driver handler that will be called when an
  75. * interrupt for the device occurs, the handler defined above performs
  76. * the specific interrupt processing for the device.
  77. */
  78. XScuGic_RegisterHandler(INTC_BASE_ADDR, TIMER_IRPT_INTR,
  79. (Xil_ExceptionHandler)timer_callback,
  80. (void *)&TimerInstance);
  81. /*
  82. * Enable the interrupt for scu timer.
  83. */
  84. XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, TIMER_IRPT_INTR);
  85. return;
  86. }
  87. void platform_enable_interrupts()
  88. {
  89. /*
  90. * Enable non-critical exceptions.
  91. */
  92. Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
  93. XScuTimer_EnableInterrupt(&TimerInstance);
  94. XScuTimer_Start(&TimerInstance);
  95. return;
  96. }
  97. void init_platform()
  98. {
  99. platform_setup_timer();
  100. platform_setup_interrupts();
  101. return;
  102. }
复制代码

2:lwip_init()
初始化 lwip
3:xemac_add ()
添加以太网的 MAC 地址,MAC 地址定义如下:
unsigned char mac_ethernet_address[] ={0x00,0x0a,0x35,0x00,0x01,0x02};
4:netif_set_default()
设置默认的以太网接口,这里定义了一个 server_netif 的全局变量,并且对其初始化。
struct netif server_netif;
netif = &server_netif;
netif_set_default(netif);
5:platform_enable_interrupts()
该函数会使能 platform_zynq.c 中的定时器,启动定时器,这样每间隔 250msTcpFastTmrFlag 变量就会设设置 1,每间隔 500ms TcpSlowTmrFlag 变量就会设置 1
6:启动 DHCP 配置
  1. dhcp_start(netif);
  2. dhcp_timoutcntr = 24;
  3. while (((netif->ip_addr.addr) == 0) && (dhcp_timoutcntr > 0))
  4. xemacif_input(netif);
  5. if (dhcp_timoutcntr <= 0) {
  6. if ((netif->ip_addr.addr) == 0) {
  7. xil_printf("ERROR: DHCP request timed out\r\n");
  8. assign_default_ip(&(netif->ip_addr),
  9. &(netif->netmask), &(netif->gw));
  10. }
  11. }
复制代码

7:start_appication()
该函数首先
  1. void start_application(void)
  2. {
  3. err_t err;
  4. ip_addr_t remote_addr;
  5. u32_t i;
  6. cam_init();/* 初始化摄像头 */
  7. first_trans_start = 0; /* 该变量判断是否第一次传输 */
  8. client_connected =0; /* 判断是否连接状态 */
  9. #if LWIP_IPV6==1
  10. remote_addr.type= IPADDR_TYPE_V6;
  11. err = inet6_aton(TCP_SERVER_IPV6_ADDRESS, &remote_addr);
  12. #else
  13. err = inet_aton(TCP_SERVER_IP_ADDRESS, &remote_addr); /* 设置服务器IP地址 */
  14. #endif /* LWIP_IPV6 */
  15. if (!err) {
  16. xil_printf("Invalid Server IP address: %d\r\n", err);
  17. return;
  18. }
  19. /* Create Client PCB */
  20. request_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); /* 创建一个客户端PCB */
  21. if (!request_pcb) {
  22. xil_printf("Error in PCB creation. out of memory\r\n");
  23. return;
  24. }
  25. err = tcp_connect(request_pcb, &remote_addr, TCP_CONN_PORT,
  26. tcp_client_connected); /* 设置客户端和主机连接上的回调函数 tcp_client_connected */
  27. if (err) {
  28. xil_printf("Error on tcp_connect: %d\r\n", err);
  29. tcp_client_close(request_pcb);
  30. return;
  31. }
  32. client.client_id = 0;
  33. return;
  34. }
复制代码

8:while 循环
该循环中,每过250ms调用tcp_fasttmr(),每间隔500ms调用tcp_slowTmr()函数。tcp_fasttmr()250ms处理延时发
送的ack报文和fin报文,并且通知上层应用处理数据。tcp_slowTmr()500ms调用,该函数负责超时重传以及移除
TIME-WAIT 足够时间的 PCB,同时将PCBunsent队列中的数据发送出去。一般使用tcp_write();写入数据后,数
据不会马上发送,而是在定时任务中发送。
While循环中还会检测当前连接状体,如果当前连接状态不存在会每间隔250ms重新尝试连接一次。
最后当连接建立后,会调用transfer_data()完成数据从DDR到以太网的发送。
  1. while (1) {
  2. if (TcpFastTmrFlag) {
  3. if(request_pcb->state == CLOSED || (request_pcb->state == SYN_SENT && request_pcb->nrtx ==
  4. TCP_SYNMAXRTX))//check conditions for create new tcp connection
  5. {
  6. start_application();
  7. }
  8. tcp_fasttmr();
  9. TcpFastTmrFlag = 0;
  10. }
  11. if (TcpSlowTmrFlag) {
  12. tcp_slowtmr();
  13. TcpSlowTmrFlag = 0;
  14. }
  15. xemacif_input(netif);
  16. if(client_connected)
  17. transfer_data();
  18. }
复制代码

8:transfer_data()
该函数负责把 DDR 中摄像头的图像数据发送出去,是本方案的核心。该函数会调用 tcp_send_perf_traffic()函数。
9:tcp_send_perf_traffic()函数
FDMA 摄 像 头 的 缓 存 中 存 在 数 据 , 首 选 发 送 帧 头 , 然 后 连 续 发 送 TCP_SEND_TIMES TCP_PACKEG_SIZE 大小的数据包,直到所有数据完成发送。
  1. static err_t tcp_send_perf_traffic(void)
  2. {
  3. err_t err;
  4. u8_t apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
  5. if (c_pcb == NULL) {
  6. return ERR_CONN;
  7. }
  8. #ifdef __MICROBLAZE__
  9. /* Zero-copy pbufs is used to get maximum performance for Microblaze.
  10. * For Zynq A9, ZynqMP A53 and R5 zero-copy pbufs does not give
  11. * significant improvement hense not used. */
  12. apiflags = 0;
  13. #endif
  14. struct tcp_pcb *tpcb = c_pcb;
  15. if (!tpcb)
  16. return;
  17. if(first_trans_start==0)
  18. {
  19. first_trans_start =1;
  20. fdma_buf.circle_cnt=0;
  21. fdma_buf.next=0;
  22. fdma_buf.pkg_done_cnt=0;
  23. fdma_buf.pkg_cnt=0;
  24. fdma_buf.fram_cnt=0;
  25. pkg_psize =0;
  26. pkg_offset =0;
  27. XGpio_DiscreteWrite(&rstn_5640, 1, 0x1);
  28. }
  29. /*当fdma_buf.pkg_done_cnt 大于0标识数据已经从PL发送到DDR,当fdma_buf.pkg_done_cnt 大于2标识缓存溢出*/
  30. if(fdma_buf.pkg_done_cnt> 0 && fdma_buf.pkg_done_cnt<3) //1MB divide in to 64 times
  31. {
  32. /*当TCP发送缓冲区足够发送一包数据,则发送数据*/
  33. if (tcp_sndbuf(tpcb) > TCP_FIRST_SEND_SIZE)
  34. {
  35. /*transmit received data through TCP*/
  36. /*第一小包数据,在数据前面插入帧头*/
  37. if(fdma_buf.pkg_cnt==0)
  38. {
  39. bufaddr = (u8*)(RxBufferPtr[fdma_buf.record[fdma_buf.next]]);//获取地址
  40. header_p = (packet_header *)bufaddr;
  41. header_p->ID0
  42. = HEADER_ID0;
  43. header_p->ID1
  44. = HEADER_ID1;
  45. header_p->hsize
  46. = 1280;
  47. header_p->vsize
  48. = 720;
  49. header_p->tsize
  50. = IMG_SIZE;
  51. header_p->framcnt = fdma_buf.fram_cnt;
  52. header_p->psize
  53. = IMG_SIZE;
  54. header_p->offset = 0;
  55. /*确保cache一致性问题*/
  56. Xil_DCacheInvalidateRange((u32)bufaddr + HEADER_SIZE, TCP_PACKEG_SIZE);
  57. /*数据写入到TCP的发送缓存*/
  58. err = tcp_write(tpcb, bufaddr, TCP_FIRST_SEND_SIZE, apiflags);
  59. /*地址增加帧头偏移*/
  60. bufaddr = bufaddr + HEADER_SIZE;
  61. /*计算累计发送的大小*/
  62. pkg_offset = pkg_offset + TCP_PACKEG_SIZE;
  63. }
  64. else if(fdma_buf.pkg_cnt < TCP_SEND_TIMES) //发送剩余包数据
  65. {
  66. /*计算下一包数据数据首地址*/
  67. bufaddr = bufaddr + TCP_PACKEG_SIZE;
  68. Xil_DCacheInvalidateRange((u32)bufaddr, TCP_PACKEG_SIZE);
  69. err = tcp_write(tpcb, bufaddr, TCP_PACKEG_SIZE, apiflags);
  70. pkg_offset = pkg_offset + TCP_PACKEG_SIZE;
  71. }
  72. else if(TCP_SEND_LAST_SIZE>0) //发送剩余包数据
  73. {
  74. bufaddr = bufaddr + TCP_PACKEG_SIZE;
  75. Xil_DCacheInvalidateRange((u32)bufaddr, TCP_SEND_LAST_SIZE);
  76. err = tcp_write(tpcb, bufaddr, TCP_SEND_LAST_SIZE, apiflags);
  77. pkg_offset = pkg_offset + TCP_SEND_LAST_SIZE;
  78. }
  79. if (err != ERR_OK) {
  80. xil_printf("txperf: Error on tcp_write: %d\r\n", err);
  81. return;
  82. }
  83. err = tcp_output(tpcb);
  84. if (err != ERR_OK) {
  85. xil_printf("txperf: Error on tcp_output: %d\r\n",err);
  86. return;
  87. }
  88. fdma_buf.pkg_cnt++;/*小包计数器*/
  89. /*判断数据是否发送完毕*/
  90. if(pkg_offset == IMG_SIZE)
  91. {
  92. pkg_offset=0;
  93. fdma_buf.fram_cnt++;
  94. fdma_buf.pkg_done_cnt--;
  95. fdma_buf.pkg_cnt = 0;
  96. if(fdma_buf.next<2)
  97. fdma_buf.next++;
  98. else
  99. fdma_buf.next=0;
  100. }
  101. }
  102. }
  103. else if(fdma_buf.pkg_done_cnt > 2) //如果缓存不能处理,通过设置irst_trans_start = 0再次同步
  104. {
  105. xil_printf("error pkg_done_cnt = %d \r\n", fdma_buf.pkg_done_cnt);
  106. first_trans_start = 0;
  107. }
  108. /*
  109. if (client.end_time || client.i_report.report_interval_time) {
  110. u64_t now = get_time_ms();
  111. if (client.i_report.report_interval_time) {
  112. if (client.i_report.start_time) {
  113. u64_t diff_ms = now - client.i_report.start_time;
  114. u64_t rtime_ms = client.i_report.report_interval_time;
  115. if (diff_ms >= rtime_ms) {
  116. tcp_conn_report(diff_ms, INTER_REPORT);
  117. client.i_report.start_time = 0;
  118. client.i_report.total_bytes = 0;
  119. }
  120. } else {
  121. client.i_report.start_time = now;
  122. }
  123. }
  124. }*/
  125. return ERR_OK;
  126. }
复制代码

10:本地 IP 地址设置
在主程序 tcp_lwip_test.c 中定义
  1. #define DEFAULT_IP_ADDRESS
  2. "192.168.137.10"
  3. #define DEFAULT_IP_MASK
  4. "255.255.255.0"
  5. #define DEFAULT_GW_ADDRESS
  6. "192.168.1.1"
复制代码

11:远程主机 IP 设置
在头文件 tcp_client.h
  1. #define TCP_SERVER_IP_ADDRESS "192.168.137.209"
  2. #define TCP_CONN_PORT 5001
复制代码

7 方案演示
7.1 硬件准备
dd5b34de59594dcc962e5bee024adbc8.jpg
4fa89e6e838344ceb0f1de56162af4a5.jpg
7.2 实验结果
24a792ded40d4274a0c662e59b3e8211.jpg































您需要登录后才可以回帖 登录 | 立即注册

本版积分规则