VGA Bitmap - red-bote/VHDL_Demos GitHub Wiki

This presentation uses the example from rams_20c.vhd to load image data from a .bmp file and initialize the memory array of the BRAM.

Image File Preparation

The .bmp file is converted to the data-file format, which is a 32-bit binary series represented as readable ASCII.

See previous presentations of VGA sync controller and loading image data from external file.

A bitmap file can be encoded as 32-bit RGBx (24-bits + 8-bits alpha channel). Normally the image attributes and size are extracted from the bitmap header, but to simplify things the header is ignored. Header size can be expected 70 bytes. To confirm the example bitmap of 32x16 RGBx using shell commands:

$ ls -l rgb.bmp 
-rwxrwxr-x 1 xubuntu xubuntu 2118 Dec  4 19:34 rgb.bmp
$ file rgb.bmp 
rgb.bmp: PC bitmap, Adobe Photoshop with alpha channel mask, 32 x 16 x 32
$ echo 2118-32*16*4 | bc -l 
70

If imagemagick is installed, the identify command is available to provide information about the file.

The following command reads the bitmap file, skips the header and dumps the image data to the rams data file in the expected format:

dd if=rgb.bmp bs=1 skip=70 | xxd -b -c 4  | cut -c11-45 | sed 's/\ //g' \
                             > vga_bitmap.srcs/sources_1/imports/rams/rams_20c.data

$ head  vga_bitmap.srcs/sources_1/imports/rams/rams_20c.data
11111111111111111111111100000000
11111111111111111111111100000000
11111111111111111111111100000000
11111111111111111111111100000000
00000000000000001111111100000000
00000000000000001111111100000000
00000000000000001111111100000000
00000000000000001111111100000000
00000000000000001111111100000000
00000000000000001111111100000000

Note: requires Reset Behavioral Simulation or Reset Synthesis Run in order to completely "rebuild" the circuit so that alterations to the external data are propagated into the data array of the RAM.

Pixel Generator

The hw_image_generator.vhd file from the VGA tutorial is modified with a crude address generator that interfaces with the data ROM and displays the image tile in a fixed location.

  • pixel_clk added as input port to entity
  • pix_address and pix_data signals added to architecture
  • p_pix_address process provides the address to clock data out of the RAM
  • u_vram added to generate pix_data
  • red green and blue signals from pix_data

Note pix_address is 6-bits which is the size of the ROM (64-bytes) so only 2 lines of the 32x16 pixel image are stored.

ENTITY hw_image_generator IS
  GENERIC(
    pixels_y :  INTEGER := 16;   --vertical extent of image
    pixels_x :  INTEGER := 16);  --horizontal extent of image
  PORT(
    pixel_clk :  IN   STD_LOGIC;
.
.
.
END hw_image_generator;
ARCHITECTURE behavior OF hw_image_generator IS

  signal pix_address : unsigned(5 downto 0) := (others => '0'); -- initialize for simulation
  signal pix_data : std_logic_vector(31 downto 0);

  signal column_r : unsigned(9 downto 0);
BEGIN

  p_pix_address : process(pixel_clk, row, column)
  begin
    if rising_edge(pixel_clk) then
      if(row < pixels_y AND column < pixels_x) THEN
        pix_address <= pix_address + 1;
      elsif (row >= pixels_y AND column >= pixels_x) OR (row = 0 AND column = 0) then
        pix_address <= (others => '0');
      end if;

      column_r <= to_unsigned(column, column_r'length);

    end if;
  end process p_pix_address;

  u_vram : entity work.rams_20c
    port map(
         clk => pixel_clk,
         we => '0',
         addr => std_logic_vector(pix_address),
         din => (others => '0'),
         dout => pix_data);
         
  PROCESS(disp_ena, row, column_r, pix_data)
  BEGIN
    IF(disp_ena = '1') THEN        --display time
--      IF(row < pixels_y AND column < pixels_x) THEN
      IF(row < pixels_y AND column_r < pixels_x) THEN
        red <= pix_data(15 downto 8);
        green  <= pix_data(23 downto 16);
        blue <= pix_data(31 downto 24);
      ELSE
        red <= (OTHERS => '0');
        green  <= (OTHERS => '0');
        blue <= (OTHERS => '0');
      END IF;
    ELSE                           --blanking time
      red <= (OTHERS => '0');
      green <= (OTHERS => '0');
      blue <= (OTHERS => '0');
    END IF;
  
  END PROCESS;
END behavior;

Simulation and Timing Analysis

Test image size 16 pixels wide with columns colored for identification in simulation trace.

Simulation trace shows relationship of data to the column address. Data from ROM is delayed 1 clock cycle relative to expect column for display.

"color-coded test image"

Registered column_r delays the column signal by 1 clock.

Source code and project files

Next