请问如何通过FPGA驱动VGA显示一个圆形

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问如何通过FPGA驱动VGA显示一个圆形相关的知识,希望对你有一定的参考价值。

利用圆的方程X^2+Y^2<=z^2.x是行扫描计数值与圆心的差,y是列扫描与圆心的差。这是你要的圆的半径。我给你贴一段程序,我自己写的12个圆环,分了四个象限,比较蠢。不分象限的话要用无符号数。
library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity vga_block isport (clk_40mhz:in std_logic; forming:in integer range 0 to 3; coulour:in integer range 0 to 2; h_or_f:in integer range 0 to 1;vga_out:out std_logic_vector(2 downto 0);hs1,vs1:out std_logic);end;architecture behave of vga_block issignal counter_hs:integer range 0 to 1055; --屏幕中行信号 HS 使用范围signal counter_vs:integer range 0 to 627; --屏幕中场信号 VS 使用范围signal hs,vs:std_logic:='1'; --行信号 hs 和场信号 vs 高电平signal rgb1,rgb2,rgb3:std_logic_vector(2 downto 0); --水平和垂直方向上表示 3 基色的中间变量signal coulour1,coulour2: std_logic_vector(2 downto 0);beginprocess(clk_40mhz) --40MHZ 触发在每行上逐点扫描beginif rising_edge(clk_40mhz) then if counter_hs>=1055 then counter_hs<=0;else counter_hs<=counter_hs+1;end if;end if;end process;process(counter_hs) --行消隐beginif counter_hs>=0 and counter_hs<128 thenhs<='0';elsehs<='1';end if;end process;process(hs)beginif falling_edge(hs) then --VGA 中行同步负脉冲有效if counter_vs>=627 thencounter_vs<=0;else counter_vs<=counter_vs+1; --垂直扫描end if;end if;end process;process(counter_vs) --场消隐beginif counter_vs>=0 and counter_vs<=3 thenvs<='0';elsevs<='1';end if;end process;
process(counter_hs,counter_vs)
if (counter_hs >=216 and counter_hs <=616) then if (counter_vs >=27 and counter_vs <=327) then if (((327-counter_vs)**2+(616-counter_hs)**2) <=90000 and ((327-counter_vs)**2+(616-counter_hs)**2) >=75625)or(((327-counter_vs)**2+(616-counter_hs)**2) < 62500 and ((327-counter_vs)**2+(616-counter_hs)**2) >=50625)or(((327-counter_vs)**2+(616-counter_hs)**2) < 40000 and ((327-counter_vs)**2+(616-counter_hs)**2) >=30625)or(((327-counter_vs)**2+(616-counter_hs)**2) < 22500 and ((327-counter_vs)**2+(616-counter_hs)**2) >=15625)or(((327-counter_vs)**2+(616-counter_hs)**2) < 10000 and ((327-counter_vs)**2+(616-counter_hs)**2) >=5625)or(((327-counter_vs)**2+(616-counter_hs)**2) < 2500 and ((327-counter_vs)**2+(616-counter_hs)**2) >=625) then rgb1 <=coulour1; elsif (((327-counter_vs)**2+(616-counter_hs)**2) < 75625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=62500)or(((327-counter_vs)**2+(616-counter_hs)**2) < 50625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=40000)or(((327-counter_vs)**2+(616-counter_hs)**2) < 30625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=22500)or(((327-counter_vs)**2+(616-counter_hs)**2) < 15625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=10000)or(((327-counter_vs)**2+(616-counter_hs)**2) < 5625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=2500)or(((327-counter_vs)**2+(616-counter_hs)**2) < 625 and ((327-counter_vs)**2+(616-counter_hs)**2) >=0) then rgb1 <=coulour2;else rgb1 <="000";end if; elsif (counter_vs >=327 and counter_vs <=627) then if (((counter_vs-327)**2+(616-counter_hs)**2) <=90000 and ((counter_vs-327)**2+(616-counter_hs)**2) >=75625)or(((counter_vs-327)**2+(616-counter_hs)**2) < 62500 and ((counter_vs-327)**2+(616-counter_hs)**2) >=50625)or(((counter_vs-327)**2+(616-counter_hs)**2) < 40000 and ((counter_vs-327)**2+(616-counter_hs)**2) >=30625)or(((counter_vs-327)**2+(616-counter_hs)**2) < 22500 and ((counter_vs-327)**2+(616-counter_hs)**2) >=15625)or(((counter_vs-327)**2+(616-counter_hs)**2) < 10000 and ((counter_vs-327)**2+(616-counter_hs)**2) >=5625)or(((counter_vs-327)**2+(616-counter_hs)**2) < 2500 and ((counter_vs-327)**2+(616-counter_hs)**2) >=625) then rgb1 <=coulour1; elsif (((counter_vs-327)**2+(616-counter_hs)**2) < 75625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=62500)or(((counter_vs-327)**2+(616-counter_hs)**2) < 50625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=40000)or(((counter_vs-327)**2+(616-counter_hs)**2) < 30625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=22500)or(((counter_vs-327)**2+(616-counter_hs)**2) < 15625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=10000)or(((counter_vs-327)**2+(616-counter_hs)**2) < 5625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=2500)or(((counter_vs-327)**2+(616-counter_hs)**2) < 625 and ((counter_vs-327)**2+(616-counter_hs)**2) >=0) then rgb1 <=coulour2;else rgb1 <="000";end if; end if; elsif (counter_hs >=616 and counter_hs <=1016) then if (counter_vs >=27 and counter_vs <=327) then if (((327-counter_vs)**2+(counter_hs-616)**2) <=90000 and ((327-counter_vs)**2+(counter_hs-616)**2) >=75625)or(((327-counter_vs)**2+(counter_hs-616)**2) < 62500 and ((327-counter_vs)**2+(counter_hs-616)**2) >=50625)or(((327-counter_vs)**2+(counter_hs-616)**2) < 40000 and ((327-counter_vs)**2+(counter_hs-616)**2) >=30625)or(((327-counter_vs)**2+(counter_hs-616)**2) < 22500 and ((327-counter_vs)**2+(counter_hs-616)**2) >=15625)or(((327-counter_vs)**2+(counter_hs-616)**2) < 10000 and ((327-counter_vs)**2+(counter_hs-616)**2) >=5625)or(((327-counter_vs)**2+(counter_hs-616)**2) < 2500 and ((327-counter_vs)**2+(counter_hs-616)**2) >=625) then rgb1 <=coulour1; elsif (((327-counter_vs)**2+(counter_hs-616)**2) < 75625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=62500)or(((327-counter_vs)**2+(counter_hs-616)**2) < 50625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=40000)or(((327-counter_vs)**2+(counter_hs-616)**2) < 30625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=22500)or(((327-counter_vs)**2+(counter_hs-616)**2) < 15625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=10000)or(((327-counter_vs)**2+(counter_hs-616)**2) < 5625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=2500)or(((327-counter_vs)**2+(counter_hs-616)**2) < 625 and ((327-counter_vs)**2+(counter_hs-616)**2) >=0) then rgb1 <=coulour2;else rgb1 <="000";end if; elsif (counter_vs >=327 and counter_vs <=627) then if (((counter_vs-327)**2+(counter_hs-616)**2) <=90000 and ((counter_vs-327)**2+(counter_hs-616)**2) >=75625)or(((counter_vs-327)**2+(counter_hs-616)**2) < 62500 and ((counter_vs-327)**2+(counter_hs-616)**2) >=50625)or(((counter_vs-327)**2+(counter_hs-616)**2) < 40000 and ((counter_vs-327)**2+(counter_hs-616)**2) >=30625)or(((counter_vs-327)**2+(counter_hs-616)**2) < 22500 and ((counter_vs-327)**2+(counter_hs-616)**2) >=15625)or(((counter_vs-327)**2+(counter_hs-616)**2) < 10000 and ((counter_vs-327)**2+(counter_hs-616)**2) >=5625)or(((counter_vs-327)**2+(counter_hs-616)**2) < 2500 and ((counter_vs-327)**2+(counter_hs-616)**2) >=625) then rgb1 <=coulour1; elsif (((counter_vs-327)**2+(counter_hs-616)**2) < 75625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=62500)or(((counter_vs-327)**2+(counter_hs-616)**2) < 50625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=40000)or(((counter_vs-327)**2+(counter_hs-616)**2) < 30625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=22500)or(((counter_vs-327)**2+(counter_hs-616)**2) < 15625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=10000)or(((counter_vs-327)**2+(counter_hs-616)**2) < 5625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=2500)or(((counter_vs-327)**2+(counter_hs-616)**2) < 625 and ((counter_vs-327)**2+(counter_hs-616)**2) >=0) then rgb1 <=coulour2;else rgb1 <="000";end if; end if; end if;--圆环
hs1 <= hs;vs1 <= vs;Vga_out<=rgb1 end process;end;
参考技术A VGA显示器是模拟的三基色输入,所以用FPGA驱动的话,首先要三个D/A转换器,当然如果只是显示一个圆形,FPGA用I/O口外搞几个电阻也是可以实现显示一个只有几种颜色的圆形。不知道你的具体要求,如果有实验箱什么的,一般上面应该有D/A转换器,而且有VGA接口,只要正确驱动就可以了。那你再具体描述一下你的要求?

FPGA的学习:HDMI显示器驱动设计与验证

HDMI的顶层模块设计如图所示:
在这里插入图片描述
其中包含了一个时钟产生电路,vga_pic模块,vga_ctrl模块,hdmi_ctrl模块。
各个模块的设计图如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
其中还要用到一个encode模块:
在这里插入图片描述
还要用到par_to_ser以及ddio_out模块:
在这里插入图片描述
在这里插入图片描述
接下来是encode模块的实现:

`timescale  1ns/1ns
module  encode
(
    input   wire            sys_clk     ,   //时钟信号
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   data_in     ,   //输入8bit待编码数据
    input   wire            c0          ,   //控制信号c0
    input   wire            c1          ,   //控制信号c1
    input   wire            de          ,   //使能信号

    output  reg     [9:0]   data_out        //输出编码后的10bit数据
);
//parameter define
parameter   DATA_OUT0   =   10'b1101010100,
            DATA_OUT1   =   10'b0010101011,
            DATA_OUT2   =   10'b0101010100,
            DATA_OUT3   =   10'b1010101011;

//wire  define
wire            condition_1 ;   //条件1
wire            condition_2 ;   //条件2
wire            condition_3 ;   //条件3
wire    [8:0]   q_m         ;   //第一阶段转换后的9bit数据

//reg   define
reg     [3:0]   data_in_n1  ;   //待编码数据中1的个数
reg     [7:0]   data_in_reg ;   //待编码数据打一拍
reg     [3:0]   q_m_n1      ;   //转换后9bit数据中1的个数
reg     [3:0]   q_m_n0      ;   //转换后9bit数据中0的个数
reg     [4:0]   cnt         ;   //视差计数器,0-1个数差别,最高位为符号位
reg             de_reg1     ;   //使能信号打一拍
reg             de_reg2     ;   //使能信号打两拍
reg             c0_reg1     ;   //控制信号c0打一拍
reg             c0_reg2     ;   //控制信号c0打两拍
reg             c1_reg1     ;   //控制信号c1打一拍
reg             c1_reg2     ;   //控制信号c1打两拍
reg     [8:0]   q_m_reg     ;   //q_m信号打一拍

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//data_in_n1:待编码数据中1的个数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in_n1  <=  4'd0;
    else
        data_in_n1  <=  data_in[0] + data_in[1] + data_in[2]
                        + data_in[3] + data_in[4] + data_in[5]
                        + data_in[6] + data_in[7];

//data_in_reg:待编码数据打一拍
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_in_reg <=  8'b0;
    else
        data_in_reg <=  data_in;

//condition_1:条件1
assign  condition_1 = ((data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4)
                        && (data_in_reg[0] == 1'b0)));

//q_m:第一阶段转换后的9bit数据
assign q_m[0] = data_in_reg[0];
assign q_m[1] = (condition_1) ? (q_m[0] ^~ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);
assign q_m[2] = (condition_1) ? (q_m[1] ^~ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);
assign q_m[3] = (condition_1) ? (q_m[2] ^~ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);
assign q_m[4] = (condition_1) ? (q_m[3] ^~ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);
assign q_m[5] = (condition_1) ? (q_m[4] ^~ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);
assign q_m[6] = (condition_1) ? (q_m[5] ^~ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);
assign q_m[7] = (condition_1) ? (q_m[6] ^~ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);
assign q_m[8] = (condition_1) ? 1'b0 : 1'b1;

//q_m_n1:转换后9bit数据中1的个数
//q_m_n0:转换后9bit数据中0的个数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            q_m_n1  <=  4'd0;
            q_m_n0  <=  4'd0;
        end
    else
        begin
            q_m_n1  <=  q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
            q_m_n0  <=  4'd8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
        end

//condition_2:条件2
assign  condition_2 = ((cnt == 5'd0) || (q_m_n1 == q_m_n0));

//condition_3:条件3
assign  condition_3 = (((~cnt[4] == 1'b1) && (q_m_n1 > q_m_n0))
                        || ((cnt[4] == 1'b1) && (q_m_n0 > q_m_n1)));

//数据打拍,为了各数据同步
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            de_reg1 <=  1'b0;
            de_reg2 <=  1'b0;
            c0_reg1 <=  1'b0;
            c0_reg2 <=  1'b0;
            c1_reg1 <=  1'b0;
            c1_reg2 <=  1'b0;
            q_m_reg <=  9'b0;
        end
    else
        begin
            de_reg1 <=  de;
            de_reg2 <=  de_reg1;
            c0_reg1 <=  c0;
            c0_reg2 <=  c0_reg1;
            c1_reg1 <=  c1;
            c1_reg2 <=  c1_reg1;
            q_m_reg <=  q_m;
        end

//data_out:输出编码后的10bit数据
//cnt:视差计数器,0-1个数差别,最高位为符号位
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            data_out    <=  10'b0;
            cnt         <=  5'b0;
        end
    else
        begin
            if(de_reg2 == 1'b1)
                begin
                    if(condition_2 == 1'b1)
                        begin
                            data_out[9]     <=  ~q_m_reg[8]; 
                            data_out[8]     <=  q_m_reg[8]; 
                            data_out[7:0]   <=  (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];
                            cnt <=  (~q_m_reg[8]) ? (cnt + q_m_n0 - q_m_n1) : (cnt + q_m_n1 - q_m_n0);
                        end
                    else
                        begin
                            if(condition_3 == 1'b1)
                                begin
                                    data_out[9]     <= 1'b1;
                                    data_out[8]     <= q_m_reg[8];
                                    data_out[7:0]   <= ~q_m_reg[7:0];
                                    cnt <=  cnt + {q_m_reg[8], 1'b0} + (q_m_n0 - q_m_n1);
                                end
                            else
                                begin
                                    data_out[9]     <= 1'b0;
                                    data_out[8]     <= q_m_reg[8];
                                    data_out[7:0]   <= q_m_reg[7:0];
                                    cnt <=  cnt - {~q_m_reg[8], 1'b0} + (q_m_n1 - q_m_n0);
                                end
                            
                        end
                end
            else
                begin
                    case    ({c1_reg2, c0_reg2})
                        2'b00:  data_out <= DATA_OUT0;
                        2'b01:  data_out <= DATA_OUT1;
                        2'b10:  data_out <= DATA_OUT2;
                        default:data_out <= DATA_OUT3;
                    endcase
                    cnt <=  5'b0;
                end
        end

endmodule

par_to_ser模块的实现如下:

`timescale  1ns/1ns
module par_to_ser
(
    input   wire            clk_5x      ,   //输入系统时钟
    input   wire    [9:0]   par_data    ,   //输入并行数据

    output  wire            ser_data_p  ,   //输出串行差分数据
    output  wire            ser_data_n      //输出串行差分数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire    [4:0]   data_rise = {par_data[8],par_data[6],
                            par_data[4],par_data[2],par_data[0]};
wire    [4:0]   data_fall = {par_data[9],par_data[7],
                            par_data[5],par_data[3],par_data[1]};

//reg   define
reg     [4:0]   data_rise_s = 0;
reg     [4:0]   data_fall_s = 0;
reg     [2:0]   cnt = 0;


always @ (posedge clk_5x)
    begin
        cnt <= (cnt[2]) ? 3'd0 : cnt + 3'd1;
        data_rise_s  <= cnt[2] ? data_rise : data_rise_s[4:1];
        data_fall_s  <= cnt[2] ? data_fall : data_fall_s[4:1];

    end

//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- ddio_out_inst0 -------------
ddio_out    ddio_out_inst0
(
    .datain_h   (data_rise_s[0] ),
    .datain_l   (data_fall_s[0] ),
    .outclock   (~clk_5x        ),
    .dataout    (ser_data_p     )
);

//------------- ddio_out_inst1 -------------
ddio_out    ddio_out_inst1
(
    .datain_h   (~data_rise_s[0]),
    .datain_l   (~data_fall_s[0]),
    .outclock   (~clk_5x        ),
    .dataout    (ser_data_n     )
);

endmodule

HDMI控制模块如下:

`timescale  1ns/1ns
module  hdmi_ctrl
(
    input   wire            clk_1x      ,   //输入系统时钟
    input   wire            clk_5x      ,   //输入5倍系统时钟
    input   wire            sys_rst_n   ,   //复位信号,低有效
    input   wire    [7:0]   rgb_blue    ,   //蓝色分量
    input   wire    [7:0]   rgb_green   ,   //绿色分量
    input   wire    [7:0]   rgb_red     ,   //红色分量
    input   wire            hsync       ,   //行同步信号
    input   wire            vsync       ,   //场同步信号
    input   wire            de          ,   //使能信号

    output  wire            hdmi_clk_p  ,
    output  wire            hdmi_clk_n  ,   //时钟差分信号
    output  wire            hdmi_r_p    ,
    output  wire            hdmi_r_n    ,   //红色分量差分信号
    output  wire            hdmi_g_p    ,
    output  wire            hdmi_g_n    ,   //绿色分量差分信号
    output  wire            hdmi_b_p    ,
    output  wire            hdmi_b_n        //蓝色分量差分信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
wire    [9:0]   red     ;   //8b转10b后的红色分量
wire    [9:0]   green   ;   //8b转10b后的绿色分量
wire    [9:0]   blue    ;   //8b转10b后的蓝色分量

//********************************************************************//
//**************************** Instantiate ***************************//
//********************************************************************//
//------------- encode_inst0 -------------
encode  encode_inst0
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_blue   ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (blue       )
);

//------------- encode_inst1 -------------
encode  encode_inst1
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_green  ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (green      )
);

//------------- encode_inst2 -------------
encode  encode_inst2
(
    .sys_clk    (clk_1x     ),
    .sys_rst_n  (sys_rst_n  ),
    .data_in    (rgb_red    ),
    .c0         (hsync      ),
    .c1         (vsync      ),
    .de         (de         ),
    .data_out   (red        )
);

//------------- par_to_ser_inst0 -------------
par_to_ser  par_to_ser_inst0
(
    .clk_5x      (clk_5x    ),
    .par_data    (blue      ),

    .ser_data_p  (hdmi_b_p  ),
    .ser_data_n  (hdmi_b_n  )
);

//------------- par_to_ser_inst1 -------------
par_to_ser  par_to_ser_inst1
(
    .clk_5x      (clk_5x    ),
    .par_data    (green     ),

    .ser_data_p  (hdmi_g_p  ),
    .ser_data_n  (hdmi_g_n  )
);

//------------- par_to_ser_inst2 -------------
par_to_ser  par_to_ser_inst2
(
    .clk_5x      (clk_5x    ),
    .par_data    (red       ),

    .ser_data_p  (hdmi_r_p  ),
    .ser_data_n  (hdmi_r_n  )
);

//------------- par_to_ser_inst3 -------------
par_to_ser  par_to_ser_inst3
(
    .clk_5x      (clk_5x        ),
    .par_data    (10'b1111100000),

    .ser_data_p  (hdmi_clk_p    ),
    .ser_data_n  (hdmi_clk_n    )
);

endmodule

vga_ctrl和vga_pic模块分别如下:

`timescale  1ns/1ns
module  vga_ctrl
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [15:0]  pix_data    ,   //输入像素点色彩信息

    output  wire    [11:0]  pix_x       ,   //输出VGA有效显示区域像素点X轴坐标
    output  wire    [11:0]  pix_y       ,   //输出VGA有效显示区域像素点Y轴坐标
    output  wire            hsync       ,   //输出行同步信号
    output  wire            vsync       ,   //输出场同步信号
    output  wire            rgb_valid   ,
    output  wire    [15:0]  rgb             //输出像素点色彩信息
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter H_SYNC    =   10'd96  ,   //行同步
          H_BACK    =   10'd40  ,   //行时序后沿
          H_LEFT    =   10'd8   ,   //行时序左边框
          H_VALID   =   10'd640 ,   //行有效数据
          H_RIGHT   =   10'd8   ,   //行时序右边框
          H_FRONT   =   10'd8   ,   //行时序前沿
          H_TOTAL   =   10'd800 ;   //行扫描周期
parameter V_SYNC    =   10'd2   ,   //场同步
          V_BACK    =   10'd25  ,   //场时序后沿
          V_TOP     =   10'd8   ,   //场时序上边框
          V_VALID   =   10'd480 ,   //场有效数据
          V_BOTTOM  =   10'd8   ,   //场时序下边框
          V_FRONT   =   10'd2   ,   //场时序前沿
          V_TOTAL   =   10'd525 ;   //场扫描周期

//wire  define
wire            pix_data_req    ;   //像素点色彩信息请求信号

//reg   define
reg     [11:0]  cnt_h           ;   //行同步信号计数器
reg     [11:0]  cnt_v           ;   //场同步信号计数器

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_h:行同步信号计数器
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h   <=  12'd0   ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_h   <=  12'd0   ;
    else
        cnt_h   <=  cnt_h + 1'd1   ;

//hsync:行同步信号
assign  hsync = (cnt_h  <=  H_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//cnt_v:场同步信号计数器
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v   <=  12'd0 ;
    else    if((cnt_v == V_TOTAL - 1'd1) &&  (cnt_h == H_TOTAL-1'd1))
        cnt_v   <=  12'd0 ;
    else    if(cnt_h == H_TOTAL - 1'd1)
        cnt_v   <=  cnt_v + 1'd1 ;
    else
        cnt_v   <=  cnt_v ;

//vsync:场同步信号
assign  vsync = (cnt_v  <=  V_SYNC - 1'd1) ? 1'b1 : 1'b0  ;

//rgb_valid:VGA有效显示区域
assign  rgb_valid = (((cnt_h >= H_SYNC + H_BACK + H_LEFT)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_data_req:像素点色彩信息请求信号,超前rgb_valid信号一个时钟周期
assign  pix_data_req = (((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)
                    && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1))
                    &&((cnt_v >= V_SYNC + V_BACK + V_TOP)
                    && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID)))
                    ? 1'b1 : 1'b0;

//pix_x,pix_y:VGA有效显示区域像素点坐标
assign  pix_x = (pix_data_req == 1'b1)
                ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 12'hfff;
assign  pix_y = (pix_data_req == 1'b1)
                ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 12'hfff;

//rgb:输出像素点色彩信息
assign  rgb = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;

endmodule
`timescale  1ns/1ns
module  vga_pic
(
    input   wire            vga_clk     ,   //输入工作时钟,频率25MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效
    input   wire    [11:0]  pix_x       ,   //输入VGA有效显示区域像素点X轴坐标
    input   wire    [11:0]  pix_y       ,   //输入VGA有效显示区域像素点Y轴坐标

    output  reg     [15:0]  pix_data        //输出像素点色彩信息
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   H_VALID =   12'd640 ,   //行有效数据
            V_VALID =   12'd480 ;   //场有效数据

parameter   RED     =   16'hF800,   //红色
            ORANGE  =   16'hFC00,   //橙色
            YELLOW  =   16'hFFE0,   //黄色
            GREEN   =   16'h07E0,   //绿色
            CYAN    =   16'h07FF,   //青色
            BLUE    =   16'h001F,   //蓝色
            PURPPLE =   16'hF81F,   //紫色
            BLACK   =   16'h0000,   //黑色
            WHITE   =   16'hFFFF,   //白色
            GRAY    =   16'hD69A;   //灰色

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <= 16'd0;
    else    if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
        pix_data    <=  ORANGE;
    else    if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
        pix_data    <=  YELLOW;
    else    if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
        pix_data    <=  CYAN;
    else    if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
        pix_data    <=  PURPPLE;
    else    if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
        pix_data    <=  WHITE;
    else    if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
        pix_data    <=  GRAY;
    else
        pix_data    <=  BLACK;

endmodule

最后是主程序的实现:

`timescale  1ns/1ns
module  hdmi_colorbar
(
    input   wire            sys_clk     ,   //输入工作时钟,频率50MHz
    input   wire            sys_rst_n   ,   //输入复位信号,低电平有效

    output  wire            ddc_scl     ,
    output  wire            ddc_sda     ,
    output  wire            tmds_clk_p  ,
    output  wire            tmds_clk_n  ,   //HDMI时钟差分信号
    output  wire    [2:0]   tmds_data_p ,
    output  wire    [2:0]   tmds_data_n     //HDMI图像差分信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire            vga_clk ;   //VGA工作时钟,频率25MHz
wire            clk_5x  ;
wire            locked  ;   //PLL locked信号
wire            rst_n   ;   //VGA模块复位信号
wire    [11:0]  pix_x   ;   //VGA有效显示区域X轴坐标
wire    [11:0]  pix_y   ;   //VGA有效显示区域Y轴坐标
wire    [15:0]  pix_data;   //VGA像素点色彩信息
wire            hsync   ;   //输出行同步信号
wire            vsync   ;   //输出场同步信号
wire    [15:0]  rgb     ;   //输出像素信息
wire            rgb_valid;   

//rst_n:VGA模块复位信号
assign  rst_n   = (sys_rst_n & locked);   
assign  ddc_scl = 1'b1;    
assign  ddc_sda = 1'b1;   

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- clk_gen_inst -------------
clk_gen clk_gen_inst
(
    .areset     (~sys_rst_n ),  //输入复位信号,高电平有效,1bit
    .inclk0     (sys_clk    ),  //输入50MHz晶振时钟,1bit

    .c0         (vga_clk    ),  //输出VGA工作时钟,频率25Mhz,1bit
    .c1         (clk_5x     ),
    .locked     (locked     )   //输出pll locked信号,1bit
);

//------------- vga_ctrl_inst -------------
vga_ctrl  vga_ctrl_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_data   (pix_data   ),  //输入像素点色彩信息,16bit

    .pix_x      (pix_x      ),  //输出VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输出VGA有效显示区域像素点Y轴坐标,10bit
    .hsync      (hsync      ),  //输出行同步信号,1bit
    .vsync      (vsync      ),  //输出场同步信号,1bit
    .rgb_valid  (rgb_valid  ),
    .rgb        (rgb        )   //输出像素点色彩信息,16bit
);

//------------- vga_pic_inst -------------
vga_pic vga_pic_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_x      (pix_x      ),  //输入VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输入VGA有效显示区域像素点Y轴坐标,10bit

    .pix_data   (pix_data   )   //输出像素点色彩信息,16bit

);

//------------- hdmi_ctrl_inst -------------
hdmi_ctrl   hdmi_ctrl_inst
(
    .clk_1x      (vga_clk           ),   //输入系统时钟
    .clk_5x      (clk_5x            ),   //输入5倍系统时钟
    .sys_rst_n   (rst_n             ),   //复位信号,低有效
    .rgb_blue    ({rgb[4:0],3'b0}   ),   //蓝色分量
    .rgb_green   ({rgb[10:5],2'b0}  ),   //绿色分量
    .rgb_red     ({rgb[15:11],3'b0} ),   //红色分量
    .hsync       (hsync             ),   //行同步信号
    .vsync       (vsync             ),   //场同步信号
    .de          (rgb_valid         ),   //使能信号
    .hdmi_clk_p  (tmds_clk_p        ),
    .hdmi_clk_n  (tmds_clk_n        ),   //时钟差分信号
    .hdmi_r_p    (tmds_data_p[2]    ),
    .hdmi_r_n    (tmds_data_n[2]    ),   //红色分量差分信号
    .hdmi_g_p    (tmds_data_p[1]    ),
    .hdmi_g_n    (tmds_data_n[1]    ),   //绿色分量差分信号
    .hdmi_b_p    (tmds_data_p[0]    ),
    .hdmi_b_n    (tmds_data_n[0]    )    //蓝色分量差分信号
);

endmodule

进行仿真:

`timescale  1ns/1ns
module  tb_hdmi_colorbar();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire  define
wire            ddc_scl     ;
wire            ddc_sda     ;
wire            tmds_clk_p  ;
wire            tmds_clk_n  ;
wire    [2:0]   tmds_data_p ;
wire    [2:0]   tmds_data_n ;

//reg   define
reg             sys_clk     ;
reg             sys_rst_n   ;

//********************************************************************//
//**************************** Clk And Rst ***************************//
//********************************************************************//

//sys_clk,sys_rst_n初始赋值
initial
    begin
        sys_clk     =   1'b1;
        sys_rst_n   <=  1'b0;
        #200
        sys_rst_n   <=  1'b1;
    end

//sys_clk:产生时钟
always  #10 sys_clk = ~sys_clk  ;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//------------- hdmi_colorbar_inst -------------
hdmi_colorbar   hdmi_colorbar_inst
(
    .sys_clk     (sys_clk    ),   //输入工作时钟,频率50MHz
    .sys_rst_n   (sys_rst_n  ),   //输入复位信号,低电平有效
                  
    .ddc_scl     (ddc_scl    ),
    .ddc_sda     (ddc_sda    ),
    .tmds_clk_p  (tmds_clk_p ),
    .tmds_clk_n  (tmds_clk_n ),   //HDMI时钟差分信号
    .tmds_data_p (tmds_data_p),
    .tmds_data_n (tmds_data_n)    //HDMI图像差分信号
);

endmodule

以上是关于请问如何通过FPGA驱动VGA显示一个圆形的主要内容,如果未能解决你的问题,请参考以下文章

基于FPGA驱动VGA显示图片的小问题

FPGA驱动OV5640用VGA显示画面上有很多彩色条纹

使用FPGA开发板驱动VGA显示器(未完待续)

FPGA VGA时序的理解

VGA驱动时序说明

FPGA的学习:HDMI显示器驱动设计与验证