AX7A200教程(8): HDMI输入和输出显示1080p视频

文章目录

本章节主要将hdmi输入的1080p视频通过ddr3缓存,然后通过hdmi输出口输出到显示屏上显示

一, 突发读写命令

设置读写突发长度为64

//parameter define
 parameter  WRITE_LENGTH = 64;
 parameter  READ_LENGTH = 64;
 parameter  IDLE        = 3'd0;            //空闲状态
 parameter  WRITE       = 3'd1;            //写状态
 parameter  WRITE_DONE  = 3'd2;            //读到写过度等待
 parameter  READ        = 3'd3;            //读状态
 parameter  READ_DONE   = 3'd4;

1.突发写命令

当写fifo计数器rd_data_count计数大于62,执行一次写突发命令,拉高wr_len_en

    //突发写使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                wr_len_en    <=  1'd0;    
            else if(ddr_wr_end)
                wr_len_en    <=  1'd0;    
            else if(rd_len_en)
                wr_len_en    <=  1'd0;    
            else if(wr_len_done)
                wr_len_en    <=  1'd0;                             
            else if(rd_data_count >= 9'd62)
                wr_len_en    <=  1'd1;                        
    end 

2.突发读命令

当读fifo计数器wr_data_count小于等于64执行一次读突发命令,拉高rd_len_en

//突发读使能
    always@(posedge ui_clk or negedge i_rst_n)begin
            if(!i_rst_n)
                rd_len_en    <=  1'd0;
            else if(ddr_rd_end)
                rd_len_en    <=  1'd0;            
            else if(wr_len_en)
                rd_len_en    <=  1'd0;     
            else if(rd_len_done)
                rd_len_en    <=  1'd0;                 
            else if(ddr_rd_en && wr_data_count <= 9'd64)
                rd_len_en    <=  1'd1;                     
    end  

从上面的读突发命令可以看出来,读突发命令rd_len_en拉高,需要fifo计数器wr_data_count小于等于64和ddr_rd_en为高才行。因读突发设置的fifo读计数器wr_data_count小于等于64才触发,开发板上电后,ddr初始化后ddr里这时并没有数据,但如果直接设置读fifo小于等于64触发,那么这时进行的突发读将会读到的是ddr里面的随机值,因为此时突发读是先开始执行的,所以加入ddr_rd_en这个信号,当ddr_rd_en拉高才能使能突发读,ddr_rd_en信号需要输入的hdmi的场信号vs计数为3开始拉高ddr_rd_en这个信号,也就是ddr写入三个帧存才开始ddr突发读。

3.突发读使能信号

将hdmi输入的vs_in场信号打拍,每次上升沿计数,当计数到3时开始拉高start_en信号

reg vs_r; 
reg [2:0] count;  
always@(posedge clk or negedge rst)begin
        if(!rst)    
            vs_r    <=  1'b0;
        else
            vs_r    <=  vs_in;
end                

always@(posedge clk or negedge rst)begin
        if(!rst)    
            count    <=  3'd0;
        else if(count == 3'd3)
            count    <=  count;    
        else if(vs_in && !vs_r)
            count    <=  count + 1'b1;
end

assign  start_en = (count == 3'd3)? 1'b1:1'b0;

可以看到start_en信号直接连接ddr_rd_en

  ddr_test ddr_test_inst (
    // Memory interface ports
    .ddr3_addr                      (ddr3_addr),  // output [13:0]		ddr3_addr
    .ddr3_ba                        (ddr3_ba),  // output [2:0]		ddr3_ba
    .ddr3_cas_n                     (ddr3_cas_n),  // output			ddr3_cas_n
    .ddr3_ck_n                      (ddr3_ck_n),  // output [0:0]		ddr3_ck_n
    .ddr3_ck_p                      (ddr3_ck_p),  // output [0:0]		ddr3_ck_p
    .ddr3_cke                       (ddr3_cke),  // output [0:0]		ddr3_cke
    .ddr3_ras_n                     (ddr3_ras_n),  // output			ddr3_ras_n
    .ddr3_reset_n                   (ddr3_reset_n),  // output			ddr3_reset_n
    .ddr3_we_n                      (ddr3_we_n),  // output			ddr3_we_n
    .ddr3_dq                        (ddr3_dq),  // inout [31:0]		ddr3_dq
    .ddr3_dqs_n                     (ddr3_dqs_n),  // inout [3:0]		ddr3_dqs_n
    .ddr3_dqs_p                     (ddr3_dqs_p),  // inout [3:0]		ddr3_dqs_p
	.ddr3_cs_n                      (ddr3_cs_n),  // output [0:0]		ddr3_cs_n
    .ddr3_dm                        (ddr3_dm),  // output [3:0]		ddr3_dm
    .ddr3_odt                       (ddr3_odt),  // output [0:0]		ddr3_odt
    .init_calib_complete            (init_calib_complete),
    // System Clock Ports
    .sys_clk_i                      (clk_out2),
    .sys_rst                        (rst_n), // input sys_rst
   //fifo
    .wr_clk                         (vin_clk),
    .rd_clk                         (video_clk),
    .write_fifo_wr_en               (vin_de),
    .write_fifo_din                 ({8'd0,vin_data[23:0]}),
    .read_fifo_rd_en                (read_en),
    .read_fifo_dout                 (read_data),
    .read_fifo_empty                (read_fifo_empty),
    .read_valid                     (read_valid),
    .ddr_rd_en                      (start_en),
    .vin_vs                         (vin_vs),
    .vout_vs                        (read_req),
    .rd_reset                       (read_req_ack)    

    ); 

二,fifo读写复位信号 

1.写fifo复位信号

hdmi输入的场信号vin_vs检测到上升沿,拉高wr_reset信号用于写fifo复位

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)begin
            wr_load_r0   <=  1'd0;
            wr_load_r1   <=  1'd0;
            end
        else begin
            wr_load_r0   <=  vin_vs;
            wr_load_r1   <=  wr_load_r0;
            end
end 

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            wr_reset   <=  1'd0;
        else if(wr_load_r0 && !wr_load_r1)
            wr_reset   <=  1'd1;
        else if(app_addr_wr == 0 && !(wr_load_r0 && !wr_load_r1))    
            wr_reset   <=  1'd0;
end

2.读fifo复位信号

hdmi输出的场信号vout_vs检测到上升沿,拉高rd_reset信号用于读fifo复位

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)begin
            rd_load_r0   <=  1'd0;
            rd_load_r1   <=  1'd0;
            end
        else begin 
            rd_load_r0   <=  vout_vs;
            rd_load_r1   <=  rd_load_r0;
            end
end

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)
            rd_reset   <=  1'd0;
        else if(rd_load_r0 && !rd_load_r1)
            rd_reset   <=  1'd1;
        else if(app_addr_rd == 0 && !(rd_load_r0 && !rd_load_r1))    
            rd_reset   <=  1'd0;
end 

三,帧缓存切换

从下面的ddr手册可以看出,ddr一共有8个bank,也就是这个ddr一共可以缓存8页

而且地址是[14:0],注意这里在mig选ddr型号的时候一定要注意ddr的地址务必要选[14:0]或者以上,不然就只能操作一个帧缓存,我前面的工程都是[13:0],即使写了多帧,也只能操作一帧,目前这个工程是[14:0],按照ddr手册可以最大操作8个帧存 ,当然具体可以操作多少个帧存也和mig控制器有关,如果ddr最大帧存有8个,那我们操作8个帧存或者8个以下的帧存都是可以,当然mig也必须配置相应的帧存个数,如果我们的帧存为4个那么只能操作4个或者以下的,即使你的mig设置为8个帧存,那么能操作的最大的也只能是4个,帧存说白了就是ddr的bank数。

1.mig控制器帧设置 

 bank数量设置,ddr最大的bank数为8,我们这里设置为4表示最大能操作4个帧存,也就是0,1,2,3这四页

 2.ddr写帧缓存切换

将hdmi输入的场信号vin_vs的上升沿做为计数信号,每次检测到上升沿就直接加1,因wr_page位宽为[1:0],也就是两个位宽,所以ddr写帧存在0,1,2,3之间切换

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)begin
            wr_load_r0   <=  1'd0;
            wr_load_r1   <=  1'd0;
            end
        else begin
            wr_load_r0   <=  vin_vs;
            wr_load_r1   <=  wr_load_r0;
            end
end 

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             wr_page    <=  2'd0;
         else if(wr_load_r0 && !wr_load_r1)
             wr_page    <=  wr_page + 1'b1;
end

3.ddr读帧缓存切换

将hdmi输出的场信号的上升沿做为计数信号,每次检测到上升沿直接将当前读ddr帧存减1,这样做的目的,就是为了让读和写不在同一个帧存,避免图像有撕裂现象(一般显示撕裂也不明显,单帧也是可以的,但为了显示效果建议还是不要在同一个帧存进行)

always@(posedge ui_clk or negedge rst_n)begin
        if(!rst_n)begin
            rd_load_r0   <=  1'd0;
            rd_load_r1   <=  1'd0;
            end
        else begin 
            rd_load_r0   <=  vout_vs;
            rd_load_r1   <=  rd_load_r0;
            end
end

always @(posedge ui_clk or negedge rst_n) begin
         if(!rst_n)
             rd_page    <=  2'd0;
         else if(rd_load_r0 && !rd_load_r1)
             rd_page    <=  wr_page - 1'b1;
end

从ddr手册看,行地址宽度是[14:0],列地址宽度为[9:0],所以ddr的寻址空间为[24:0],所以帧存控制管脚BA0,BA1,BA2,为ddr地址里25,26,27这三个管脚,2^3=8所以最大寻址控制为0~7一共8个帧存,又因我们上面mig控制器设置的是4,所以将ddr寻址的27这个管脚设置为0,直接使用25,26两个管脚来进行帧存切换,一共有0,1,2,3这样四种帧存切换,如下图所示。

hdmi输入和输出显示工程截图如下所示

工程看起来也不是很多,将黑金的hdmi输入和输出工程的axi的ddr控制全部去掉,然后把ddr读写这部分放进去,两个hdmi输入和输出的iic配置都是使用黑金的代码,ddr缓存使用前面的工程文件

四,硬件连接

hdmi输入接机箱,hdmi输出接显示屏

 五,显示效果

手机不行,只能拍出这种效果了,实际显示还是很清晰的

  工程下载链接:链接:链接:https://pan.baidu.com/s/1_3o0YiaL7cE_9mjd9fy6GQ  提取码:4clr

如若转载,请注明出处

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值