查看: 1191|回复: 0

[评测分享] 【ALINX和紫光同创PGL12G开发板】-迫不及待地先试试HDMI 试用3

[复制链接]
  • TA的每日心情
    开心
    2020-7-25 10:37
  • 签到天数: 40 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2020-7-28 08:59:00 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 武器哈12 于 2020-7-28 01:47 编辑

        高清多媒体接口High Definition Multimedia Interface,HDMI)是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。
           HDMI 采用和 DVI 相同的传输原理——TMDS(Transition  Minimized  Differential  signal),最小化传输差分信号。 TMDS 传输系统分为分为两个部分:发送端和接收端。TMDS 发送端收到 HDMI 接口传来的示 RGB 信号的 24 位并行数(TMDS 对每个像素的 RGB 三原色分别按 8bit 编码,即 R 信号有 8位,G 信号有 8 位,B 信号有 8 位),然后对这些数据进行编码和并/串转换,再将表示 3 个 RGB信号的数据分别分配到独立的传输通道发送出去。接收端接收来自发送端的串行信号,对其进行解码和串/并转换,然后发送到显示器的控制端。与此同时也接收时钟信号,以实现同步。
       HDMI 输出程序设计
       实验将实现 HDMI 输出显示,verilog 实现编程驱动 HDMI 输出,在 HDMI 显示器里显示测
    试图像彩条。HDMI 输出显示模块分成 3 个模块实现,分别是时钟模块 vidio_pll,  彩条生成模块
    color_bar 和 VGA 转 DVI 模块 dvi_encoder。实现的逻辑框图如下:

    hdmi1.JPG       

    站在巨人的肩膀上,我们可以把VGA转DVI模块可以当做一个IP来使用,只要我们懂得VGA时序就可以来使用或者完成本次实验。VGA时序:
        VGA时序.jpg

        想更进一步了解VGA时序:https://blog.csdn.net/liuligui5200/article/details/80974319
        彩条产生模块 color_bar.v:
        color_bar.v 是产生 8 种颜色的 VGA 格式的彩条,彩条分别为白、黄、青、绿、紫、红、蓝和黑。针对 VGA 的时序,行同步和场同步各使用一个计数器,行同步计数器用于产生行同步,行有效像素,场同步计数器用于产生场同步,场有效像素。同时根据计数器的值可以产生水平(X)和垂直(Y)坐标,通过坐标信息,可以实时显示一些图形。

        在屏幕中显示汉字:
        在 HDMI 显示的基础上增加了一个 osd_display 的模块,“osd_display”模块是用来读取存储在 Rom ip 核里转换后的字符信息,并在指定区域显示。osd_display 模块包timing_gen_xy  模块和 osd_rom 模块。Osd_rom 里存储的字符数据,如果数据为 1,OSD 的区域显示 ROM 中的前景红色,如果数据是 0,OSD 的区域显示数据为背景色(彩条)。程序框图如下图所示:

        hdmi2.JPG


      在“timing_gen_xy”模块是根据 HDMI 时序标准定义了“x_cnt”和“y_cnt”两个计数器并由这两个计数器产生了 HDMI 显示的“x”坐标和“y”坐标。程序中用“vs_edge”和“de_falling”分 别 表 示 场 同 步 开 始 信 号 和 数 据 有 效 结 束 信 号 。
        hdmi3.JPG
        下面利用“FPGA 字模提取”工具生成能够被 Pango FPGA 识别的.dat 文件:
    2.JPG 1.JPG

    大概知道代码实现方式后,修改下面代码中加粗部分代码,编译后下载到FPGA开发板。
    • module osd_display(
    •         input                       rst_n,
    •         input                       pclk,
    •         input[23:0]                 wave_color,
    •         input                       adc_clk,
    •         input                       adc_buf_wr,
    •         input[11:0]                 adc_buf_addr,
    •         input[7:0]                  adc_buf_data,
    •         input                       i_hs,
    •         input                       i_vs,
    •         input                       i_de,
    •         input[23:0]                 i_data,
    •         output                      o_hs,
    •         output                      o_vs,
    •         output                      o_de,
    •         output[23:0]                o_data
    • );
    • parameter OSD_WIDTH   =  12'd264;
    • parameter OSD_HEGIHT  =  12'd64;
    • parameter OSD_WIDTH_OFFSET   =  12'd500;
    • parameter OSD_HEGIHT_OFFSET  =  12'd320;
    • wire[11:0] pos_x;
    • wire[11:0] pos_y;
    • wire       pos_hs;
    • wire       pos_vs;
    • wire       pos_de;
    • wire[23:0] pos_data;
    • reg[23:0]  v_data;
    • reg[11:0]  osd_x;
    • reg[11:0]  osd_y;
    • reg[18:0]  osd_ram_addr;
    • wire[7:0]  q;
    • reg        region_active;
    • reg        region_active_d0;
    • reg        region_active_d1;
    • reg        region_active_d2;
    • reg        pos_vs_d0;
    • reg        pos_vs_d1;
    • assign o_data = v_data;
    • assign o_hs = pos_hs;
    • assign o_vs = pos_vs;
    • assign o_de = pos_de;
    • //delay 1 clock
    • always@(posedge pclk)
    • begin
    •         if(pos_y >= OSD_HEGIHT_OFFSET && pos_y <= OSD_HEGIHT_OFFSET + OSD_HEGIHT - 12'd1 && pos_x >= OSD_WIDTH_OFFSET && pos_x  <= OSD_WIDTH_OFFSET + OSD_WIDTH - 12'd1)
    •                 region_active <= 1'b1;
    •         else
    •                 region_active <= 1'b0;
    • end
    • always@(posedge pclk)
    • begin
    •         region_active_d0 <= region_active;
    •         region_active_d1 <= region_active_d0;
    •         region_active_d2 <= region_active_d1;
    • end
    • always@(posedge pclk)
    • begin
    •         pos_vs_d0 <= pos_vs;
    •         pos_vs_d1 <= pos_vs_d0;
    • end
    • //delay 2 clock
    • //region_active_d0
    • always@(posedge pclk)
    • begin
    •         if(region_active_d0 == 1'b1)
    •                 osd_x <= osd_x + 12'd1;
    •         else
    •                 osd_x <= 12'd0;
    • end
    • always@(posedge pclk)
    • begin
    •         if(pos_vs_d1 == 1'b1 && pos_vs_d0 == 1'b0)
    •                 osd_ram_addr <= 16'd0;
    •         else if(region_active == 1'b1)
    •                 osd_ram_addr <= osd_ram_addr + 16'd1;
    • end
    • always@(posedge pclk)
    • begin
    •         if(region_active_d0 == 1'b1)
    •                 if(q[osd_x[2:0]] == 1'b1)//这里很重要!一个字节代表 8 个时钟的像素,所以在从 Rom IP 核中读取 dat 文件的值,                              //需要判断每一位的值,如果值为 1,显示红色前景色,否则显示背景色
    •                         v_data <= 24'hffff00;
    •                 else
    •                         v_data <= pos_data;
    •         else
    •                 v_data <= pos_data;
    • end
    • osd_rom osd_rom_m0 (         //存储字符的RAM
    •     .addr(osd_ram_addr[16:3]),
    •     .clk(pclk),
    •     .rst(1'b0),
    •     .rd_data(q));
    • timing_gen_xy timing_gen_xy_m0(
    •         .rst_n    (rst_n    ),
    •         .clk      (pclk     ),
    •         .i_hs     (i_hs     ),
    •         .i_vs     (i_vs     ),
    •         .i_de     (i_de     ),
    •         .i_data   (i_data   ),
    •         .o_hs     (pos_hs   ),
    •         .o_vs     (pos_vs   ),
    •         .o_de     (pos_de   ),
    •         .o_data   (pos_data ),
    •         .x        (pos_x    ),//XY坐标
    •         .y        (pos_y    )
    • );
    • endmodule



    实验结果:
    E6E963F8436BFFE2864697D9BE829727.png BC8EFF601B38AA69E21506E0387B4757.png






    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 12:40 , Processed in 0.111510 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.