Tetris Handheld

Matt Kopperud

Overview

I started my idea with my love for retro video games. At the beginning, I was planning on modifying a github project of space invaders for use with our microcontroller. However, I figured out that it was incomplete and would be difficult to get working. Therefore, after discussion with the professor I decided to change my project idea to modify a Tetris GitHub that was created for a different microcontroller. This device has a 320x240 TFT color LCD screen which displays the game screen and menus. A speaker for broadcasting sounds based on program events and a joystick for interacting with the program.

Board top Board back Side view Video

Hardware

For this project, I used a Waveshare 2-inch LCD screen with SPI interface for displaying images, a 2W 1" 4-Ohm round speaker to generate sound, an 8-direction joystick for user input and a EFR32BG22 microcontroller from Silicon Labs. The joystick has been limited to the 4 cardinal directions using software components in Simplicity Studio IDE. The device gets its power from a USB connector.

Assembly Schematic

Software

I used C programming language to develop code for this project using Silicon Labs' Simplicity Studio. The audio files are generated using .wav audio files converted into raw PCM audio data. To convert the .wav audio files to the correct format I created a project in C# programming language using Visual Studio. The used audio files were collected from Web and were converted to a resolution of 16-bit and a sampling rate of 16ksps to play back via microcontrollers's DMA module. The github project was converted over and recoded to use an initialization function, ISR and switch-case statements in the app_process_action loop.

Title screen Game screen

Once the user presses a joystick input a start sound will play from the speaker and the game will switch states to the game screen. The game screen is broken into two parts: the play area and the sidebar. The pieces that the user can manipulate are constrained to the play area and side bar. The play area is 10 blocks wide and 20 blocks tall counting from the top left corner of the screen. The sidebar is colored based on the level and displays the next piece to enter the play area, the user's current score and the player's current level.

The blocks fall at a set rate determined by the level's gravity ISR but can be sped up by pressing the down direction on the joystick. If the user fills a full row in the play area the clear_line function is called and the user has their score increased by 10 and the line is removed from the play area, shifting everything above it down by one row. Depending on the current game level the gravity ISR will speed up, the sidebar will change color, and a sound file will play. I created three different levels for my program starting at level 0 (the slowest), then after clearing 1 line upgrading to level 2, and after clearing 5 lines level 3 (the fastest). The 3 pictures below are of each level (level 0 | 800ms gravity timer, level 1 | 400ms gravity timer, level 2 | 200ms gravity timer).

Level 1 Level 2 Level 3

Tetris pieces are generated from a 2d template array static_pieces[x][y] storing each of the 7 pieces [x] and their 4 rotation directions [y]. See below for all the shapes. Piece randomization was changed to this micro controller’s True Random Hardware (TRNG) function that was called to generate a number between 0 and 6. This generated number corresponds to a piece as shown above. If pieces are placed into the top row the game will end when the next piece is spawned; displaying a Game Over text over the game screen. A prompt will show up that says, "play again?" which can be used to restart the game.

Shapes Game over

Final Thoughts

Overall, this project felt a little intimidating being given the program logic completed for a different micro controller then needing to change it to be functional with my microcontroller. My biggest challenge of this project was creating the program to convert the audio files into the proper format and changing over the game logic to use switch-cases instead of if else statements. This was a necessary switch because the audio files, when played caused the program to crash if played in-line with logic instead of inside the app_void_process function where I put the cases. If I were to do this again, I would try to break parts of the code into separate projects instead of leaving all of the code in the one project.

Downloads