For some Electronics students a bare metal FPGA can be quite boring, knowing that a Microcontroller can do a lot better job in many situation. However, that doesn't mean that FPGA is boring itself! For instance, we can store an information about an imagine inside the Memory of FPGA and then put the image through the VGA cable onto the LCD display.
First things first, for the project I used Diligent Basys 2 board, which now is almost obsolete. I suggest you using some newer FPGA for a better image quality, larger number of connections and larger amount of memory as the image that I put here used up about 99% of the chip!
I used Verilog programming language and one of the software packages from Xilinx (Any other should do the job as well). Digilent Adept 2 software was used to upload the bit file from Verilog to the board.
One more interesting thing to point out - you probably noticed how distorted the image on the screen is. This is because the board is really old and it uses an awful clock! I currently don't have an external clock, which can be put instead, but if you have one (or have a newer board), you will most likely get rid of this effect.
More about the board:
Step 1: Choosing the Right Picture
I noticed that the largest picture that you can put on Basys 2 board was about 85x85 pixel size . The background of the picture is preferably white for the chip to optimise the connections. If you don't have any picture of such size size you can always use the ones provided by me (GIMP LOGO or Mickey Mouse).
Otherwise you can use Photoshop, Gimp (for free) or any other Image editor to crop the image, separate the image from its background by making the background transparent and scale the picture down to around 80x80 pixels. Export the image as .jpg or .png format.
Step 2: Image Processing
We need to extract raw pixel data from the image, then compress that and the reconstruct in the FPGA through VGA cable. For this I used Matlab, but you can use python as well.
An important thing to mention is that the a pixel has 3 components: RED, GREEN and BLUE and thus is called RBG. Meaning that any other colour (orange, brown...) can be created using these 3 Base colours.
Usually there is 3 bytes per pixel dedicated for colours (one Byte per Base colour). For VGA all 3 colours are stored in only one Byte thus we have to somehow compress three Bytes into one. From the data sheet you will see that the first 3 bits (from the least significant bit / from the most right position) are RED, then 3 bit for GREEN and the final 2 bits for BLUE colours.
Firstly use Matlab function imread ('name.png'); which reads the image and stores its pixel information. Then we can extract R, G & B components into separate variables and then convert that to double format for further conversions. For the RED and GREEN components to translate 1 Byte (8 bits) into 3 bits we can raise the decimal value of the component to 3/8 (mathematically, rise 3 bits of total bit number root, which is 8..). For BLUE component this number is 1/4 (or 2/8, which is the same). Translate the result of doable to uint8 (integer of 8 bits) which will also round the result up. Some of the rounded values might get a little bigger than expected (due to rounding to ceiling), thus minus one for the bits to not overflow. Then we need to combine all 3 colours back together into a single uint8 value. This is done by shifting Green 3 times, Blue 6 times and then adding Red, Green & Blue together. Finally need to store everything in a .list file in HEX format. (see Matlab file).
After running the Matlab script the data will be stored in 'Mickey.list'. Before quitting Matlab, read the size of the variable COLOUR (right or left side of Matlab window where all the variables are stored) because you will need to enter this value in Verilog code as to how many lines of file to read (For Mickey.jpg it is 6960 x 2 char, thus note down 6960). I also provide the gimp.txt and gimp.list for those you don't want to do the Matlab part.
Step 3: Verilog Code
Finally we can write the Verilog code. Well, actually all the code is already prewritten for you, so you can analyse it and test it out.
Counter.v, PixCounter.v & VGAInterface.v files are used solely to construct the VGA communication and all the fun part of the project happens inside MainActivity.v. At the bottom of the file I commented out an example code of how to make a non moving image (which is easier), however for the main use I made the picture to move as in the video (will post this weekend).
All the external connection from the board are in MainActivity.ucf.