1、不同分辨率视频切换输出原理
不同分辨率的视频输出对应不同的时序和时钟,一般情况下是不存在同时或分时输出的,但现实项目中如果遇到这样的情况怎么办呢?
很好办,找我就行了。。。
不同分辨率的视频肯定有大有小,但输出分辨率却只有一个,很显然,要选择大的分辨率时序作为输出时序,大视频原样输出,小视频在大分辨率下降采样输出;
以本设计为例,输入分辨率有720P和1080P,那么输出时序当然就是1080P,720P视频在1080P时序下降采样输出;
2、设计思想和架构详解
设计架构如下:
输入1:ov5640摄像头1280x720@60Hz;
输入2:hdmi输入1920x1080@60Hz;
输出:hdmi输出1920x1080@60Hz;
具体哪一路作为输出视频,由串口协议帧控制;
具体协议如下:
串口协议帧有效数据0x00 0x00 0xaa 0xbb 输入2作为输出;
串口协议帧有效数据0x00 0x00 0xcc 0xdd 输入1作为输出;
ov5640摄像头输入:
ov5640摄像头输出rgb565格式视频,需要iic配置和数据采集,详细配置和采集源码请将文章看到最后;
HDMI输入和输出:
HDMI输入采用silicon9011解码,HDMI输出采用silicon9134编码,关于这一块的配置和使用,请参考我之前写的文章点击查看:silicon9011和silicon9134编解码
串口协议帧解析:
主要控制不同分辨率参数写入FDMA控制器,进而控制DDR读写,这个串口协议帧解析方案高度贴近真实项目,也是我常用的套路,关于串口协议帧解析这一块,请参考我之前写的文章点击查看:串口协议帧解析方案
FDMA数据缓存方案:
经典的图像缓存DDR3的方案,关于FDMA数据缓存方案点击查看:FDMA数据缓存方案这一块,请参考我之前写的文章
3、vivado工程详解
vivado版本:2019.1;
如果是高版本打开,升级IP即可;
如果是低版本打开,打开工程后需另存为,然后即可使用;
工程BD如下:
工程代码架构如下:
顶层源码如下:
`timescale 1ns / 1ps
module top(
//ddr3
output [14:0]DDR3_0_addr,
output [2:0]DDR3_0_ba ,
output DDR3_0_cas_n ,
output [0:0]DDR3_0_ck_n ,
output [0:0]DDR3_0_ck_p ,
output [0:0]DDR3_0_cke ,
output [0:0]DDR3_0_cs_n ,
output [3:0]DDR3_0_dm ,
inout [31:0]DDR3_0_dq ,
inout [3:0]DDR3_0_dqs_n ,
inout [3:0]DDR3_0_dqs_p ,
output [0:0]DDR3_0_odt ,
output DDR3_0_ras_n ,
output DDR3_0_reset_n ,
output DDR3_0_we_n ,
input CLK_IN1_D_0_clk_n,
input CLK_IN1_D_0_clk_p,
output ddr3_ok ,
inout cmos_scl, //cmos i2c clock
inout cmos_sda, //cmos i2c data
input cmos_vsync, //cmos vsync
input cmos_href, //cmos hsync refrence,data valid
input cmos_pclk, //cmos pxiel clock
output cmos_xclk, //cmos externl clock
input [7:0]cmos_db, //cmos data
output cmos_rst_n, //cmos reset
output cmos_pwdn, //cmos power down
output hdmi_in_nreset , //9011/9013 reset
input vin_clk , //clock for 9111/9013
input vin_hs , //horizontal synchronization for 9011/9013
input vin_vs , //vertical synchronization for 9011/9013
input vin_de , //data valid for 9011/9013
input[23:0] vin_data , //data for 9011/9013
inout hdmi_scl , //HDMI I2C clock
inout hdmi_sda , //HDMI I2C data
//hdmi_out
output vout_hs , //horizontal synchronization for 9134
output vout_vs , //vertical synchronization for 9134
output vout_de , //data valid for 9134
output vout_clk , //clock for 9134
output[23:0] vout_data , //data for 9134
output hdmi_nreset ,
input i_uart_rx ,
output o_uart_tx
);
wire clk_25m ;
wire clk_200m ;
wire clk_hdmi ;
wire pll_resetn;
wire [0:0] resetn;
wire ud_r_0_ud_rclk;
wire [31:0] ud_r_0_ud_rdata;
wire ud_r_0_ud_rde;
wire ud_r_0_ud_rvs;
reg ud_w_0_ud_wclk ;
reg [23:0] ud_w_0_ud_wdata;
reg ud_w_0_ud_wde ;
reg ud_w_0_ud_wvs ;
reg [10:0] dis_h;
reg [10:0] dis_v;
wire ui_clk_100m;
wire [9:0] lut_index;
wire [31:0] lut_data;
wire [9:0] lut_index_hdmi;
wire [31:0] lut_data_hdmi ;
wire [23:0] ov5640_rgb;
wire ov5640_de ;
wire ov5640_vs ;
wire o_data_req;
wire [23:0] i_rgb;
wire o_hs ;
wire o_vs ;
wire o_de ;
wire [23:0] o_rgb;
wire hdmi_clk_rstn;
wire o_rx_done;
wire [31:0]o_rx_data;
reg [31:0] _rx_data;
assign hdmi_nreset =pll_resetn;
assign hdmi_in_nreset=pll_resetn;
assign ud_r_0_ud_rclk=clk_hdmi;
assign ud_r_0_ud_rvs=o_vs;
assign ud_r_0_ud_rde=o_data_req;
assign i_rgb=ud_r_0_ud_rdata[23:0];
assign vout_clk=clk_hdmi;
assign vout_hs=o_hs;
assign vout_vs=o_vs;
assign vout_de=o_de;
assign vout_data=o_rgb;
assign cmos_rst_n = 1'b1;
assign cmos_pwdn = 1'b0;
i2c_config i2c_config_ov5640(
.rst (~pll_resetn ),
.clk (clk_200m ),
.clk_div_cnt (16'd500 ),
.i2c_addr_2byte (1'b1 ),
.lut_index (lut_index ),
.lut_dev_addr (lut_data[31:24]),
.lut_reg_addr (lut_data[23:8] ),
.lut_reg_data (lut_data[7:0] ),
.error ( ),
.done ( ),
.i2c_scl (cmos_scl ),
.i2c_sda (cmos_sda )
);
ov5640_reg_cfg #(
.DISPAY_H(1280),
.DISPAY_V(720 )
)
u_ov5640_reg_cfg(
.lut_index(lut_index), //Look-up table address
.lut_data (lut_data ) //Device address (8bit I2C address), register address, register data
);
i2c_config i2c_config_hdmi(
.rst (~pll_resetn ),
.clk (clk_200m ),
.clk_div_cnt (16'd500 ),
.i2c_addr_2byte (1'b0 ),
.lut_index (lut_index_hdmi ),
.lut_dev_addr (lut_data_hdmi[31:24]),
.lut_reg_addr (lut_data_hdmi[23:8] ),
.lut_reg_data (lut_data_hdmi[7:0] ),
.error ( ),
.done ( ),
.i2c_scl (hdmi_scl ),
.i2c_sda (hdmi_sda )
);
lut_hdmi u_lut_hdmi(
.lut_index(lut_index_hdmi), //Look-up table address
.lut_data (lut_data_hdmi) //Device address (8bit I2C address), register address, register data
);
uiSensorRGB565 u_uiSensorRGB565(
.cmos_clk_i (clk_25m),//cmos senseor clock.
.rst_n_i (resetn ),//system reset.active low.
.cmos_pclk_i (cmos_pclk),//input pixel clock.
.cmos_href_i (cmos_href),//input pixel hs signal.
.cmos_vsync_i(cmos_vsync),//input pixel vs signal.
.cmos_data_i (cmos_db),//data.
.cmos_xclk_o (cmos_xclk),//output clock to cmos sensor.
.rgb_o (ov5640_rgb),
.de_o (ov5640_de ),
.vs_o (ov5640_vs ),
.hs_o ()
);
uart_rx_analysis_top #(
.CLK_FREQ(200_000_000), //系统时钟频率
.UART_BPS(115200 ) //串口波特率
)
uart_rx_analysis(
.clk (clk_200m),
.rst_n (resetn ),
.i_uart_rx (i_uart_rx),
.o_uart_tx (o_uart_tx),
.o_rx_done (o_rx_done),
.o_rx_data (o_rx_data)
);
ila_0 u_ila_0 (
.clk(clk_200m), // input wire clk
.probe0(o_rx_done), // input wire [0:0] probe0
.probe1(o_rx_data) // input wire [31:0] probe1
);
always @(posedge clk_200m) begin
if(~resetn) _rx_data<=32'h00000000;
else if(o_rx_done) _rx_data<=o_rx_data;
end
always @(*) begin
if(_rx_data==32'h0000aabb) begin
ud_w_0_ud_wclk =vin_clk ;
ud_w_0_ud_wdata=vin_data;
ud_w_0_ud_wde =vin_de ;
ud_w_0_ud_wvs =vin_vs ;
dis_h =11'd1920;
dis_v =11'd1080;
end
else if(_rx_data==32'h0000ccdd) begin
ud_w_0_ud_wclk =cmos_pclk ;
ud_w_0_ud_wdata={ov5640_rgb[7:0],ov5640_rgb[15:8],ov5640_rgb[23:16]};
ud_w_0_ud_wde =ov5640_de ;
ud_w_0_ud_wvs =ov5640_vs ;
dis_h =11'd1280;
dis_v =11'd720 ;
end
else begin
ud_w_0_ud_wclk =vin_clk ;
ud_w_0_ud_wdata=vin_data;
ud_w_0_ud_wde =vin_de ;
ud_w_0_ud_wvs =vin_vs ;
dis_h =11'd1920;
dis_v =11'd1080;
end
end
design_1_wrapper u_design_1_wrapper (
.CLK_IN1_D_0_clk_n(CLK_IN1_D_0_clk_n),
.CLK_IN1_D_0_clk_p(CLK_IN1_D_0_clk_p),
.DDR3_0_addr (DDR3_0_addr ),
.DDR3_0_ba (DDR3_0_ba ),
.DDR3_0_cas_n (DDR3_0_cas_n ),
.DDR3_0_ck_n (DDR3_0_ck_n ),
.DDR3_0_ck_p (DDR3_0_ck_p ),
.DDR3_0_cke (DDR3_0_cke ),
.DDR3_0_cs_n (DDR3_0_cs_n ),
.DDR3_0_dm (DDR3_0_dm ),
.DDR3_0_dq (DDR3_0_dq ),
.DDR3_0_dqs_n (DDR3_0_dqs_n ),
.DDR3_0_dqs_p (DDR3_0_dqs_p ),
.DDR3_0_odt (DDR3_0_odt ),
.DDR3_0_ras_n (DDR3_0_ras_n ),
.DDR3_0_reset_n (DDR3_0_reset_n ),
.DDR3_0_we_n (DDR3_0_we_n ),
.clk_200m (clk_200m ),
.clk_hdmi (clk_hdmi ),
.ddr3_ok (ddr3_ok ),
.pll_resetn (pll_resetn ),
.resetn (resetn ),
.ud_r_0_ud_rclk (ud_r_0_ud_rclk ),
.ud_r_0_ud_rdata (ud_r_0_ud_rdata ),
.ud_r_0_ud_rde (ud_r_0_ud_rde ),
.ud_r_0_ud_rempty (ud_r_0_ud_rempty ),
.ud_r_0_ud_rvs (ud_r_0_ud_rvs ),
.ud_w_0_ud_wclk (ud_w_0_ud_wclk ),
.ud_w_0_ud_wdata (ud_w_0_ud_wdata ),
.ud_w_0_ud_wde (ud_w_0_ud_wde ),
.ud_w_0_ud_wfull (ud_w_0_ud_wfull ),
.ud_w_0_ud_wvs (ud_w_0_ud_wvs ),
.ui_clk_100m (ui_clk_100m ),
.clk_25m (clk_25m ),
.R_XSIZE_0 (dis_h ),
.R_YSIZE_0 (dis_v ),
.W_XSIZE_0 (dis_h ),
.W_YSIZE_0 (dis_v )
);
video_timing_control vga(
.i_clk (clk_hdmi ),
.i_rst_n (pll_resetn ),
.i_start_x (0),
.i_start_y (0),
.i_disp_h (dis_h),
.i_disp_v (dis_v),
.i_rgb (i_rgb ),
.o_hs (o_hs ),
.o_vs (o_vs ),
.o_de (o_de ),
.o_rgb (o_rgb ),
.o_data_req(o_data_req )
);
endmodule
资源消耗和功耗如下:使用的是Xilinx Artix7-35T;
4、上板调试验证并演示
开发板:Xilinx Artix7-35T开发板; 开发环境:vivado2019.1;
输入1:ov5640摄像头1280x720@60Hz;
输入2:hdmi输入1920x1080@60Hz;
输出:hdmi输出1920x1080@60Hz;
输出演示视频如下:
FPGA实现不同分辨率视频切换输出,串口协议帧控制,提供工程
5、福利:工程代码的获取
福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料获取方式:私,或者文章末尾的V名片。
网盘资料如下: