【开源】国产安路FPGA实现四路视频分屏显示与全屏切换

前言

本文在前文的基础上介绍如何实现四分屏与全屏切换。切换效果点击观看:视频切换显示

四分屏显示实现

硬件平台:anPH1A 开发板链接

软件版本:TD6.0

本工程所有的代码均已上传至Github,开源工程链接,可以把bit流文件直接烧录至anPH1A开发板进行验证。还请大家给点点star喽~ 如果有不理解的地方,欢迎评论区讨论~ 有写错的地方也请大家评论区批评指正~

一、设计概述

除去DDR3控制器、FIFO等常用IP,本设计所用到的主要的IP模块如下。

IP功能来源
uidbuf基于FDMA信号时序的缓存控制器
适合用于基于RGB时序的视频数据或者数据流传输
米联客
uiFDMA基于AXI总线的自定义内存控制器
简化AXI总线的控制,完成数据的搬运
米联客
uidbuf_r_baseaddr_switch在uidbuf的基础上进行更改
用于全屏切换时选择不同通路的视频源进行读取
个人开发
uidbufw_interconnect基于FDMA信号时序的多路数据写入DDR3仲裁模块
不必使用AXI interconnectIP核,减少逻辑资源的使用
个人开发
uidbufr_interconnect基于FDMA信号时序的多路数据读出DDR3仲裁模块
不必使用AXI interconnectIP核,减少逻辑资源的使用
个人开发

二、系统实现方案

2.1 理论分析

四分屏显示与全屏显示是互斥的一个状态,为了减少DDR3的吞吐量,在进行四分屏显示时,对全屏显示模块进行复位。同理,在进行全屏显示时,对四分屏显示模块进行复位。此外,全屏显示时,在同一时刻也需要对一路视频源进行存储和显示,其他的三路视频源也不必写入DDR3,减少吞吐量。

全屏显示模块的设计思路为:为每一路视频源划分指定大小的存储空间,当需要对第一路视频进行全屏显示时,就去读取第一路视频存储的位置,当需要对第二路视频进行全屏显示时,就去读取第二路视频存储的位置。

2.2 全屏显示系统框图

在这里插入图片描述
在读取的时候通过uidbuf_r_baseaddr_switch控制读取的地址即可

2.3 uidbuf_r_baseaddr_switch模块

控制读取的基地址改变,在每次读取完一帧数据后,判断是否需要更改读取的基地址,I_state_ddr_clk信号由外部传入。

reg [AXI_ADDR_WIDTH-1'b1: 0]R_BASEADDR;

localparam VIDEO_0_BASEADDR = 1843200;
localparam VIDEO_1_BASEADDR = 3686400;
localparam VIDEO_2_BASEADDR = 5529600;
localparam VIDEO_3_BASEADDR = 7372800;

//根据I_state_ddr_clk来进行地址的切换

//何时切换?在一帧视频读完后进行切换,保证每一帧画面的完整性

localparam VIDEO_0  = 3'd0;
localparam VIDEO_1  = 3'd1;
localparam VIDEO_2  = 3'd2;
localparam VIDEO_3  = 3'd3;

always @(posedge I_ui_clk or negedge I_ui_rstn) begin
    if (~I_ui_rstn) begin
        R_BASEADDR <= VIDEO_0_BASEADDR;
    end else if (R_FS) begin
        case (I_state_ddr_clk)
            VIDEO_0:begin
                R_BASEADDR <= VIDEO_0_BASEADDR;
            end 
            VIDEO_1:begin
                R_BASEADDR <= VIDEO_1_BASEADDR;
            end 
            VIDEO_2:begin
                R_BASEADDR <= VIDEO_2_BASEADDR;
            end 
            VIDEO_3:begin
                R_BASEADDR <= VIDEO_3_BASEADDR;
            end 
            default: begin
                R_BASEADDR <= VIDEO_0_BASEADDR;
            end
        endcase
    end
end

2.4 跨时钟域处理

此工程是通过接收串口数据,进行命令解析,发送控制信号进行分屏全屏切换。下面为输入至全屏显示模块的控制信号,发送域的时钟为25Mhz,接收域的时钟为DDR IP用户侧时钟(533/4 Mhz)。

从慢时钟域到快时钟域,单bit信号直接打两拍处理即可。多bit信号,在此模块的处理方式为采用独热码+状态机的思路进行处理。

    //uart ctrl signal
    input  wire    [3:0]    I_screen_switch,   //该信号用于选择哪个屏幕进行显示,跨时钟域信号(多bit,慢时钟到快时钟)采用独热码与状态机处理
	input  wire             I_full_rstn,       //该模块的复位信号,在分屏显示时,对该模块进行复位(单bit,慢时钟到快时钟)采用打两拍进行处理

多bit信号在进行跨时钟域处理的时候可能会造成同步时序,如下图所示。正常情况下输入序列 00->11,但是因为延迟问题,输入产生了 10 的组合,从而导致接收端解码器输出了一个错误值。
在这里插入图片描述
解决方法:独热码+接收端状态机的解决思路进行处理。如下图所示
在这里插入图片描述
输入端bdec[1:0]共有四种组合状态,在进行跨时钟域传输前,即发送的时候在bclk时钟域用4位独热码即可对应四种不同的状态,接收端打两拍之后,使用状态机进行处理,假设从状态1110跳转至状态1011,在aclk时钟域进行接收的时候,可能会接收到1111、1010、1011三种状态。其中1010和1011均可以使状态机跳转至正确的状态,1111保持在当前状态。通过接收端的状态机处理,使的电路处于稳定可控的状态。(这里是使用独热码的反码进行处理的)

参考链接:跨时钟域/CDC设计方法总结

2.5 跨时钟域处理代码

(这一块如有错误,还请指正)


//---------跨时钟域信号处理-----------

//发送端的信号I_screen_switch对应的功能解释
//I_screen_switch=4'b0001,video 0全屏
//I_screen_switch=4'b0010,video 1全屏
//I_screen_switch=4'b0100,video 2全屏
//I_screen_switch=4'b1000,video 3全屏

//先对输入至接收端信号在接收时钟为ddr_ip_clk情况下打两拍处理,此情况可能会导致同步失序
reg [3:0]  screen_switch_dly1_ddr_clk;
reg [3:0]  screen_switch_dly2_ddr_clk;

always @(posedge O_axi_clk or negedge pll_locked) begin
	if (~pll_locked) begin
		screen_switch_dly1_ddr_clk <= 'd0;
		screen_switch_dly2_ddr_clk <= 'd0;
	end else begin
		screen_switch_dly1_ddr_clk <= I_screen_switch;
		screen_switch_dly2_ddr_clk <= screen_switch_dly1_ddr_clk;
	end
end

//接收端状态
//这个状态的状态转移取决于独热码里“热”的那一位,即 1 的位置。
localparam VIDEO_0  = 3'd0;
localparam VIDEO_1  = 3'd1;
localparam VIDEO_2  = 3'd2;
localparam VIDEO_3  = 3'd3;

//接收端状态机,接收时钟域为ddr_clk
reg [2:0] state_ddr_clk;

always @(posedge O_axi_clk or negedge pll_locked) begin
	if (~pll_locked) begin
		state_ddr_clk <= VIDEO_0; //默认VIDEO_0全屏
	end else begin
		case (state_ddr_clk)
			VIDEO_0:begin
				if (screen_switch_dly2_ddr_clk[3] == 1'b1) begin
					state_ddr_clk <= VIDEO_3;
				end else if (screen_switch_dly2_ddr_clk[2] == 1'b1) begin
					state_ddr_clk <= VIDEO_2;
				end else if (screen_switch_dly2_ddr_clk[1] == 1'b1) begin
					state_ddr_clk <= VIDEO_1;
				end else begin
					state_ddr_clk <= VIDEO_0;
				end
			end 
			VIDEO_1:begin
				if (screen_switch_dly2_ddr_clk[3] == 1'b1) begin
					state_ddr_clk <= VIDEO_3;
				end else if (screen_switch_dly2_ddr_clk[2] == 1'b1) begin
					state_ddr_clk <= VIDEO_2;
				end else if (screen_switch_dly2_ddr_clk[0] == 1'b1) begin
					state_ddr_clk <= VIDEO_0;
				end else begin
					state_ddr_clk <= VIDEO_1;
				end
			end
			VIDEO_2:begin
				if (screen_switch_dly2_ddr_clk[3] == 1'b1) begin
					state_ddr_clk <= VIDEO_3;
				end else if (screen_switch_dly2_ddr_clk[1] == 1'b1) begin
					state_ddr_clk <= VIDEO_1;
				end else if (screen_switch_dly2_ddr_clk[0] == 1'b1) begin
					state_ddr_clk <= VIDEO_0;
				end else begin
					state_ddr_clk <= VIDEO_2;
				end
			end
			VIDEO_3:begin
				if (screen_switch_dly2_ddr_clk[2] == 1'b1) begin
					state_ddr_clk <= VIDEO_2;
				end else if (screen_switch_dly2_ddr_clk[1] == 1'b1) begin
					state_ddr_clk <= VIDEO_1;
				end else if (screen_switch_dly2_ddr_clk[0] == 1'b1) begin
					state_ddr_clk <= VIDEO_0;
				end else begin
					state_ddr_clk <= VIDEO_3;
				end
			end
			default: begin
				state_ddr_clk <= VIDEO_0;
			end
		endcase
	end
end

三、移植注意事项

1、 在本工程中,为了减少ERAM资源的使用,我们将图像像素点在DDR3中的存储和读取格式设置为RGB565格式,其中每个像素点占用16bit,并将DDR3的数据位宽设置为16bit。由于DDR3的突发传输长度固定为8,每次突发传输8次16bit数据,即总共传输128bit。因此,在进行DDR3存取时,FIFO的读写位宽可以设置为16bit和128bit。与此不同,若将图像像素点的存储格式设置为RGB888格式,每个像素点将占用24bit,并将DDR3的数据位宽设置为32bit。在这种情况下,进行存取时,FIFO的读写位宽将为32bit和256bit,这样会导致ERAM资源消耗的加倍。

2、本工程四路视频源输入的视频分辨率为1280×720

3、使用串口命令发送16进制 00 视频不移动,发送16进制01 视频开始移动。10 分屏显示 11 Video0全屏 12 video1全屏 13 video2全屏 14 video3全屏,波特率为115200。

四、上板验证

四路视频数据是由FPGA内部产生的测试数据,分屏显示与全屏切换效果图如下。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值