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

1-4-16 基于UDP的网络摄像头方案

文档创建者:uisrc
浏览次数:500
最后更新:2024-04-10
文档课程分类
AMD: FPGA部分(2024样板资料) » 1_START(适配所有型号) » 4-硬件功能案例
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA
登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!
1概述
在前面的课程中,我们实现了基于PHY芯片RGMII接口实现的千兆以太网UDP通信。都详细展示了UDP通信的实现方式,而本文是基于之前的demo增加摄像头采集部分,以及通过DDR实现图像数据的缓存。采集到的图像通过以上任何一种方式把图像数据发动到电脑上,并且通过电脑的上位机显示图像。
2系统框图
本系统采用摄像头输入采用OV5640,I2C的寄存器配置采用Milianke uiSensorRGB565 IP配置。通过Milianke uifdma_dbuf将数据写入DDR。上位机使用太网通过AXI Interconnect IP读取存放在DDR中的摄像头数据。

2504661-20231227195534229-1744086464.jpg
3FPGA程序设计3.1blockdesign设计
这张图的设计和DDR部分的摄像头采集部分一样,主要是配合"米联客"自定义IP FDMA实现数据缓存到DDR,和从DDR读出。在DDR部分的例子数据读出后就在显示器上显示了,而这里我们需要通过以太网发送给电脑。关于FDMA IP的应用可以参考DDR部分例子。
2504661-20231227195534818-1875123339.jpg
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};

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(RO_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


reg [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 = (RO_INDEX == 2'd0 || RO_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;
RO_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(RO_INDEX[1:0] == 2'd2)
RO_INDEX[1:0] <= 2'd0;
else
RO_INDEX[1:0] <= RO_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接口千兆以太网
2504661-20231227195535319-1107625681.jpg
5程序测试
老版本MA703-100T开发板需要通过设置模式开关输出125M。
2504661-20231227195545662-1172908257.jpg


2504661-20231227195546039-748283873.jpg
1
2
3
4
5
6
时钟
以太网速度
OFF
OFF
ON
OFF
OFF
OFF
125M
1Gbps



新版本F9-100T开发板直接焊接了一个125M固定时钟
2504661-20231227195546360-1651030761.jpg
5.1千兆以太网上位机采集设置
时间间隔参设置300~400大概是10~15fps的帧率
2504661-20231227195546672-194201132.jpg


本地主机以太网IP地址设置

2504661-20231227195547064-185676806.jpg
上位机主要需要正确设置IP地址以及端口号,目前"米联客"所有的UDP通信方案,开发板端口号为6002,本地主机端口号为6001,对于以太网UDP通信开发板的IP地址(摄像头IP地址)为192.168.137.2
2504661-20231227195547590-2053397695.jpg

发表评论已发布 2

gjtxfjpd

发表于 2024-3-16 15:21:54 | 显示全部楼层

为什么文档说用fdma_dbuf但是bd图里只用了fdma呀

uisrc

发表于 2024-4-10 22:40:17 | 显示全部楼层

gjtxfjpd 发表于 2024-3-16 07:21
为什么文档说用fdma_dbuf但是bd图里只用了fdma呀

bd 里面没有fdma dbuf 但是在,顶层文件里面调用了源文件
越努力越幸运!加油!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则