Like the rest of our design, our software is very modular. The variance tasks needed to completely run and display snake is broken down into fairly indep. These tasks are as follows:
This is the code that is run prior to anything else. This code sets up the behavior of the MCU and also initializes the state of the game.
Sync up with external sync generator
After being initialized, the MCU must be able to know where in the sequence of horizontal and vertical syncs it is so that it knows when to display the start of a frame. This was achieved using one of the external interrupts. Upon every negative edge of the sync pattern, an ISR would run that would calculate the duration since the last negative edge. Because horizontal and vertical syncs have different durations, the exact place in the sequence of pulses can be determined.
After “sync-ing up,” the program just starts sending pixels to the screen. Again, timing is determined by interrupting off of an external interrupt. By now counting the edges that cause an interrupt, it is possible to keep track of which lines need to be displayed to. For lines that do not contain information to be displayed, housekeeping code is run to update frame information along with game state. Those lines that do contain information to be displayed, proceed to set pixel values based upon the value stored in either SRAM of FLASH (depending on line number). Using assembly to optimize our code, the best resolution for pixels per line was 64. However, the limited 1K of SRAM forced us to limit the number of pixels to 48 across, but keeping the same pixel resolution. Memory addressing was broken down by line. 32 lines were used to display dynamic content via the SRAM. Content was kept dynamic by refreshing the appropriate pixels once per screen. Furthermore, 5 lines were used to display static content via the FLASH.
Snake game code
The snake code simply manipulated the contents of SRAM. This was done during the time when the MCU was not displaying information to the screen. Based upon game state variables including button pushed, snake length, and nibble location, variable pixels would be turned “on” and “off” to move the snake around the screen. To make the task of changing pixels easier, two functions were created:
By using these functions, the value of a pixel at location (x,y) could easily be read or set to a desired color.
Though game play code is limited in complexity to the number of free cycles per screen, if used correctly, significant time is available for game code to process.
Since the structure outlined by our code is so modular, it would be quite easy to simply remove the snake code and replace it with another application.