本帖最后由 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中的摄像头数据。
3FPGA程序设计
3.1blockdesign设计这张图的设计和DDR部分的摄像头采集部分一样,主要是配合“米联客”自定义IP FDMA实现数据缓存到DDR,和从DDR读出。在DDR部分的例子数据读出后就在显示器上显示了,而这里我们需要通过以太网发送给电脑。关于FDMA IP的应用可以参考DDR部分例子。
3.2图像数据格式以下代码是上位机的帧头部分定义,用上位机定义图像的格式很容易理解。由于UDP一包数据最大是1472字节,所以这里一副1280*720(用户可以修改分辨率)数据格式为RGB888的图像,UDP传输需要分720*3次传输完成,每次传输32字节的帧头和1280字节的图像数据。 - #define FLAG_HEAD 0xAA0055FF
- struct stHeader
- {
- quint32 flag; //固定为 FLAG_HEAD 对数据合法性判断,防止其他数据干扰
- quint32 width; //图片宽度 例如 1280
- quint32 height; //图片高度 例如 720
- quint32 total; //一张图片总大小 例如 1280*720*3
- quint32 offset; //当前数据偏移量 例如,第一帧数据为0, 第n帧数据为 (n-1)*framesize
- quint32 picseq; //图片序号,第几张图片
- quint32 frameseq; //一张图片发送的帧序号,当前图片的第n帧 ,从1~ 720*3
- quint32 framesize; //当前帧图片数据大小 例如每一次都发有效图片数据大小为1280
- quint8 data[0]; //有效图片数据
- };
复制代码
有了以上代码的参考设计FPGA的图像帧数据就简单了一些。以下给出master_ch中关键的图像帧定义,以及以FPGA的方式发送帧数据的代码。通过FDMA获取的数据是128bit位宽(4个32bit XRGB格式的数据)而我们上位机需要的是RGB888所以是需要去掉无效的一个字节数据去掉,并且以RGB888 24bit数据紧密排列。详细的代码阅读配套的demo中代码。 - localparam IMG_HEADER = 32'hAA0055FF;
- localparam IMG_WIDTH = 32'd1280;
- localparam IMG_HEIGHT = 32'd720;
- localparam IMG_TOTAL = IMG_WIDTH*IMG_HEIGHT*3;
- localparam IMG_FRAMSIZE = 32'd1280;
- localparam IMG_FRAMTOTAL = IMG_HEIGHT*3;
- localparam IMG_HEADER_LEN = 6'd32;//4个64bit
- reg [31 :0] IMG_FRAMSEQ;
- reg [31 :0] IMG_PICSEQ;
- wire [31 :0] IMG_OFFSET = (IMG_FRAMSEQ-1'b1) * IMG_FRAMSIZE;
- wire [255:0] STHEADER_X86 = {IMG_FRAMSIZE,IMG_FRAMSEQ,IMG_PICSEQ,IMG_OFFSET,IMG_TOTAL,IMG_HEIGHT,IMG_WIDTH,IMG_HEADER};
-
- wire [0 :0] ui_rstn;
- wire ui_clk;
- wire cfg_done;
- wire R0_rclk_i = clk_15_625;
- wire [127:0] R0_data_o;
- reg [127:0] R0_data_r;
- wire R0_rdy_o;
- wire R0_rden_i;
- reg R0_FS_i;
- reg [1 :0] R0_INDEX;
- always@(posedge clk_15_625 or posedge core_reset)begin
- if(core_reset) begin
- app_tx_data <= 64'd0;
- R0_data_r <= 128'd0;
- end
- else begin
- if(UDP_MS == S_UDP_ACK || UDP_MS == S_IMG_HEADER)begin
- app_tx_data <= STHEADER_X86[app_tx_header_cnt*8 +: 64];
- end
- else if(UDP_MS == S_IMG_DATA)begin
- R0_data_r <= R0_data_o;
- case(R0_INDEX)
- 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
- 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
- 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
- default:begin app_tx_data <= app_tx_data; end
- endcase
- end
- else begin
- app_tx_data <= app_tx_data;
- end
- end
- end
- eg [11:0] vstout_cnt;
- wire [15:0] PACKET_INTERVAL;
- reg [15:0] delay_cnt;
- always@(posedge clk_15_625 or posedge core_reset)
- begin
- if(core_reset) begin
- delay_cnt <= 16'd0;
- end
- else begin
- if(delay_cnt < PACKET_INTERVAL)
- delay_cnt <= delay_cnt + 1'b1;
- else
- delay_cnt <= 16'd0;
- end
- end
- wire pkg_tx_en = (delay_cnt == PACKET_INTERVAL);
- vio_0 vio_debug(.clk(clk_15_625),.probe_out0(PACKET_INTERVAL));
- assign R0_rden_i = (R0_INDEX == 2'd0 || R0_INDEX == 2'd2)&& (UDP_MS == S_IMG_DATA );
- always@(posedge clk_15_625 or posedge core_reset)
- begin
- if(core_reset) begin
- app_tx_data_valid <= 1'b0;
- app_tx_header_cnt <= 8'd0;
- app_tx_data_cnt <= 12'd0;
- app_tx_data_last <= 1'b0;
- R0_FS_i <= 1'b0;
- IMG_PICSEQ <= 32'd0;
- IMG_FRAMSEQ <= 32'd0;
- vstout_cnt <= 12'd0;
- UDP_MS <= S_SYNC_1;
- end
- else begin
- case(UDP_MS)
- S_SYNC_1:begin
- vstout_cnt <= 12'd0;
- R0_INDEX <= 2'd0;
- R0_FS_i <= 1'b0;
- IMG_FRAMSEQ <= 32'd0;
- IMG_PICSEQ <= IMG_PICSEQ + 1'b1;
- UDP_MS <= S_SYNC_2;
- end
- S_SYNC_2:begin
- UDP_MS <= S_SYNC_3;
- end
- S_SYNC_3:begin
- R0_FS_i <= 1'b1;
- vstout_cnt <= vstout_cnt + 1'b1;
- if(R0_rdy_o)begin
- UDP_MS <= S_UDP_WAIT;
- end
- else if(vstout_cnt[11])
- UDP_MS <= S_SYNC_1;
- end
- S_UDP_WAIT:begin
- app_tx_header_cnt <= 8'd0;
- app_tx_data_cnt <= 12'd0;
- if(udp_tx_ready&&pkg_tx_en) begin
- app_tx_data_req <= 1'b1;UDP_MS <= S_UDP_ACK;
- end
- else begin
- app_tx_data_req <= 1'b0;UDP_MS <= S_UDP_WAIT;
- end
- end
-
- S_UDP_ACK:begin
- if(app_tx_ack) begin
- app_tx_data_req <= 1'b0;
- app_tx_data_valid <= 1'b1;
- app_tx_header_cnt <= app_tx_header_cnt + 8;
- IMG_FRAMSEQ <= IMG_FRAMSEQ + 1'b1;
- UDP_MS <= S_IMG_HEADER;
- end
- else if(dst_ip_unreachable) begin
- app_tx_data_req <= 1'b0;app_tx_data_valid <= 1'b0;UDP_MS <= S_SYNC_1;
- end
- else begin
- app_tx_data_req <= 1'b1;app_tx_data_valid <= 1'b0;UDP_MS <= S_UDP_ACK;
- end
- end
-
- S_IMG_HEADER:begin
- app_tx_data_valid <= 1'b1;
- app_tx_header_cnt <= app_tx_header_cnt + 8;
- if((app_tx_header_cnt + 8) >= IMG_HEADER_LEN )
- UDP_MS <= S_IMG_DATA;
- else UDP_MS <= S_IMG_HEADER;
- end
-
- S_IMG_DATA:begin
- app_tx_data_valid <= 1'b1;
- app_tx_data_cnt <= app_tx_data_cnt + 8;
- if(R0_INDEX[1:0] == 2'd2)
- R0_INDEX[1:0] <= 2'd0;
- else
- R0_INDEX[1:0] <= R0_INDEX[1:0] + 1'b1;
- if((app_tx_data_cnt + 8) >= IMG_FRAMSIZE) begin
- app_tx_data_last <= 1'b1; UDP_MS <= S_IMG_END;
- end
- else UDP_MS <= S_IMG_DATA;
- end
-
- S_IMG_END:begin
- app_tx_data_valid <= 1'b0;
- app_tx_data_last <= 1'b0;
- if(IMG_FRAMSEQ >= IMG_FRAMTOTAL)begin
- UDP_MS <= S_SYNC_1;
- end
- else begin
- UDP_MS <= S_UDP_WAIT;
- end
- end
- default: UDP_MS <= S_SYNC_1;
- endcase
- end
- end
复制代码
4硬件连接
4.1 RGMII接口千兆以太网
4.2 SFP+接口千兆以太网
4.3 SFP+接口万兆以太网
5程序测试
| 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的帧率
本地主机以太网IP地址设置
上位机主要需要正确设置IP地址以及端口号,目前”米联客”所有的UDP通信方案,开发板端口号为6002,本地主机端口号为6001,对于以太网UDP通信开发板的IP地址(摄像头IP地址)为192.168.137.2
5.2万兆以太网上位机采集设置万兆网需要SFP+接口具备10Gbps以上的通信速度才可以实现,所以低端的MA703 MA704 MZ7015的GTP接口最高只能做到千兆UDP通信。 时间间隔参数设置1000以上,否则上位机会严重处理不过来图形的显示。
本地主机以太网IP地址设置,因为在一台主机上测试,所以本地IP地址不能一样,设置为192.168.137.100网
上位机主要需要正确设置IP地址以及端口号,目前“米联客”所有的UDP通信方案,开发板端口号为6002.本地主机端口号为60001,对于千兆以太网UDP通信开发板的IP地址(摄像头IP地址)为192.168.137.2。
|