Zynq based Game Implementation

2 minute read

This particular project used the Zynq FPGA dual-core ARM processor. The hardware and software flow made the use of Vivado and Software Development Kit (SDK) respectively as follows:

Flows

The objective of the project was to develop a game of pong. The game had to have a single bat at the bottom of the screen controlled by the hardware and a ball that bounced off of the three walls and the bat. The game score incremented by one each time the ball hit the bat and the game session was said to be over once the ball missed the bat and left the screen.

A Real-time Operating System (FreeRTOS) was used in order to introduce more flexibility in the program and allow for multiple tasks to handle the hardware input and animation. The IP used were a PWM-based controller and a VGA display for game demonstartion. The PWM value (knob position) was polled to determine the bat’s horizontal position on the screen.

The FPGA was programmed to add the VGA display and to continuously update the incoming pulse width coming from the controller’s knob position. The block diagram of the connections between the Zynq board, VGA display and the PWM-based controller is shown below:

Block Diagram

Once the FPGA fabric on the board was programmed, SDK was used to test the functionality of the developed hardware. Three seperate tasks were created: BallTask, BatTask and ScoreTask. The BatTask was responsible for linearly mapping the knob position (technically the period of the pulse coming from the knob) to the position of the bat on the screen, so that knob minimum mapped to the leftmost bat position and knob maximum mapped to the rightmost bat position on the screen. To begin with, we supplied the code with a rough estimate of the maximum and minimum values of the knob. As the game progressed and the newer values of pulse periods were detected, we updated the minimum and maximum values accordingly.

The BallTask basically took care of all collisions with walls and the bat. It had a series of ‘if’ conditions that told it what to do if the ball circumference came in contact with the walls/bat. Some parameters were passed to the BallTask that consisted of the starting coordinates of the ball, the step increment coordinates, colour of the ball and the y coordinates of the bat (constant throughout,only x coordinates of the bat change). To detect and respond to collisions, the ball was to reverse the direction of its x coordinate (if it collided with the right or left walls) and y coordinate (if it collided with the top wall or the bat). If the bat was not brought to the correct position to ensure a collision, then the ball left the play area and the string “GAME OVER” appeared at the centre of the screen. Moreover, every time the ball collided with the bat, integer variable “score” incremented by one. This score value was sent to the ScoreTask.

The ScoreTask just printed the score that the ball sent it on the screen.

As can be seen, the different tasks needed to communicate with each other. The Bat and Ball Tasks needed to know each other positions in order to detect collisions. The ScoreTask needed to know when the ball has collided with the bat and update the score accordingly. Two queues were created for these purposes- one to take care of each communication as shown below:

Queue 1

Queue 2