«

»

Aug 05

FPGA NES: VGA (Part 1)

Any good video game requires one very fundamental feature: video. The nanoboard includes a VGA port and seeing as I don’t know anything about the VGA protocol it seems like the perfect place to start.  The nanoboard also has a built in touch-screen, however I feel like that would be easier to implement and will be covered in a later post.  My goal for this section is to display the “SMPTE color bars” on a standard computer monitor.

Video Graphics Array (VGA) is a graphical standard dating back to the 1980′s.  The defined VGA resolution is 640×480, meaning that each row in the display contains 640 pixels and each column contains 480 pixels.  A second way to look at this is as a display with 480 horizontal rows, each row containing 640 pixels.  This is a convenient viewpoint to take due to the method displays use to generate images. A simplified animation of the display process is shown below.

VGA Animation

Enoch Hwang from  has written a nice article about VGA and creating a VGA controller based on two 10-bit binary counters.  The FPGA design described here is based off of the circuit and timings provided in his article.  This version of the VGA controller works at a fixed resolution of 640×480 and displays a solid color across the entire screen.  This VGA controller is broken up into two basic parts: a timing circuit and a color generator.  The timing circuit is fed a 25MHz clock signal and generates the necessary H Sync and V Sync signals along with the state of the currently active pixel.  These signals are in turn used by the color generator to provide the required data to the DAC that drives the nanoboard’s VGA port.

The 6-bit RGB color value is selected using the nanoboard’s DIP switch.  The binary color commands generated from the switch configuration are displayed on the user LED’s.  The code for the clock and color circuits as well as the schematic linking them to the nanoboard are all provided below.  This example has been tested on an LCD monitor and is successful for displaying solid colors. There may be underlying timing problems masked by the simplicity of this example. These should be found and addressed in the more complex examples that will follow.

 

VGAClock.vhd


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Library IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_Unsigned.all;

ENTITY VGAClock is
    Port(
        Clock, Enable, Reset: in STD_LOGIC;
        HSync, VSync, rowActive, columnActive, pixelActive : out STD_LOGIC;
        row,column : out STD_LOGIC_VECTOR(0 to 9)
    );
end VGAClock;

Architecture structure of VGAClock is

    signal HSync_sig : STD_LOGIC := '1';
    signal VSync_sig : STD_LOGIC := '1';
    signal row_sig : STD_LOGIC_VECTOR(0 to 9) := "0000000000";
    signal column_sig : STD_LOGIC_VECTOR(0 to 9) := "0000000000";

    signal rowActive_sig : STD_LOGIC;
    signal columnActive_sig : STD_LOGIC;
    signal pixelActive_sig : STD_LOGIC;

    constant pixelCount  : integer := 640;
    constant HSyncTime   : integer := 95;
    constant HLeftBlank  : integer := 23;
    constant HRightBlank : integer := 47;

    constant VSyncTime   : integer := 2;
    constant VBlankLeft  : integer := 14;
    constant rowCount    : integer := 480;
    constant VBlankRight : integer := 32;

begin process(Clock, Reset)
    begin
        if (Reset = '1') then
            HSync_sig <= '1';
            VSync_sig <= '1';
            column_sig <= "0000000000";
            row_sig <= "0000000000";
            pixelActive_sig <= '0';
            rowActive_sig <= '1';
            columnActive_sig <= '0';
        elsif (Clock'event and Clock = '1') then
            --Done Pixels, enter HBlankLeft
            if(column_sig = (pixelCount-1)) then
                rowActive_sig <= '0';
                column_sig <= column_sig + 1;
            --Done HBlankLeft, Send HSync Pulse
            elsif(column_sig = (pixelCount+HLeftBlank-1)) then
                HSync_sig <= '0';
                column_sig <= column_sig + 1;
            --HBlankRight
            elsif(column_sig = (pixelCount+HLeftBlank+HSyncTime-1)) then
                HSync_sig <= '1';
                row_sig <= row_sig + 1;
                column_sig <= column_sig + 1;
            -- Reset counter and start next line
            elsif(column_sig = (pixelCount+HLeftBlank+HSyncTime+HRightBlank-1)) then
                column_sig <= "0000000000";
                rowActive_sig <= '1';
            else
                column_sig <= column_sig + 1;
            end if;

            if(row_sig = rowCount-1) then
                columnActive_sig <= '0';
            elsif(row_sig = (rowCount + VBlankLeft-1)) then
                VSync_sig <= '0';
            elsif(row_sig = (rowCount + VBlankLeft + VSyncTime-1)) then
                VSync_sig <= '1';
            elsif(row_sig = (rowCount + VBlankLeft + VSyncTime + VBlankRight-1)) then
                row_sig <= "0000000000";
                columnActive_sig <= '1';
            end if;
        end if;


        if (rowActive_sig = '1' and columnActive_sig = '1') then
            pixelActive_sig<='1';
        else
            pixelActive_sig<='0';
        end if;
    end process;
    HSync <= HSync_sig;
    VSync <= VSync_sig;
    column <= column_sig;
    row <= row_sig;
    pixelActive <= pixelActive_sig;
    rowActive <= rowActive_sig;
    columnActive <= columnActive_sig;
end structure;

VGAColor.vhd


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Library IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_Unsigned.all;

ENTITY VGAColor is
    Port(
        Clock,Reset : in STD_LOGIC;
        pixel : in STD_LOGIC_VECTOR(7 downto 0);
        pixelActive : in STD_LOGIC;
        Red, Green, Blue : out STD_LOGIC_VECTOR(7 downto 0)
    );
end VGAColor;

Architecture structure of VGAColor is
    signal Red_sig,Green_sig,Blue_sig : STD_LOGIC_VECTOR(7 downto 0);


    constant pixelCount  : integer := 640;


begin process(Clock, Reset)
    begin
        if (Reset = '1') then
            Blue_sig <= "00000000";
            Red_sig <= "00000000";
            Green_sig <= "00000000";
        elsif (Clock'event and Clock = '1') then
            if pixelActive = '1' then
                if ((pixel(0) = '1') and (pixel(1) = '1')) then
                    Blue_sig <= "11111111";
                elsif pixel(0) = '1' then
                    Blue_sig <= "01010101";
                elsif pixel(1) = '1' then
                    Blue_sig <= "10101010";
                else
                    Blue_sig <= "00000000";
                end if;

                if ((pixel(2) = '1') and (pixel(3) = '1')) then
                    Green_sig <= "11111111";
                elsif pixel(2) = '1' then
                    Green_sig <= "01010101";
                elsif pixel(3) = '1' then
                    Green_sig <= "10101010";
                else
                    Green_sig <= "00000000";
                end if;

                if ((pixel(4) = '1') and (pixel(5) = '1')) then
                    Red_sig <= "11111111";
                elsif pixel(4) = '1' then
                    Red_sig <= "01010101";
                elsif pixel(5) = '1' then
                    Red_sig <= "10101010";
                else
                    Red_sig <= "00000000";
                end if;

            else
                Blue_sig <= "00000000";
                Red_sig <= "00000000";
                Green_sig <= "00000000";
            end if;
        end if;
    end process;

    Red <= Red_sig;
    Green <= Green_sig;
    Blue <= Blue_sig;

end structure;

Sources:

VGA Controller

File Downloads:

SimpleVGA_Altium (537)

 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>