-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Our goal was to replicate an Etch-A-Sketch using an Altera II DE2 FPGA board. The FPGA will output signals to a VGA monitor from an SP/2 keyboard.
Items used to create this project:
- Altera II DE2-115 board and power cable
- VGA cable and monitor
- SP/2 keyboard
- USB cable for uploading to board
- Quartus II software
To use our Etch-a-Sketch: Use the keyboard keys W, A, S, D, Q, E, Z, and C to move the drawing pixel up, left, down, right, , up and left, up and right, down and left, down and write respectively. Pressing the spacebar will clear the screen using the color that the drawing pixel currently is. This effectively sets the background color to the color of the drawing pixel. The keys R, G, and B, will change the colors of the drawing pixel to red, green, or blue, respectively. Turning all three on creates a black pixel, or turning all three off will create a white pixel. You can find the drawing pixel because it will be blinking between the color of the drawing pixel and the background color. If the drawing pixel is the same color as the background, the drawing pixel will blink grey.
https://www.youtube.com/watch?v=0iur8l7tg_s&feature=youtu.be
An Etch-a-Sketch is a popular mechanical toy that has two knobs controlled by a user. These knobs scrape a stylus across a glass screen coated in aluminum dust, drawing a dark line in its wake. By shaking the entire device, the aluminum powder is redistributed across the screen and any image is “erased”. Essentially, an Etch-a-Sketch is a mechanical drawing tool that creates one, continuous contour line.
In order to recreate an Etch-a-Sketch with an FPGA board, we first had to determine what it is that we needed our system to do. We defined the following capabilities:
-
Output a display on a VGA monitor. The display will consist of a solid background and a pixel that draws a line.
-
By using the W, S, A, D, Q, E, Z, and C keys, the user can specify which direction they would like the pixel to move, effectively drawing a line as it moves in that direction.
-
Additional functionality is included by allowing the user to change colors of their pixel with the R, B, G keys. Pressing space bar will clear the screen and simultaneously set the color of the background to whatever values of R, B, G are selected.
A 640 x 480 VGA monitor acts as a grid of pixels that are independently set to triplet values of three fundamental colors: red, green, and blue, where each color intensity is represented by a 8-bit value (0-255). The first pixel activated is at the top-left, where x = 0 and y = 0, and then the monitor moves from left to right across the screen activating each pixel serially. After x = 640, the vga starts horizontal front porch of the vga until x = 655. At x = 655 the horizontal sync starts then from x = 747 to x = 793 the horizontal back porch is going on. After x = 793, x is set back to 0 and y is incremented by 1. This goes on until y = 480 which is where the vertical front porch starts. From y = 490 to 492 the vertical sync occurs then the vertical back porch goes on until y = 525. After y = 525 and x = 793 both x and y are set back to 0 and the process starts all over again. This cycle of front porch, sync and back porch is important so that the screen knows when to set its own x and y positions back to 0. If you want to use a different resolution it is important that you change the front porch, sync and back porch values as well as the clock speed. For the 640 x 480 resolution, we down scaled our FPGA's 50 MHz clock down to 25 MHz. The VGA module provides xCount and yCount which allows for the rest of the project to know which pixel is being draw to the screen at any given time.
We referenced the Instructables project "Snake" on an FPGA to interface with our VGA monitor.
The VGA monitor and adapter do not have built-in memory, therefore the data to activate pixels on the screen will not be stored. To achieve a stable image, we used a SRAM to write and update this information and continuously send it back to the VGA monitor. xCount
and yCount
are the x and y pixels of the VGA, and the xy-coordinates of the cursor pixel are writex
and writey
.
The first requirement we needed to include was a ram reset. Lines 137-152 will set all of the pixels on the screen to black if resetram
is high, while setting the location of the cursor to where it was originally at.
To avoid the cursor moving without each location being written to the SRAM (creating spaces),the cursor does not move until xCount
equals writex
and yCount
equals writey
and it has been at least 2000 clock cycles since the cursor last moved. Lines 163-200 adjust the location of the pixel based on direction
set from our keyboard inputs while defining the boundaries of our screen. If the VGA has reached the location of the cursor, look at the value of direction
. If the cursor can move in that direction, add (or subract) 1 from writex
and/or writey
. If the space bar is pressed (direction == 5
), the current cursor position is saved in prev_writex
and prev_writey
, resetram <= 1
, and the values of R, G, and B for the background are set to the current R, G, and B values of the cursor.
At line 229-239, when resetram == 1
we select an SRAM address equal to the current cursor position, {writex,writey}
, set sram_we = 0
, and set the SRAM data to the background color to begin writing the background color to SRAM.
Lines 241 to 268 are what blinks the cursor and writes the R, G, and B value of the cursor to SRAM when xCount
equals writex
and yCount
equals writey
. If the VGA has reached the position of the cursor, the if/else statements first check to see if the cursor is moving. If it is not, it then it looks at the values of the cursor and background colors. If these two are the same, the color of the cursor will blink between the same color as the background and grey. If not, it will blink between the color of the background and the current RGB value of the cursor.
When the SRAM is not being reset and the VGA is not at the position of the cursor, lines 270 to 276 set the SRAM adress to {xCount,yCount}
and sets the VGA colors to the values from the SRAM data.
In order to allow the user to interact with our project we chose to use a PS2 keyboard for inputs. The PS2 keyboard has it's own clock and data line which it uses to send key codes to the FPGA. When you push a key down, the PS2 keyboard will send out a code, C. If you continue to hold down the key, the PS2 keyboard will continue to send the key code over and over again, C ... C ... C. Once you release the key, the PS2 keyboard will normally send out the code F0 then the key code of the key pressed one last time, F0 C. The PS2 keyboard will send out additional codes along with F0 before the final code if certain special keys are pressed. These special keys are not used in this project. The PS2 keyboard's clock will only run when it is sending data and the data should be read on the negedge of the clock. The data comes in the form starting bit of 0, 8 bit code, odd parity bit, and ending bit of 1. Because of certain errors that can occur it is important that if a full 11 bits are not received a certain time after receiving the first bit, you drop all bits received and restart the process of receiving a signal. In order to do this timing aspect the module must be run off of the FPGA's clock rather than the PS2 clock because the PS2 clock is not always running. In the always loop run by the FPGA's clock you can test for when the negedge of the PS2's clock occurs. this is possible because the FPGA's 50 MHz clock is a lot faster than a PS2's clock which only goes up to 16.7 kHz. The keyboard module sends out the 8 bit code that is received and pulse of 1 when a new code is received.
In the main module of our program the codes from the keyboard and the pulse is used to change colors and move the cursor. Values directly based off of the codes from the keyboard are only updated when the pulse of 1 is received from the keyboard module. If the previous code was F0 then we know that a key has been released and no longer want to move the cursor so we do not update the keycode
to the new code received. If the previous code was not F0 then as key is being pressed and we do want to update keycode
. keycode
is then used in a combination block to determine the value of direction. If certain keys are being pressed direction is set to a specific value otherwise direction is set to 0. If a key has just been released, previous code equals F0, then we want to invert the R, G, or B of the cursor if R, G, or B is being released which is determined off of the code received.
We referenced the post PS2-Keyboard with Verilog... to interface with our PS2 keyboard.
To conclude, we have successfully created a digital version of an Etch-a-Sketch and added additional functionality with colors and a changing background. We have outlined the goals we set and the hardware and modules used to complete them. With the provided design files and the resources we outlines, replication and modification of this project should be obtainable.
-
VGA controller module from "Snake" on an FPGA by Daniel Lovegrove, Ian Sweetland, Kristjan Jacobson, and Roberto Alves
-
Keyboard module from PS2-Keyboard with Verilog... by funkheld