ECE3140 CS3420 Final Project

By: YoungSeok Na, John Lee, Jasmin An

View the Project on GitHub ece3140-sp2020/ja499-jsl344-yn224/tree/final-code

Table of Contents

Introduction

System Overview

System Description

Testing

Work Distribution

Reference

Welcome to ECE3140 / CS3420 GitHub Pages!

Baskin-Robbins 31 Game

[Introduction]

In this project, we implemented a game called Baskin Robbins 31 on the board. This game requires two players to alternate turns and say 1, 2, or 3 consecutive numbers from where the previous player left off. The player who says 31 loses. In order to play this game on the board, we used periodic real-time scheduling to give each player a 5-second turn; the green LED represents player 1’s turn while the blue LED represents player 2's turn. Each player inputs his or her number by pressing the assigned switch button. This is done by GPIO and interrupts. In addition to the RGB LED, we used UART and PuTTY to describe the progression of the game. Although the game might sound simple, we believe it is the utmost importance that the game is as interactive and resilient as possible. With these values, we successfully recreated the game on the board. The extensive use of GPIO, interrupts, and real-time scheduling enabled us to gather in different materials we have learned in a way that we have never thought of in regular labs.

[System Overview]

Game Design
Diagram 1. Design of the game "Baskin Robbins 31"
Interface
Diagram 2. System-Player Interface
Game Structure
Diagram 3. The overall structure of the game

Our system can be divided into 3 stages as described in Diagram 3: setup, game, and ending. In setup, we initialize UART, switch buttons, and LED and choose which player will go first. Then the two periodic processes, each representing the 5-second alternating turns given to the two players, are created in the order determined. In each turn, the LED’s color corresponding to that player would light up while each button press causes the LED to toggle. During the game, the player in his or her turn presses the respective button 1, 2, or 3 times. The game ends when either the total number of the buttons pressed reaches 31 or the number of turns that did not have any inputs reaches 3. The ending of the game is then followed by an infinite loop of either blinking of the winner's LED or the red LED for error. The total number of buttons pressed that gets displayed in the serial monitor is determined with respect to the previous turns.

*Special thanks to George Zhuang and Jenny Suk for allowing us to use the recording of them playing our game.

[System Description]

In the set-up stage, we initialized UART, Button, and the LED. Then, we notify the players of their LED colors through PuTTY - player 1 is assigned to SW2 and the green LED while player 2 to SW3 and the blue LED (SW1 is RESET button). Then, choose_first_to_go() is called to decide on which player would go first. This is done by using its local variable that would alternate between 1 and 2 until either of the two players presses his or her button so as to add randomness. Indeed, we could have made the function run automatically and decide randomly between numbers 1 and 2. However, the one of the most important values we had for this project was to make the game as interactive with the players as possible. Hence, we decided to make use of button inputs when determining who would go first. Furthermore, it is true that the operations could have been simplified by using values of 0 and 1 and using bitwise XOR operators. However, to be consistent with the numbers associated with the players, we have decided to use values 1 and 2. When the player is chosen, white LED blink - no_problem_sign() - is displayed to notify the players that the player to go first got chosen and the LED of that player is displayed, which are both indicated through PuTTY simultaneously.

One of the problems we faced was that the variable that keeps track of the total number of buttons pressed in the game got updated when RESET was pressed to start the game. This issue was addressed by re-initializing it to 0 at the end of choose_first_to_go().

Once the starting player is determined, the periodic processes (representative of each player) for the turns are created. Because the order at which periodic processes are created matters when the scheduler starts to run, the function pointers needed in creating a player are also required to be aligned with the order of players chosen previously. Hence, we needed to adjust which function the function pointer parameter used in creating the first player points to accordingly.

After creating the two players, the function that signals for the start of the game gets called. It starts the countdown on the serial monitor and the red LED would blink to indicate that the game is about to start. By initiating the execution of the scheduler through process_start, this turn-based game would start. Each player’s 5-second turn is indicated through both the serial monitor and the LED, with the color of the player for that turn. The player can press his or her assigned button one to three times during the turn. If the player attempts to press his or her buttons more than 3 times during the turn, the interrupt handler would not allow LEDs to be manipulated or the variables dedicated to keeping track of the number of buttons pressed to be incremented. In addition, the player’s button will be disabled from such functionalities on the opponent’s turn. Any button interrupts detected during a turn are indicated by the LED toggle and the text ‘PRESSED’ being printed on the serial monitor.

Aforementioned, there exist two ending protocols: the general case where the total number of buttons pressed reaches 31 and an exceptional case where the number of turns at which no inputs were detected reaches three.

In the general case, once the number 31 has been reached, first the winner flag is updated with the winner’s number (1 for player 1 and 2 for player 2) and both buttons will be disabled from manipulating the LED by setting the turn variable to 0. Then, player processes will be deallocated from the stack and heap space to prevent memory leak. After freeing, the periodic scheduler would terminate and the LED with the color of the winner will toggle infinitely.

In the exceptional case, the number of turns with no inputs are kept track of by observing whether the turn that just ended had any updates in its PCB field indicating the number of buttons pressed. If the field was 0, then the variable that keeps track of the “no-input turns” was incremented. Once that number reaches 3, similar procedure as the general case follows: the buttons will be blocked from manipulating the LEDs, player processes would get deallocated, and the scheduler would terminate. Instead of displaying the winner, the program would run the “error” loop that would blink red LED infinitely, signalling the faulty game.

When developing solutions for this exceptional case, we have tried to come up with one that would not disturb our periodic real-time scheduling structure and maintain good coding practice. The first proposal was to pause the game when the player in the previous turn did not press any buttons. Naively approaching the proposal, we inserted a while loop in the button interrupt handler, making a white LED turn on to signal the pause. However, this gave rise to the issue of ignoring the basic property of interrupt handlers: they need to execute as quickly as possible. Other solutions involved forcing the player to press a button if they did not press any on their turn, or resetting and delaying the current player’s turn so that the game includes the “error turn” with no manipulation of LEDs or number of buttons pressed incrementation is possible. However, this involved unnecessarily complicating the logic of LED signals by requiring us to add an indicator LED signal, which we thought would confuse the players even more. This constant allusion to the tradeoff between the implementation complexity and the visual complexity led us to agree upon the most optimal yet simplest solution, where the game would stop if 3 turns with no inputs are detected. This was reasonable given that the standard premise of the original game that this project is based upon requires each player to at least give one input.

Other exceptional cases or behaviors were also approached similarly. However, there existed one case we were unable to handle even after following the same procedure. When the first player gets to go, if that player presses his button as soon as the UART starts to stream data into the serial monitor, the system recognizes that interrupt and increments the number of buttons pressed in that turn, making the maximum number of possible button presses to 4 instead of 3. But, this was outside of our control since this involves dealing with real-time problems and timing, rather than a compile time factor.

We initially have been using UART and PuTTY simply to help us to debug but we went further to use it in the game because it enabled us to complicate the game even more than when using the RGB LED alone to indicate the status of the game to the players by having the serial monitor display further information about the current status of the game at the appropriate moment. The game could still be played from the board alone by recognizing distinct LED configurations for each step as described above, but UART and serial monitor output gave deeper insights into the game. Both the board and UART and serial monitor have the mechanism for celebrating the winner when the total number of pressed reaches 31.

Moreover, though not critical to the functionality of the game, we tried enhancing the method of displaying the winner through pulse width modulation (PWM). Simply put, it adjusts the duty cycle of the LED’s signal and depending on that duty cycle, different “brightness” of the LED can be achieved. After a long searching process on how to implement such a display system without going through register-wise manipulations of the FTM module, we encountered the standard library provided by MK64F12 library that abstracted away such details for us inside Kinetis SDK v.2.0 API Reference Manual. Unfortunately, it was too late in the timeline when we realized that it was hard for us to use the FTM module provided by the MK64F12 standard library because there was no wiring between the module and the embedded LED, as found in K64 Sub-family Reference Manual. We could have bit-banged the FTM module and manipulated another PIT timer to demonstrate PWM but due to our limited amount of time, we settled on an agreement that it was sufficient to display the winner as simply an infinitely-running blinking of the winner’s LED.

Additional Note:

[Testing]

We made use of incremental testing and physical testing through human interactions. To ease the process of incremental testing, we tried our best to amortize required testing. This way, we could guarantee that any errors encountered on each step of our project development was due to the new parts added from the previous stage of progression. Doing so significantly reduced our overall debugging timeline. When moving onto the next stage of testing, we simply added on to the test file we previously had been working on. Accumulating all the testing methods in one file prevented us from losing track of multiple unique test files. The final test script essentially became our main code for our game. Additionally, we asked our friends to play the game for us. Having human interactions with ad-hoc testing helped us to find edge cases that we could not think of when developing the code. Moreover, UART/Serial through PuTTY helped us to debug by finding the specific line of code that was causing an error or illogical code progression.

Here is the testing procedure we followed:

  1. General functionality of buttons and their independence.
  2. Combining buttons with periodic processes.
  3. Making sure that the numbers of buttons pressed are being kept track of.
  4. Handling minor erroneous behaviors.
    • LEDs reacting to the RESET button.
    • RESET button incrementing total number of buttons pressed.
    • Button interrupts manipulating LEDs during the setup phase of the game.
  5. Setting limits to numbers of buttons pressed.
  6. Applying UART/Serial.
  7. Transitioning to displaying the winner state.
  8. Handling the case when the player has not pressed any buttons in his or her turn

The validity of the board’s behavior for each test case was confirmed by comparing the board’s response to our input with the expected behavior. We decided not to test the debouncing of buttons extensively because we trusted the capacitor inside the board was strong enough to be capable of dealing with such debouncing.

[Work Distribution]

We have brainstormed together to come up with the overall design of the game and would implement for most of the coding through Zoom. However, since some of us are in different time zones, some of us had to work separately. Github was used to share code while debugging and testing would be done separately and readme texts were written to declare changes in code. The website was created from a google doc which everyone had access to. The final video was produced by John, who had friends around him to test and play the game. We believed that a video with several people playing the game would be much more efficient to convey information than merely an explanation video.

Major roles:

YoungSeok Na

  • Overall code development
  • Content research
  • Website writeup
  • Website content transfer to HTML

Jasmin An

  • Website writeup
  • Overall code development
  • Detailed debugging
  • Drawing system schematics

John Lee

  • Drawing system schematics
  • Ad-hoc testing
  • Filming

[Reference]

We largely depended on the K64 Sub-Family Reference Manual and the FRDM-K64F Freedom Module User’s Guide to set up the GPIO and interrupt. Aforementioned, we looked into Kinetis SDK v2.0 API Reference Manual but it did not have impact our code significantly. Also, the implementation of periodic processes and the usage of the RGB LED required us to borrow some functions from our lab5 codes. However, we had to readjust them in order to fit our purpose of building a game that involves many other requirements - the button switch and UART initializations and the necessity for ending the periodic processes, just to name a few. Apart from those and the provided resources from the Piazza and Canvas, everything else is done from scratch.