Lab 3 (FPGA Video Controller)
During this lab we worked on writing code in Verilog to allow an FPGA to control a VGA monitor. We also implemented a method of communication between the Arduino and the FPGA to control the output on the screen.
Overview
For the final competition Red Rover (our robot) must map out a maze and we must update the configuration of the maze on a screen in real time. Using our maze mapping algorithm and the wall sensors, Red Rover must send its position and whether there are walls to its front and sides via its Arduino to the other Arduino at the base station that is connected to the FPGA. The FPGA will process this information and then the VGA monitor will display the output. In preparation for this, lab 3 taught us how to control the VGA display with the Verilog code, and how to control this with the base station Arduino.
Building the DAC
Soldering the Digital-to-Analog Converter (DAC)
The first step we needed to take in this lab was to connect the FPGA to the VGA using a digital-to-analog converter because the FPGA outputs digital bits at 3.3V representing the RGB (3 bits for green, 3 bits for red, 2 bits for blue) color to be outputted to the screen, but the VGA requires analog inputs with a maximum value of one volt. Therefore, we built a DAC using resistors connected to each GPIO output of the FPGA, where the signals are then combined into analog voltages.
The different combinations of bit values determine the strength of the color value and are mapped to analog values via the DAC. This mapping was done with voltage dividers, and a MATLAB script was written to obtain the required values of the resistors.
Programming the FPGA to Generate VGA Output
Project Configuration
The next step in lab 3 was to download the DEO NANO project from the website and open it in Quartus. DE0 Nano was the top level file with various modules instantiated in it, including an M9K RAM module for storing the position, orientation, and wall data, an image processor module to make sense of this data, and a VGA driver to update the screen. We also set up a phase-locked-loop to control the clocking. The Verilog code for the instantiation of the PLL is below.
team24_secondtry team24_secondtry_inst ( .inclk0 ( CLOCK_50 ), .c0 ( c0_sig ), .c1 ( c1_sig ), .c2 ( c2_sig ) );
Image Processor
The default was the code set the screen to blue except for a black square in the upper left corner, which is where the maze would be drawn. We changed the coordinates of this square to be 270 by 270 pixels to ease the maze mapping later since 270 is divisible by nine and the grid the robot with traverse will be a nine by nine grid. We edited the image processor module to control the colors and pattern in this box. We added a four-bit color output from the image processor module (will later be mapped to eight bits) and a write enable input that flipped between 0 and 1 on the positive edge of the clock. Then on every positive edge of the clock we increase the value of the x and/or y pixel address variables to traverse the screen pixel by pixel. On every positive edge of the clock we output the x and y pixel addresses and the four-bit color value.
Then the following equation: WRITE_ADDRESS = X_ADDR + Y_ADDR*(`SCREEN_WIDTH) maps these pixel addresses to addresses in the M9K RAM, which will store this color data in the corresponding cell. This address and the four-bit color value is inputted into the M9K RAM. The data values are read out from the M9K RAM into the VGA driver module. Then these four-bit color values were mapped to eight-bit RGB vectors. By changing how and when we assigned which of the four-bit values to which x and y pixel values, we were able to display different patterns on the VGA monitor. Below is our code to update the screen with stripes.
Verilog Code
always@(posedge CLK) begin W_EN <= 1'b1; if (x_pixel_addr < 270) begin x_pixel_addr <= x_pixel_addr + 1; end else begin x_pixel_addr <= 0; y_pixel_addr <= y_pixel_addr + 1; end if (y_pixel_addr >= 270) begin y_pixel_addr <= 0; x_pixel_addr <= 0; end if ((x_pixel_addr/10)%2 == 1) begin PIXEL_OUT = 4'b1111; end else begin PIXEL_OUT = 4'b1110; end end
Programming the Arduino to Communicate with the FPGA
Configuring Both Devices
Finally we connected digital pin 13 of the Arduino to one of the GPIO pins of the FPGA and looped through setting this value to high and low. In the DEO NANO file we set the value of the screen to different colors based on whether the GPIO pin was reading a high or low value. We also set the built-in LED on the Arduino to blink so to show that the Arduino is controlling the changing colors on the screen. Therefore we were able to control the VGA monitor screen with data from the Arduino. Please see our Arduino code below.
Arduino Code
#define pin13 13 void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode (pin13, OUTPUT); digitalWrite(pin13, LOW); } void loop() { // put your main code here, to run repeatedly: digitalWrite(pin13, HIGH); delay(50); digitalWrite(pin13, LOW); delay(50); }
VGA Driver
The instantiation of the VGA driver module uses ternary operators to decide what to output to the screen based on if the GPIO pin is reading a high or low value. This instantiation is shown in the code below, with the output logic in the "PIXEL_COLOR_IN" connection.
VGA_DRIVER driver ( .RESET(VGA_RESET), .CLOCK(c1_sig), .PIXEL_COLOR_IN(VGA_READ_MEM_EN ? (GPIO_1_D[25] == 1 ? (MEM_OUTPUT == 4'b1111 ? BLUE: RED) : GREEN) : GREEN), .PIXEL_X(VGA_PIXEL_X), .PIXEL_Y(VGA_PIXEL_Y), .PIXEL_COLOR_OUT({GPIO_0_D[9],GPIO_0_D[11],GPIO_0_D[13],GPIO_0_D[15],GPIO_0_D[17],GPIO_0_D[19],GPIO_0_D[21],GPIO_0_D[23]}), .H_SYNC_NEG(GPIO_0_D[7]), .V_SYNC_NEG(VGA_VSYNC_NEG) );
Video of Arduino Toggling One Bit to Change VGA Output from FPGA
In the video, you can see the VGA output changing every second as a result of the Arduino toggling the state of one pin (pin 13), and this is evident by the internal LED on the Arduino turning on and off every second.
In conclusion, our base station’s Arduino can communicate with the FPGA and the base station can draw some patterns on the monitor, and the information controlling what is drawn is sent from the base station’s Arduino to the FPGA. Now that we are able to control the output on the screen of the VGA monitor with the Verilog code and the Arduino, we will have the Arduino use parallel communication to send the wall, location, and orientation data to the FPGA and update the configuration of the maze on the screen.