当前位置:   article > 正文

FPGA学习记录(5)_HDMI彩条显示_正点原子领航者开发板

FPGA学习记录(5)_HDMI彩条显示_正点原子领航者开发板

前言

        今天学习正点原子领航者开发板HDMI彩条显示模块,以下是记录的笔记和重写的代码。


1:HDMI彩条显示

1.1 HDMI

        VGA接口接收模拟信号,分辨率高了之后,就会受到干扰。HDMI接口取代了VGA接口,支持高分辨率。

1.2 TMDS编码

 1.3 原语

        原语:英文名称Primitive,是Xilinx针对其器件特征开发的一系列常用模块名称,涵盖了FPGA开发过程中的常用领域,方便用户直接调用FPGA的底层组件。以Xilinx为例,共分为10类:计算组件、IO端口组件、寄存器/锁存器、时钟组件、处理器组件、移位寄存器、配置和检测组件、RAM/ROM组件、Slice/CLB组件以及G-tranceiver。原语可以看作是库函数,可以直接例化调用,使用方便,功能全面,可以有效提高开发效率。

         PAD是FPGA的金属引脚,从FPGA出来后,首先跟IOB对接,IDELAY和ODELAY的作用是数据同时对齐,以免发生延迟。

        IOB主要的作用是三态门,差分信号和单端,单端和差分信号互相转换。

OSERDESE2工作时序图

OSERDESE2三态时序图


2:  波形图——写代码

2.1 video_driver

        1:行场同步信号赋值:分别在计数器大于等于其行场同步时间赋1,小于行场同步时间赋0。

        2:行计数器h_cnt对像素时钟计数:与上节LCD实验相同。

        3:场计数器v_cnt对行计数:与上节LCD实验相同。

        4:请求像素点颜色数据输入data_req:与上节LCD实验相同。

        5:数据使能信号:与上节LCD实验相同。

  1. //像素点x坐标
  2. always@ (posedge pixel_clk or negedge sys_rst_n) begin
  3. if(!sys_rst_n)
  4. pixel_xpos <= 11'd0;
  5. else if(data_req)
  6. pixel_xpos <= cnt_h + 2'd2 - H_SYNC - H_BACK ;
  7. else
  8. pixel_xpos <= 11'd0;
  9. end

        6:像素点x坐标:data_req拉高的时候,pixel_xpos <= h_cnt + 2'd2 - h_sync - h_back,加2的原因是pixel_xpos是从1开始的,而计数器是从0开始计时,所以得先加个1。其次是因为data_req信号比使能信号早一个周期,时序赋值也得加个1。

  1. //像素点y坐标
  2. always@ (posedge pixel_clk or negedge sys_rst_n) begin
  3. if(!sys_rst_n)
  4. pixel_ypos <= 11'd0;
  5. else if((cnt_v >= (V_SYNC + V_BACK)) && (cnt_v < (V_SYNC + V_BACK + V_DISP)))
  6. pixel_ypos <= cnt_v + 1'b1 - (V_SYNC + V_BACK) ;
  7. else
  8. pixel_ypos <= 11'd0;
  9. end

        7:像素点y坐标:场计数器位于有效显示区域时,pixel_ypos <= v_cnt + 1‘b1’ - v_sync -v_back,加1的原因是pixel_ypos是从1开始的,而计数器是从0开始计时,所以得加个1。

  1. module video_driver(
  2. input pixel_clk ,
  3. input sys_rst_n ,
  4. //RGB接口
  5. output video_hs , //行同步信号
  6. output video_vs , //场同步信号
  7. output video_de , //数据使能
  8. output [23:0] video_rgb , //RGB888颜色数据
  9. output reg data_req ,
  10. input [23:0] pixel_data , //像素点数据
  11. output reg [10:0] pixel_xpos , //像素点横坐标
  12. output reg [10:0] pixel_ypos //像素点纵坐标
  13. );
  14. //parameter define
  15. //1280*720 分辨率时序参数
  16. parameter H_SYNC = 11'd40; //行同步
  17. parameter H_BACK = 11'd220; //行显示后沿
  18. parameter H_DISP = 11'd1280; //行有效数据
  19. parameter H_FRONT = 11'd110; //行显示前沿
  20. parameter H_TOTAL = 11'd1650; //行扫描周期
  21. parameter V_SYNC = 11'd5; //场同步
  22. parameter V_BACK = 11'd20; //场显示后沿
  23. parameter V_DISP = 11'd720; //场有效数据
  24. parameter V_FRONT = 11'd5; //场显示前沿
  25. parameter V_TOTAL = 11'd750; //场扫描周期
  26. //1920*1080分辨率时序参数
  27. //parameter H_SYNC = 12'd44; //行同步
  28. //parameter H_BACK = 12'd148; //行显示后沿
  29. //parameter H_DISP = 12'd1920; //行有效数据
  30. //parameter H_FRONT = 12'd88; //行显示前沿
  31. //parameter H_TOTAL = 12'd2200; //行扫描周期
  32. //
  33. //parameter V_SYNC = 12'd5; //场同步
  34. //parameter V_BACK = 12'd36; //场显示后沿
  35. //parameter V_DISP = 12'd1080; //场有效数据
  36. //parameter V_FRONT = 12'd4; //场显示前沿
  37. //parameter V_TOTAL = 12'd1125; //场扫描周期
  38. //reg define
  39. reg [11:0] cnt_h;
  40. reg [11:0] cnt_v;
  41. reg video_en;
  42. //*****************************************************
  43. //** main code
  44. //*****************************************************
  45. assign video_de = video_en;
  46. assign video_hs = ( cnt_h < H_SYNC ) ? 1'b0 : 1'b1; //行同步信号赋值
  47. assign video_vs = ( cnt_v < V_SYNC ) ? 1'b0 : 1'b1; //场同步信号赋值
  48. //使能RGB数据输出
  49. always @(posedge pixel_clk or negedge sys_rst_n) begin
  50. if(!sys_rst_n)
  51. video_en <= 1'b0;
  52. else
  53. video_en <= data_req;
  54. end
  55. //RGB888数据输出
  56. assign video_rgb = video_de ? pixel_data : 24'd0;
  57. //请求像素点颜色数据输入
  58. always @(posedge pixel_clk or negedge sys_rst_n) begin
  59. if(!sys_rst_n)
  60. data_req <= 1'b0;
  61. else if(((cnt_h >= H_SYNC + H_BACK - 2'd2) && (cnt_h < H_SYNC + H_BACK + H_DISP - 2'd2))
  62. && ((cnt_v >= V_SYNC + V_BACK) && (cnt_v < V_SYNC + V_BACK+V_DISP)))
  63. data_req <= 1'b1;
  64. else
  65. data_req <= 1'b0;
  66. end
  67. //像素点x坐标
  68. always@ (posedge pixel_clk or negedge sys_rst_n) begin
  69. if(!sys_rst_n)
  70. pixel_xpos <= 11'd0;
  71. else if(data_req)
  72. pixel_xpos <= cnt_h + 2'd2 - H_SYNC - H_BACK ;
  73. else
  74. pixel_xpos <= 11'd0;
  75. end
  76. //行计数器对像素时钟计数
  77. always @(posedge pixel_clk or negedge sys_rst_n) begin
  78. if (!sys_rst_n)
  79. cnt_h <= 11'd0;
  80. else begin
  81. if(cnt_h < H_TOTAL - 1'b1)
  82. cnt_h <= cnt_h + 1'b1;
  83. else
  84. cnt_h <= 11'd0;
  85. end
  86. end
  87. //场计数器对行计数
  88. always @(posedge pixel_clk or negedge sys_rst_n) begin
  89. if (!sys_rst_n)
  90. cnt_v <= 11'd0;
  91. else if(cnt_h == H_TOTAL - 1'b1) begin
  92. if(cnt_v < V_TOTAL - 1'b1)
  93. cnt_v <= cnt_v + 1'b1;
  94. else
  95. cnt_v <= 11'd0;
  96. end
  97. end
  98. endmodule

2.2 video_display

        与上节LCD实验几乎相同,除了分辨率都一样。

  1. module video_display(
  2. input pixel_clk,
  3. input sys_rst_n,
  4. input [10:0] pixel_xpos, //像素点横坐标
  5. input [10:0] pixel_ypos, //像素点纵坐标
  6. output reg [23:0] pixel_data //像素点数据
  7. );
  8. //parameter define
  9. parameter H_DISP = 11'd1280; //分辨率——行
  10. parameter V_DISP = 11'd720; //分辨率——列
  11. localparam WHITE = 24'b11111111_11111111_11111111; //RGB888 白色
  12. localparam BLACK = 24'b00000000_00000000_00000000; //RGB888 黑色
  13. localparam RED = 24'b11111111_00001100_00000000; //RGB888 红色
  14. localparam GREEN = 24'b00000000_11111111_00000000; //RGB888 绿色
  15. localparam BLUE = 24'b00000000_00000000_11111111; //RGB888 蓝色
  16. //*****************************************************
  17. //** main code
  18. //*****************************************************
  19. //根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
  20. always @(posedge pixel_clk ) begin
  21. if (!sys_rst_n)
  22. pixel_data <= 16'd0;
  23. else begin
  24. if((pixel_xpos >= 0) && (pixel_xpos < (H_DISP/5)*1))
  25. pixel_data <= WHITE;
  26. else if((pixel_xpos >= (H_DISP/5)*1) && (pixel_xpos < (H_DISP/5)*2))
  27. pixel_data <= BLACK;
  28. else if((pixel_xpos >= (H_DISP/5)*2) && (pixel_xpos < (H_DISP/5)*3))
  29. pixel_data <= RED;
  30. else if((pixel_xpos >= (H_DISP/5)*3) && (pixel_xpos < (H_DISP/5)*4))
  31. pixel_data <= GREEN;
  32. else
  33. pixel_data <= BLUE;
  34. end
  35. end
  36. endmodule

2.3 dvi_ecoder

        1:计算像素数据中“1”的个数

  1. always @ (posedge clkin) begin
  2. n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];
  3. din_q <=#1 din;
  4. end

        代码中,#1代表延迟一个时间刻度尺,在实际代码生成比特流的过程中是不考虑它的,也就是不可综合,只在仿真中起作用。

        2:判断1的个数是否大于4

assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));

        3:如果1的个数大于等于4,对输入的比特数据进行异或非操作。如果1的个数小于4,对输入的比特数据进行异或操作。

  1. wire [8:0] q_m;
  2. assign q_m[0] = din_q[0];
  3. assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
  4. assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
  5. assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
  6. assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
  7. assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
  8. assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
  9. assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
  10. assign q_m[8] = (decision1) ? 1'b0 : 1'b1;

        4:de、c1、q_m信号进行数据对齐。

  1. always @ (posedge clkin) begin
  2. de_q <=#1 de;
  3. de_reg <=#1 de_q;
  4. c0_q <=#1 c0;
  5. c0_reg <=#1 c0_q;
  6. c1_q <=#1 c1;
  7. c1_reg <=#1 c1_q;
  8. q_m_reg <=#1 q_m;
  9. end

        5:如果de_reg信号为0,则执行以下代码。

  1. case ({c1_reg, c0_reg})
  2. 2'b00: dout <=#1 CTRLTOKEN0;
  3. 2'b01: dout <=#1 CTRLTOKEN1;
  4. 2'b10: dout <=#1 CTRLTOKEN2;
  5. default: dout <=#1 CTRLTOKEN3;
  6. endcase

        6:如果de_reg信号为1且decision2 == (cnt == 5'h0) | (n1q_m == n0q_m),则执行以下代码:

  1. if(decision2) begin
  2. dout[9] <=#1 ~q_m_reg[8];
  3. dout[8] <=#1 q_m_reg[8];
  4. dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
  5. cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
  6. end

        7:如果de_reg信号为1且decision2 != (cnt == 5'h0) | (n1q_m == n0q_m),则执行以下代码:

  1. if(decision3) begin
  2. dout[9] <=#1 1'b1;
  3. dout[8] <=#1 q_m_reg[8];
  4. dout[7:0] <=#1 ~q_m_reg[7:0];
  5. cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
  6. end else begin
  7. dout[9] <=#1 1'b0;
  8. dout[8] <=#1 q_m_reg[8];
  9. dout[7:0] <=#1 q_m_reg[7:0];
  10. cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
  11. end
  1. `timescale 1 ps / 1ps
  2. module dvi_encoder (
  3. input clkin, // pixel clock input
  4. input rstin, // async. reset input (active high)
  5. input [7:0] din, // data inputs: expect registered
  6. input c0, // c0 input
  7. input c1, // c1 input
  8. input de, // de input
  9. output reg [9:0] dout // data outputs
  10. );
  11. // Counting number of 1s and 0s for each incoming pixel
  12. // component. Pipe line the result.
  13. // Register Data Input so it matches the pipe lined adder
  14. // output
  15. reg [3:0] n1d; //number of 1s in din
  16. reg [7:0] din_q;
  17. //计算像素数据中“1”的个数
  18. always @ (posedge clkin) begin
  19. n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];
  20. din_q <=#1 din;
  21. end
  22. ///
  23. // Stage 1: 8 bit -> 9 bit
  24. // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  25. ///
  26. wire decision1;
  27. assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));
  28. wire [8:0] q_m;
  29. assign q_m[0] = din_q[0];
  30. assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
  31. assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
  32. assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
  33. assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
  34. assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
  35. assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
  36. assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
  37. assign q_m[8] = (decision1) ? 1'b0 : 1'b1;
  38. /
  39. // Stage 2: 9 bit -> 10 bit
  40. // Refer to DVI 1.0 Specification, page 29, Figure 3-5
  41. /
  42. reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
  43. always @ (posedge clkin) begin
  44. n1q_m <=#1 q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
  45. n0q_m <=#1 4'h8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
  46. end
  47. parameter CTRLTOKEN0 = 10'b1101010100;
  48. parameter CTRLTOKEN1 = 10'b0010101011;
  49. parameter CTRLTOKEN2 = 10'b0101010100;
  50. parameter CTRLTOKEN3 = 10'b1010101011;
  51. reg [4:0] cnt; //disparity counter, MSB is the sign bit
  52. wire decision2, decision3;
  53. assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);
  54. /
  55. // [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
  56. /
  57. assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));
  58. // pipe line alignment
  59. reg de_q, de_reg;
  60. reg c0_q, c1_q;
  61. reg c0_reg, c1_reg;
  62. reg [8:0] q_m_reg;
  63. always @ (posedge clkin) begin
  64. de_q <=#1 de;
  65. de_reg <=#1 de_q;
  66. c0_q <=#1 c0;
  67. c0_reg <=#1 c0_q;
  68. c1_q <=#1 c1;
  69. c1_reg <=#1 c1_q;
  70. q_m_reg <=#1 q_m;
  71. end
  72. ///
  73. // 10-bit out
  74. // disparity counter
  75. ///
  76. always @ (posedge clkin or posedge rstin) begin
  77. if(rstin) begin
  78. dout <= 10'h0;
  79. cnt <= 5'h0;
  80. end else begin
  81. if (de_reg) begin
  82. if(decision2) begin
  83. dout[9] <=#1 ~q_m_reg[8];
  84. dout[8] <=#1 q_m_reg[8];
  85. dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
  86. cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);
  87. end else begin
  88. if(decision3) begin
  89. dout[9] <=#1 1'b1;
  90. dout[8] <=#1 q_m_reg[8];
  91. dout[7:0] <=#1 ~q_m_reg[7:0];
  92. cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
  93. end else begin
  94. dout[9] <=#1 1'b0;
  95. dout[8] <=#1 q_m_reg[8];
  96. dout[7:0] <=#1 q_m_reg[7:0];
  97. cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
  98. end
  99. end
  100. end else begin
  101. case ({c1_reg, c0_reg})
  102. 2'b00: dout <=#1 CTRLTOKEN0;
  103. 2'b01: dout <=#1 CTRLTOKEN1;
  104. 2'b10: dout <=#1 CTRLTOKEN2;
  105. default: dout <=#1 CTRLTOKEN3;
  106. endcase
  107. cnt <=#1 5'h0;
  108. end
  109. end
  110. end
  111. endmodule

2.4 serializer_10_to_1

        例化了两个原语,一个作为主模式使用,一个作为从模式使用。因为一个OSERDESE2最多使用8bit的数据,所以要有两个OSERDESE模块级联来使用。DDR是指双边沿的数据采样,所以只要5倍时钟就可以。DATA_WIDTH并转串数据的位宽,所以这里设计成10bit的数据就行。TRISTATE_WIDTH是指三态的位宽,因为本节不使用,所以位宽设置为1。从模式的SHIFTOUT1和SHIFTOUT2连接到了主模式的SHIFTIN1和SHIFTIN2。作用就是把10bit的数据转成1bit的数据输出出去,输出为serial_data_out。

  1. `timescale 1ns / 1ps
  2. module serializer_10_to_1(
  3. input reset, // 复位,高有效
  4. input paralell_clk, // 输入并行数据时钟
  5. input serial_clk_5x, // 输入串行数据时钟
  6. input [9:0] paralell_data, // 输入并行数据
  7. output serial_data_out // 输出串行数据
  8. );
  9. //wire define
  10. wire cascade1; //用于两个OSERDESE2级联的信号
  11. wire cascade2;
  12. //*****************************************************
  13. //** main code
  14. //*****************************************************
  15. //例化OSERDESE2原语,实现并串转换,Master模式
  16. OSERDESE2 #(
  17. .DATA_RATE_OQ ("DDR"), // 设置双倍数据速率
  18. .DATA_RATE_TQ ("SDR"), // DDR, BUF, SDR
  19. .DATA_WIDTH (10), // 输入的并行数据宽度为10bit
  20. .SERDES_MODE ("MASTER"), // 设置为Master,用于10bit宽度扩展
  21. .TBYTE_CTL ("FALSE"), // Enable tristate byte operation (FALSE, TRUE)
  22. .TBYTE_SRC ("FALSE"), // Tristate byte source (FALSE, TRUE)
  23. .TRISTATE_WIDTH (1) // 3-state converter width (1,4)
  24. )
  25. OSERDESE2_Master (
  26. .CLK (serial_clk_5x), // 串行数据时钟,5倍时钟频率
  27. .CLKDIV (paralell_clk), // 并行数据时钟
  28. .RST (reset), // 1-bit input: Reset
  29. .OCE (1'b1), // 1-bit input: Output data clock enable
  30. .OQ (serial_data_out), // 串行输出数据
  31. .D1 (paralell_data[0]), // D1 - D8: 并行数据输入
  32. .D2 (paralell_data[1]),
  33. .D3 (paralell_data[2]),
  34. .D4 (paralell_data[3]),
  35. .D5 (paralell_data[4]),
  36. .D6 (paralell_data[5]),
  37. .D7 (paralell_data[6]),
  38. .D8 (paralell_data[7]),
  39. .SHIFTIN1 (cascade1), // SHIFTIN1 用于位宽扩展
  40. .SHIFTIN2 (cascade2), // SHIFTIN2
  41. .SHIFTOUT1 (), // SHIFTOUT1: 用于位宽扩展
  42. .SHIFTOUT2 (), // SHIFTOUT2
  43. .OFB (), // 以下是未使用信号
  44. .T1 (1'b0),
  45. .T2 (1'b0),
  46. .T3 (1'b0),
  47. .T4 (1'b0),
  48. .TBYTEIN (1'b0),
  49. .TCE (1'b0),
  50. .TBYTEOUT (),
  51. .TFB (),
  52. .TQ ()
  53. );
  54. //例化OSERDESE2原语,实现并串转换,Slave模式
  55. OSERDESE2 #(
  56. .DATA_RATE_OQ ("DDR"), // 设置双倍数据速率
  57. .DATA_RATE_TQ ("SDR"), // DDR, BUF, SDR
  58. .DATA_WIDTH (10), // 输入的并行数据宽度为10bit
  59. .SERDES_MODE ("SLAVE"), // 设置为Slave,用于10bit宽度扩展
  60. .TBYTE_CTL ("FALSE"), // Enable tristate byte operation (FALSE, TRUE)
  61. .TBYTE_SRC ("FALSE"), // Tristate byte source (FALSE, TRUE)
  62. .TRISTATE_WIDTH (1) // 3-state converter width (1,4)
  63. )
  64. OSERDESE2_Slave (
  65. .CLK (serial_clk_5x), // 串行数据时钟,5倍时钟频率
  66. .CLKDIV (paralell_clk), // 并行数据时钟
  67. .RST (reset), // 1-bit input: Reset
  68. .OCE (1'b1), // 1-bit input: Output data clock enable
  69. .OQ (), // 串行输出数据
  70. .D1 (1'b0), // D1 - D8: 并行数据输入
  71. .D2 (1'b0),
  72. .D3 (paralell_data[8]),
  73. .D4 (paralell_data[9]),
  74. .D5 (1'b0),
  75. .D6 (1'b0),
  76. .D7 (1'b0),
  77. .D8 (1'b0),
  78. .SHIFTIN1 (), // SHIFTIN1 用于位宽扩展
  79. .SHIFTIN2 (), // SHIFTIN2
  80. .SHIFTOUT1 (cascade1), // SHIFTOUT1: 用于位宽扩展
  81. .SHIFTOUT2 (cascade2), // SHIFTOUT2
  82. .OFB (), // 以下是未使用信号
  83. .T1 (1'b0),
  84. .T2 (1'b0),
  85. .T3 (1'b0),
  86. .T4 (1'b0),
  87. .TBYTEIN (1'b0),
  88. .TCE (1'b0),
  89. .TBYTEOUT (),
  90. .TFB (),
  91. .TQ ()
  92. );
  93. endmodule

2.5 dvi_transmitter_top

        这里使用的是OBUFDS原语,然后产生tmds_data_p的差分信号,差分信号最终接到顶层模块的端口,通过顶层,通过FPGA的IO引脚,连接到HDMI显示屏。

  1. module dvi_transmitter_top(
  2. input pclk, // pixel clock
  3. input pclk_x5, // pixel clock x5
  4. input reset_n, // reset
  5. input [23:0] video_din, // RGB888 video in
  6. input video_hsync, // hsync data
  7. input video_vsync, // vsync data
  8. input video_de, // data enable
  9. output tmds_clk_p, // TMDS 时钟通道
  10. output tmds_clk_n,
  11. output [2:0] tmds_data_p, // TMDS 数据通道
  12. output [2:0] tmds_data_n,
  13. output tmds_oen // TMDS 输出使能
  14. );
  15. //wire define
  16. wire reset;
  17. //并行数据
  18. wire [9:0] red_10bit;
  19. wire [9:0] green_10bit;
  20. wire [9:0] blue_10bit;
  21. wire [9:0] clk_10bit;
  22. //串行数据
  23. wire [2:0] tmds_data_serial;
  24. wire tmds_clk_serial;
  25. //*****************************************************
  26. //** main code
  27. //*****************************************************
  28. assign tmds_oen = 1'b1;
  29. assign clk_10bit = 10'b1111100000;
  30. //异步复位,同步释放
  31. asyn_rst_syn reset_syn(
  32. .reset_n (reset_n),
  33. .clk (pclk),
  34. .syn_reset (reset) //高有效
  35. );
  36. //对三个颜色通道进行编码
  37. dvi_encoder encoder_b (
  38. .clkin (pclk),
  39. .rstin (reset),
  40. .din (video_din[7:0]),
  41. .c0 (video_hsync),
  42. .c1 (video_vsync),
  43. .de (video_de),
  44. .dout (blue_10bit)
  45. ) ;
  46. dvi_encoder encoder_g (
  47. .clkin (pclk),
  48. .rstin (reset),
  49. .din (video_din[15:8]),
  50. .c0 (1'b0),
  51. .c1 (1'b0),
  52. .de (video_de),
  53. .dout (green_10bit)
  54. ) ;
  55. dvi_encoder encoder_r (
  56. .clkin (pclk),
  57. .rstin (reset),
  58. .din (video_din[23:16]),
  59. .c0 (1'b0),
  60. .c1 (1'b0),
  61. .de (video_de),
  62. .dout (red_10bit)
  63. ) ;
  64. //对编码后的数据进行并串转换
  65. serializer_10_to_1 serializer_b(
  66. .reset (reset), // 复位,高有效
  67. .paralell_clk (pclk), // 输入并行数据时钟
  68. .serial_clk_5x (pclk_x5), // 输入串行数据时钟
  69. .paralell_data (blue_10bit), // 输入并行数据
  70. .serial_data_out (tmds_data_serial[0]) // 输出串行数据
  71. );
  72. serializer_10_to_1 serializer_g(
  73. .reset (reset),
  74. .paralell_clk (pclk),
  75. .serial_clk_5x (pclk_x5),
  76. .paralell_data (green_10bit),
  77. .serial_data_out (tmds_data_serial[1])
  78. );
  79. serializer_10_to_1 serializer_r(
  80. .reset (reset),
  81. .paralell_clk (pclk),
  82. .serial_clk_5x (pclk_x5),
  83. .paralell_data (red_10bit),
  84. .serial_data_out (tmds_data_serial[2])
  85. );
  86. serializer_10_to_1 serializer_clk(
  87. .reset (reset),
  88. .paralell_clk (pclk),
  89. .serial_clk_5x (pclk_x5),
  90. .paralell_data (clk_10bit),
  91. .serial_data_out (tmds_clk_serial)
  92. );
  93. //转换差分信号
  94. OBUFDS #(
  95. .IOSTANDARD ("TMDS_33") // I/O电平标准为TMDS
  96. ) TMDS0 (
  97. .I (tmds_data_serial[0]),
  98. .O (tmds_data_p[0]),
  99. .OB (tmds_data_n[0])
  100. );
  101. OBUFDS #(
  102. .IOSTANDARD ("TMDS_33") // I/O电平标准为TMDS
  103. ) TMDS1 (
  104. .I (tmds_data_serial[1]),
  105. .O (tmds_data_p[1]),
  106. .OB (tmds_data_n[1])
  107. );
  108. OBUFDS #(
  109. .IOSTANDARD ("TMDS_33") // I/O电平标准为TMDS
  110. ) TMDS2 (
  111. .I (tmds_data_serial[2]),
  112. .O (tmds_data_p[2]),
  113. .OB (tmds_data_n[2])
  114. );
  115. OBUFDS #(
  116. .IOSTANDARD ("TMDS_33") // I/O电平标准为TMDS
  117. ) TMDS3 (
  118. .I (tmds_clk_serial),
  119. .O (tmds_clk_p),
  120. .OB (tmds_clk_n)
  121. );
  122. endmodule

2.6 asyn_rst_syn

        因为一个FPGA芯片中,每个模块之间传输有距离,导致传输过程中会有延迟。该模块作用是将复位信号进行同步释放,就可以同时进入工作状态。

  1. module asyn_rst_syn(
  2. input clk, //目的时钟域
  3. input reset_n, //异步复位,低有效
  4. output syn_reset //高有效
  5. );
  6. //reg define
  7. reg reset_1;
  8. reg reset_2;
  9. //*****************************************************
  10. //** main code
  11. //*****************************************************
  12. assign syn_reset = reset_2;
  13. //对异步复位信号进行同步释放,并转换成高有效
  14. always @ (posedge clk or negedge reset_n) begin
  15. if(!reset_n) begin
  16. reset_1 <= 1'b1;
  17. reset_2 <= 1'b1;
  18. end
  19. else begin
  20. reset_1 <= 1'b0;
  21. reset_2 <= reset_1;
  22. end
  23. end
  24. endmodule

2.7 hdmi_colorbar_top

        调用了锁相环PLL、视频显示驱动。视频显示、HDMI驱动等模块。

  1. module hdmi_colorbar_top(
  2. input sys_clk,
  3. input sys_rst_n,
  4. output tmds_clk_p, // TMDS 时钟通道
  5. output tmds_clk_n,
  6. output [2:0] tmds_data_p, // TMDS 数据通道
  7. output [2:0] tmds_data_n
  8. );
  9. //wire define
  10. wire pixel_clk;
  11. wire pixel_clk_5x;
  12. wire clk_locked;
  13. wire [10:0] pixel_xpos_w;
  14. wire [10:0] pixel_ypos_w;
  15. wire [23:0] pixel_data_w;
  16. wire video_hs;
  17. wire video_vs;
  18. wire video_de;
  19. wire [23:0] video_rgb;
  20. //*****************************************************
  21. //** main code
  22. //*****************************************************
  23. //例化MMCM/PLL IP核
  24. clk_wiz_0 clk_wiz_0(
  25. .clk_in1 (sys_clk),
  26. .clk_out1 (pixel_clk), //像素时钟
  27. .clk_out2 (pixel_clk_5x), //5倍像素时钟
  28. .reset (~sys_rst_n),
  29. .locked (clk_locked)
  30. );
  31. //例化视频显示驱动模块
  32. video_driver u_video_driver(
  33. .pixel_clk ( pixel_clk ),
  34. .sys_rst_n ( sys_rst_n ),
  35. .video_hs ( video_hs ),
  36. .video_vs ( video_vs ),
  37. .video_de ( video_de ),
  38. .video_rgb ( video_rgb ),
  39. .data_req (),
  40. .pixel_xpos ( pixel_xpos_w ),
  41. .pixel_ypos ( pixel_ypos_w ),
  42. .pixel_data ( pixel_data_w )
  43. );
  44. //例化视频显示模块
  45. video_display u_video_display(
  46. .pixel_clk (pixel_clk),
  47. .sys_rst_n (sys_rst_n),
  48. .pixel_xpos (pixel_xpos_w),
  49. .pixel_ypos (pixel_ypos_w),
  50. .pixel_data (pixel_data_w)
  51. );
  52. //例化HDMI驱动模块
  53. dvi_transmitter_top u_rgb2dvi_0(
  54. .pclk (pixel_clk),
  55. .pclk_x5 (pixel_clk_5x),
  56. .reset_n (sys_rst_n & clk_locked),
  57. .video_din (video_rgb),
  58. .video_hsync (video_hs),
  59. .video_vsync (video_vs),
  60. .video_de (video_de),
  61. .tmds_clk_p (tmds_clk_p),
  62. .tmds_clk_n (tmds_clk_n),
  63. .tmds_data_p (tmds_data_p),
  64. .tmds_data_n (tmds_data_n),
  65. .tmds_oen () //预留的端口,本次实验未用到
  66. );
  67. endmodule

参考内容

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/887910
推荐阅读
相关标签
  

闽ICP备14008679号