[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_UDP篇连载-04基于UDP的网络摄像头方案

文档创建者:FPGA课程
浏览次数:310
最后更新:2024-09-12
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 4-FPGA UDP通信
本帖最后由 FPGA课程 于 2024-9-12 08:51 编辑

​ 软件版本: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概述
在前面的课程中,我们基于不同的通信方式,分别实现了:
  • 基于PHY芯片RGMII接口实现的千兆以太网UDP通信
  • 基于高速GTP/GTX通过SFP+接口实现的千兆以太网UDP通信
  • 基于高速GTX通过SFP+接口实现的万兆以太网通信(A7系列开发板不支持万兆以太网)
以上通信实际上都详细展示了UDP通信的实现方式,而本文是基于之前的demo增加摄像头采集部分,以及通过DDR实现图像数据的缓存。采集到的图像通过以上任何一种方式把图像数据发动到电脑上,并且通过电脑的上位机显示图像。
2系统框图
本系统采用摄像头输入采用OV5640,I2C的寄存器配置采用Milianke uiSensorRGB565 IP配置。通过Milianke uifdma_dbuf将数据写入DDR。上位机使用太网通过AXI Interconnect IP读取存放在DDR中的摄像头数据。

96ec71452fb1429198606a369a6be911.jpg
3FPGA程序设计
3.1blockdesign设计
这张图的设计和DDR部分的摄像头采集部分一样,主要是配合“米联客”自定义IP FDMA实现数据缓存到DDR,和从DDR读出。在DDR部分的例子数据读出后就在显示器上显示了,而这里我们需要通过以太网发送给电脑。关于FDMA IP的应用可以参考DDR部分例子。
771ca19add304d8e8cd21d43dcbef3de.jpg
3.2图像数据格式
以下代码是上位机的帧头部分定义,用上位机定义图像的格式很容易理解。由于UDP一包数据最大是1472字节,所以这里一副1280*720(用户可以修改分辨率)数据格式为RGB888的图像,UDP传输需要分720*3次传输完成,每次传输32字节的帧头和1280字节的图像数据。
  1. #define FLAG_HEAD   0xAA0055FF
  2. struct stHeader
  3. {
  4.     quint32 flag;       //固定为  FLAG_HEAD 对数据合法性判断,防止其他数据干扰
  5.     quint32 width;      //图片宽度  例如 1280
  6.     quint32 height;     //图片高度  例如 720
  7.     quint32 total;      //一张图片总大小   例如  1280*720*3
  8.     quint32 offset;     //当前数据偏移量   例如,第一帧数据为0, 第n帧数据为 (n-1)*framesize
  9.     quint32 picseq;     //图片序号,第几张图片
  10.     quint32 frameseq;   //一张图片发送的帧序号,当前图片的第n帧 ,从1~ 720*3
  11.     quint32 framesize;  //当前帧图片数据大小 例如每一次都发有效图片数据大小为1280
  12.     quint8 data[0];     //有效图片数据
  13. };
复制代码


有了以上代码的参考设计FPGA的图像帧数据就简单了一些。以下给出master_ch中关键的图像帧定义,以及以FPGA的方式发送帧数据的代码。通过FDMA获取的数据是128bit位宽(4个32bit XRGB格式的数据)而我们上位机需要的是RGB888所以是需要去掉无效的一个字节数据去掉,并且以RGB888 24bit数据紧密排列。详细的代码阅读配套的demo中代码。
  1. localparam       IMG_HEADER     = 32'hAA0055FF;
  2. localparam       IMG_WIDTH       = 32'd1280;
  3. localparam       IMG_HEIGHT      = 32'd720;
  4. localparam       IMG_TOTAL       = IMG_WIDTH*IMG_HEIGHT*3;
  5. localparam       IMG_FRAMSIZE    = 32'd1280;
  6. localparam       IMG_FRAMTOTAL   = IMG_HEIGHT*3;
  7. localparam       IMG_HEADER_LEN  = 6'd32;//4个64bit
  8. reg  [31 :0]    IMG_FRAMSEQ;
  9. reg  [31 :0]    IMG_PICSEQ;
  10. wire [31 :0]    IMG_OFFSET      = (IMG_FRAMSEQ-1'b1) * IMG_FRAMSIZE;
  11. wire [255:0]    STHEADER_X86    = {IMG_FRAMSIZE,IMG_FRAMSEQ,IMG_PICSEQ,IMG_OFFSET,IMG_TOTAL,IMG_HEIGHT,IMG_WIDTH,IMG_HEADER};
  12.                                    
  13. wire [0 :0]     ui_rstn;
  14. wire            ui_clk;
  15. wire            cfg_done;
  16. wire            R0_rclk_i = clk_15_625;
  17. wire [127:0]    R0_data_o;
  18. reg  [127:0]    R0_data_r;
  19. wire            R0_rdy_o;
  20. wire            R0_rden_i;
  21. reg             R0_FS_i;
  22. reg  [1 :0]     R0_INDEX;

  23. always@(posedge clk_15_625 or posedge core_reset)begin
  24.     if(core_reset) begin
  25.         app_tx_data <= 64'd0;
  26.         R0_data_r   <= 128'd0;
  27.     end
  28.     else begin
  29.         if(UDP_MS == S_UDP_ACK || UDP_MS == S_IMG_HEADER)begin
  30.             app_tx_data <= STHEADER_X86[app_tx_header_cnt*8 +: 64];
  31.         end
  32.         else if(UDP_MS == S_IMG_DATA)begin
  33.             R0_data_r <= R0_data_o;
  34.             case(R0_INDEX)
  35.             0:begin app_tx_data <={R0_data_o[47 : 40],R0_data_o[55 : 48],R0_data_o[71 : 64],R0_data_o[79 : 72],R0_data_o[87 : 80],R0_data_o[103: 96],R0_data_o[111:104],R0_data_o[119:112]};end
  36.             1:begin app_tx_data <={R0_data_o[87 : 80],R0_data_o[103: 96],R0_data_o[111:104],R0_data_o[119:112],R0_data_r[7  :  0],R0_data_r[15 : 8 ],R0_data_r[23 : 16],R0_data_r[39 : 32]};end
  37.             2:begin app_tx_data <={R0_data_r[7  :  0],R0_data_r[15 : 8 ],R0_data_r[23 : 16],R0_data_r[39 : 32],R0_data_r[47 : 40],R0_data_r[55 : 48],R0_data_r[71 : 64],R0_data_r[79 : 72]};end
  38.             default:begin app_tx_data <= app_tx_data; end
  39.             endcase
  40.         end
  41.         else begin
  42.             app_tx_data <= app_tx_data;
  43.         end
  44.     end
  45. end

  46. eg  [11:0] vstout_cnt;
  47. wire [15:0] PACKET_INTERVAL;
  48. reg  [15:0] delay_cnt;
  49. always@(posedge clk_15_625 or posedge core_reset)
  50. begin
  51.     if(core_reset) begin
  52.         delay_cnt <= 16'd0;
  53.     end
  54.     else begin
  55.         if(delay_cnt < PACKET_INTERVAL)
  56.             delay_cnt <= delay_cnt + 1'b1;
  57.         else
  58.             delay_cnt <= 16'd0;
  59.     end
  60. end

  61. wire pkg_tx_en = (delay_cnt == PACKET_INTERVAL);
  62. vio_0 vio_debug(.clk(clk_15_625),.probe_out0(PACKET_INTERVAL));

  63. assign R0_rden_i = (R0_INDEX == 2'd0 || R0_INDEX == 2'd2)&& (UDP_MS == S_IMG_DATA );

  64. always@(posedge clk_15_625 or posedge core_reset)
  65. begin
  66.     if(core_reset) begin
  67.        app_tx_data_valid <= 1'b0;
  68.        app_tx_header_cnt <= 8'd0;
  69.        app_tx_data_cnt   <= 12'd0;
  70.        app_tx_data_last  <= 1'b0;
  71.        R0_FS_i           <= 1'b0;
  72.        IMG_PICSEQ        <= 32'd0;
  73.        IMG_FRAMSEQ       <= 32'd0;
  74.        vstout_cnt        <= 12'd0;
  75.        UDP_MS            <= S_SYNC_1;
  76.     end
  77.     else begin
  78.        case(UDP_MS)
  79.        S_SYNC_1:begin
  80.          vstout_cnt  <= 12'd0;
  81.          R0_INDEX    <= 2'd0;
  82.          R0_FS_i     <= 1'b0;
  83.          IMG_FRAMSEQ <= 32'd0;
  84.          IMG_PICSEQ  <= IMG_PICSEQ + 1'b1;
  85.          UDP_MS      <= S_SYNC_2;
  86.        end
  87.        S_SYNC_2:begin
  88.          UDP_MS      <= S_SYNC_3;
  89.        end
  90.        S_SYNC_3:begin
  91.          R0_FS_i     <= 1'b1;
  92.          vstout_cnt <= vstout_cnt + 1'b1;
  93.          if(R0_rdy_o)begin
  94.             UDP_MS      <= S_UDP_WAIT;
  95.          end
  96.          else if(vstout_cnt[11])
  97.             UDP_MS <= S_SYNC_1;
  98.        end
  99.        S_UDP_WAIT:begin
  100.           app_tx_header_cnt <= 8'd0;
  101.           app_tx_data_cnt   <= 12'd0;
  102.           if(udp_tx_ready&&pkg_tx_en) begin
  103.               app_tx_data_req <= 1'b1;UDP_MS <= S_UDP_ACK;
  104.            end
  105.            else begin
  106.                app_tx_data_req <= 1'b0;UDP_MS <= S_UDP_WAIT;
  107.            end
  108.        end
  109.       
  110.        S_UDP_ACK:begin
  111.           if(app_tx_ack) begin
  112.                app_tx_data_req     <= 1'b0;
  113.                app_tx_data_valid   <= 1'b1;
  114.                app_tx_header_cnt   <= app_tx_header_cnt + 8;
  115.                IMG_FRAMSEQ         <= IMG_FRAMSEQ + 1'b1;
  116.                UDP_MS <= S_IMG_HEADER;
  117.            end
  118.            else if(dst_ip_unreachable) begin
  119.                app_tx_data_req   <= 1'b0;app_tx_data_valid <= 1'b0;UDP_MS <= S_SYNC_1;
  120.            end
  121.            else begin
  122.                app_tx_data_req   <= 1'b1;app_tx_data_valid <= 1'b0;UDP_MS <= S_UDP_ACK;
  123.             end
  124.          end
  125.          
  126.          S_IMG_HEADER:begin
  127.             app_tx_data_valid   <= 1'b1;
  128.             app_tx_header_cnt   <= app_tx_header_cnt + 8;
  129.             if((app_tx_header_cnt + 8) >= IMG_HEADER_LEN )  
  130.                  UDP_MS <= S_IMG_DATA;
  131.             else UDP_MS <= S_IMG_HEADER;
  132.          end
  133.          
  134.          S_IMG_DATA:begin
  135.             app_tx_data_valid <= 1'b1;
  136.             app_tx_data_cnt   <= app_tx_data_cnt + 8;
  137.             if(R0_INDEX[1:0] == 2'd2)
  138.                 R0_INDEX[1:0] <= 2'd0;
  139.              else
  140.                 R0_INDEX[1:0] <= R0_INDEX[1:0]  + 1'b1;
  141.             if((app_tx_data_cnt + 8) >= IMG_FRAMSIZE) begin        
  142.                 app_tx_data_last <= 1'b1; UDP_MS <= S_IMG_END;
  143.             end     
  144.             else UDP_MS <= S_IMG_DATA;            
  145.          end
  146.          
  147.          S_IMG_END:begin
  148.             app_tx_data_valid <= 1'b0;
  149.             app_tx_data_last  <= 1'b0;      
  150.             if(IMG_FRAMSEQ >= IMG_FRAMTOTAL)begin
  151.                   UDP_MS <= S_SYNC_1;
  152.             end
  153.             else begin
  154.                 UDP_MS  <= S_UDP_WAIT;
  155.             end
  156.           end
  157.           default: UDP_MS <= S_SYNC_1;
  158.         endcase
  159.     end
  160. end   
复制代码


4硬件连接
4.1 RGMII接口千兆以太网
8352d878e0a8419ca6978a8fe89094ef.jpg
4.2 SFP+接口千兆以太网
bf370bcf9fae446b95313242a4d80d23.jpg


4.3 SFP+接口万兆以太网
187c99ea78ad469d8035c9746409bcb4.jpg

5程序测试
                        
                        
                         d9c18ae17a864c0ba77ae3a63aed300e.jpg


                        
1
                        
                        
2
                        
                        
3
                        
                        
4
                        
                        
5
                        
                        
6
                        
                        
时钟
                        
                        
以太网速度
                        
                        
OFF
                        
                        
OFF
                        
                        
ON
                        
                        
OFF
                        
                        
OFF
                        
                        
OFF
                        
                        
125M
                        
                        
1Gbps
                        
                        
OFF
                        
                        
OFF
                        
                        
ON
                        
                        
ON
                        
                        
OFF
                        
                        
OFF
                        
                        
156.25M
                        
                        
10Gbps
                        

5.1千兆以太网上位机采集设置
时间间隔参设置300~400大概是10~15fps的帧率
e8ec849ad0424d558437787fb4dca28e.jpg
本地主机以太网IP地址设置
65aa6e4e05ff4866a0cd0f2583cce887.jpg
上位机主要需要正确设置IP地址以及端口号,目前”米联客”所有的UDP通信方案,开发板端口号为6002,本地主机端口号为6001,对于以太网UDP通信开发板的IP地址(摄像头IP地址)为192.168.137.2
8718dd0dd5da4b92a693114293006762.jpg
5.2万兆以太网上位机采集设置
万兆网需要SFP+接口具备10Gbps以上的通信速度才可以实现,所以低端的MA703 MA704 MZ7015的GTP接口最高只能做到千兆UDP通信。
  时间间隔参数设置1000以上,否则上位机会严重处理不过来图形的显示。
4b35e5a128e640b987ec5e6a59c9f98d.jpg
  本地主机以太网IP地址设置,因为在一台主机上测试,所以本地IP地址不能一样,设置为192.168.137.100网
d015b0f08402491a905c01bb53d18584.jpg
上位机主要需要正确设置IP地址以及端口号,目前“米联客”所有的UDP通信方案,开发板端口号为6002.本地主机端口号为60001,对于千兆以太网UDP通信开发板的IP地址(摄像头IP地址)为192.168.137.2。
4e8ce7db29b0461ba3926c1561db38b8.jpg



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

本版积分规则