Snake game on an ARM microcontroller

I’m starting to get accustomed to using an ARM chip and wanted to do a small project. I’ve always enjoyed playing the game of Snake, but never programmed it myself. I present to you Snake on an ARM Cortex-M0 microcontroller.

I’m using the STM32 F0 Discovery board along with a Nokia 3595 cellphone screen. The hardware SPI on the ARM chip makes it pretty easy to address the display. But I’ve written the program to be display agnostic. Keep reading for more details on the programming choices I made.

You can seen in the video demo that I’m almost done with everything. I have one collision bug to work out and I’ll have achieve all of my goals. You take a look at the code if you’re interested. It may look complex, but I put everything together using simple steps:

  1. Develop functions to draw and erase pixels. If I move to new display hardware all I need to do is change these to match.
  2. Start with a dot that moves back and forth on the display. To implement this I needed a timer system and a way to track the dot. The ARM SysTick function is perfect for this type of timing.
  3. Make the dot controllable. I added a joystick and monitor the buttons. Each button sets a direction flag which is then used by the functions written in step 2. This gave me a chance to practice setting up the I/O and their internal pull-up resistors.
  4. Make the dot into a longer object and make the tail follow the head of that object. Now we’re getting a bit more complex.
  5. Add collision detection to see if we’ve hit the walls or the snake itself.
  6. Add fruit for the snake to eat, making it longer
  7. Add eye candy: a startup graphic (button press to get past graphic acts as the random see for locating fruit) and “Game Over” text.

Hardware Setup

I had already used this screen with the Discovery board. The board offers pins for 3.3V power regulated from the 5V coming in on the USB cable so there’s no need for an external supply. The buttons were simply a matter of connecting the common pin to ground and the rest to I/O pins on the board.

Tracking the snake

One thing that I had to think about for a few days was how to keep track of the snake. The program must know where every section of the snake is in order to detect collisions. This chip has a lot of RAM, but it seemed too wasteful to hold a buffer of every point on the game board. That would probably have worked, but it greatly limits the scalability of the code.

What I came up with was to store the head and tail of the snake as points. I used a point by declaring a┬ástruct that has an X and Y variable. I then created an array of these structs. Whenever the snake turns, the corner is added to the list. I keep global variables ‘head’ and ‘tail’ which are the array indexes of those points. With a little math I can always figure out:

  • how many corners there are on the snake right now
  • what pixel coordinates can be found between each of those corners.

This is everything necessary to check for a collision. The one thing that becomes a problem is memory management. There’s no malloc() function for ARM (not really anyway) so I would have had to do my own memory management for a linked list. In the end I just did the development with a really large array and added support to make it circular. When I get to the last element in the array the code starts over at index 0 again. I haven’t had a problem with the head catching up with the tail.

Conclusion

I couldn’t get an image during game play. The size of the screen makes it tough to snap an image but you can see some game play in video posted earlier

It was a fun project. It doesn’t really delve into many of the extras that the ARM brings to the table. But I did end up using the On Chip Debugging to chase down a problem I had with tracking the nodes of the snake, and that’s something I never really tried with smaller 8-bit or 16-bit chips.

Resources

Source code repository

Leave a Reply