Gaming on the Raspberry Pi Pico

games on raspberry pi pico

In this post, I want to talk about gaming on the Raspberry Pi Pico.

I remember my first dumbphone, which was called a “phone” back then. It could play simple games like Snake. That was bleeding edge.

Prior to that, you’d have to carry a separate handheld that played Tetris or a more dynamic gaming system like a Gameboy.

The Raspberry Pi Pico is a pretty powerful microcontroller compared to what handhelds ran on in the 90s. Naturally, it offers us the ability to play games from that era.

How powerful is the Raspberry Pi Pico

Compared to a ‘80s console, the Raspberry Pi Pico is extremely powerful. 

If you program a game that’s similar to the resource requirements of a game from the 1980s, the Raspberry Pi Pico will probably breeze through it.

It’s the ‘90s where it starts becoming a bit more difficult to state such a clear-cut conclusion.

On the one hand, if you think of it as a device capable of playing games that are similar to what you’d find on a Gameboy or a mobile phone, you will probably be pleased.

However, games in the late ‘90s became much more taxing. You won’t be playing Quake 3 (a 1999 game) on the Pico, for example.

In fact, while the Raspberry Pi Pico will play Doom (1993), it was a six-month endeavour for the person who coded it because it was quite a difficult task to compress the game into the 2MB storage that the Raspberry Pi Pico has.

So, while the Pico has two 133MHz processors, it has limited RAM and storage, making it difficult.

Let’s see how it compares to a Gameboy:

SpecRaspberry Pi PicoGameboy (1989)Gameboy Color (1998)
DisplayColour LCD or e-ink ,it’s up to your imagination4 shades greyscale10, 32, 56 colours
ResolutionDepends on your display, but limited by Pico’s resources.160x144px160×144 px
CPU133MHz dual core4MHz4MHz/8MHz
RAM264KB8KB32KB RAM, 16KB VRAM
Storage2MB Game Pak cartridge: 8MB ROM, 128KB RAMGame Pak cartridge: 8MB ROM, 128KB RAM

Why play games on the Pico and not the Zero/Pi 4?

Good question.

As you know, the Raspberry Pi Pico is a microcontroller while the Raspberry Pi Zero or Pi 4 are microcomputers.

Both can play games, but the Raspberry Pi Pico is much more limited.

That said, if you wanted to build an emulator or gaming system from the Raspberry Pi Zero or Pi 4s today (in 2022), you’d better have one already or else your biggest bottleneck is stock.

It’s very difficult to get a Pi Zero and quite challenging to get a Pi 4.

On the other hand, the Pico is plentiful. It also boots up almost immediately, whereas the microcomputer Pis have to go through a lengthy boot-up process.

The Pico also lasts much longer. If you want a mobile setup that will run for hours and is portable, you’ll do a lot better with the Pico.

Finally, besides stock, the Pico is also plentiful in stock.

To be fair to the Pi Zero and Pi 4, you can definitely play better games and have better emulation results with those microcomputers. As you will see in the next section, the Pico does struggle to play games that the Zero or Pi 4 will breeze through.

What games can the Raspberry Pi Pico play?

We’ll start by seeing what the tinkering community has been able to play on the Raspberry Pi Pico.

RP2040 Doom is the answer to “will it Doom?”

Yes! The Raspberry Pi Pico can play Doom.

A guy named Graham Sanderson from Austin, Texas, managed to port Doom onto the Raspberry Pi Pico.

His magic formula?

while (!convice_myself_its_probably_impossible()) {
    do_some_more();
}

He explained in his documentation of the process that he faced multiple restrictions from the hardware specifications that the Raspberry Pi Pico had. After all, it’s not a device intended for gaming.

Nonetheless, Graham also decided to make the porting of Doom even harder. He wanted the authentic experience of Doom, which meant having 320×200 (colour) resolution, stereo sound, OPL2 music, saving and loading, network multiplayer and other features that are available in the original name.

To pack so much game onto the Raspberry Pi Pico meant challenges with memory. Both RAM and storage were key issues.

Firstly, the Raspberry Pi Pico only has 2MB of storage, but the shareware version of Doom is twice that size. While other developers might decide to cut certain features like splash screens and downsampling of textures, Graham didn’t want to do that.

RAM was also another issue, with the Chocolate Doom source code requiring around 1MB of RAM whereas the Pico only has around 264KB. Memory is tight because rendering the graphics takes up a huge chunk of the RAM’s space, but RAM is also very important for the smooth running of the game. In order to manage both aspects, Graham had to do what he called “liposuction”.

You can read more by going to the documentation, watching his YouTube playlist or reviewing the code.

NES emulator

The Raspberry Pi Pico has been successfully made into an NES emulator.

In an Emulator Zone Forum thread, user ropgar said that the Raspberry Pi Pico has the power to emulate a NES and it can do 60 frames per second and can emulate APU and PPP perfectly.

Ropgar uses a PS/2 keyboard as a controller, but you can also use the original NES controller.

Sound is good and there are no glitches on video and background game music.

The Pico has about 1.5MB of flash space left for different games, which can be chosen by pressing Caps Lock to switch between games. 

The games ropgar managed to load onto his demo are Pacman, Arkanoids, DK, DK Jr, BubbleBobble, Galaga, and many others.

The one downside is that there’s no public source code or tutorial on how to do this.

Gameboy emulator for the Raspberry Pi Pico

You can make your own Gameboy case and then use the Raspberry Pi Pico to emulate the Gameboy.

The tricky part here is that it’s actually not something that has seen a great amount of success. In other words, what you build might work, but not always.

Let’s take a look at the options out there.

Rust Gameboy emulator (OxidGB Pico Port)

Image by u/j_selby (Reddit)

Upon seeing the Pokemon image on the screen, I was immediately excited.

However, James Selby actually wrote about the challenges and shortcomings of his Gameboy emulator, written in Rust, named OxidGB Pico Port.

“This has been a ride – a frustrating ride, but a ride I’ve thoroughly enjoyed nonetheless from an educational perspective,” Selby said.

Problems and wins

Here’s the main challenge: The Rust Gameboy emulator “isn’t exactly playable in its current state unfortunately.”

Selby said games only get about 10 FPS because the emulator’s code is a bottleneck as well as the slow SPI interface to the display.

It’s possible to speed things up but that would require time to plan and implement.

Input hasn’t been configured, since the games weren’t playable. 

Testing the OxidGB Pico Port

If you’d like to give it a try, you can follow Selby’s instructions on his Github repo for the OxidGB Pico Port.

RP2040_GB emulator

RP2040_GB emulator hardware and setup, photo by Mahyar Koshkouei.

Another emulator you can try is the RP2040_GB, which is based on the Peanut-GB emulator.

Performance on the RP2040_GB is decent, with Koshkouei saying that his setup “runs at more than 70 fps without audio emulation. With frame skip and interlacing, can run at up to 120 fps.”

As you can see, the RP2040_GB is playing Pokemon. The steps to getting a ROM onto the RP2040 are as such:

  • You must have the Pico SDK
  • Convert .gb or .gbc ROM to a C header file using the xxd program
  • Modify the converted file by adding two lines of code (in the Github readme)
  • Copy ROM to the src folder and compile.

There are some limitations of this emulator:

  • “This emulator is inaccurate and is very much a work in progress … some games may run incorrectly or not run at all.” 
  • Gameboy Color games will throw an error
  • Not optimized for microcontroller: Koshkouei suggested that, “Using an APU that is optimised for space and speed” can help.

See the RP2040_GB’s Github repo here.

Mega Games Compilation with Raspberry Pi Pico

The best part about this project is that it’s simple and the instructions are adequate for you to get started on a Raspberry Pi Pico gaming console quickly.

Roger Bühler has parts, instructions and demos included on his Github.

The Mega Games Compilation comes with the following games:

  1. Tiny Gilbert
  2. Tiny Trick
  3. Tiny Invaders v3.1
  4. Tiny Pinball v2
  5. Tiny Pacman v1.2
  6. Tiny Bomber v1.3
  7. Tiny Bike v1.2
  8. Tiny Bert 1.1
  9. Tiny Arkanoid v2
  10. Tiny Tris v2.1e
  11. Tiny Plaque
  12. Tiny DDug
  13. Tiny Missile v1.1
  14. Tiny Lander v1.0 ( by Roger Buehler  )
  15. Tiny Morpion
  16. Tiny Pipe

The parts you’ll need are as follows:

  1. Raspberry Pi Pico
  2. SSD1309 128x64px SPI OLED display (2.42” display at 2:1 ratio)
  3. Piezo buzzer
  4. Five buttons
  5. Breadboard
  6. Jumper cables
  7. Optional: 10 ohm resistors, electrolytic condenser rated for at least 10V and 220uF

You will also need Adafruit’s SSD1306 library.

Here’s how to connect the display:

  • GND –> Display GND 
  • 3V3(OUT) -> Display VCC 
  • GP16 -> Display DC (Data Command) 
  • GP17 -> Display CS (Channel Select) 
  • GP18 -> Display SCL (Clock) 
  • GP19 -> Display SDA (MOSI) 
  • GP20 -> Display RES (Reset)

And to connect the buttons:

  • GP15 -> button UP 
  • GP14 -> button DOWN 
  • GP13 -> button LEFT 
  • GP12 -> button RIGHT 
  • GP11 -> button FIRE (all buttons to GND)

And to connect the piezo buzzer:

  • GP10 -> Buzzer(+) 
  • GND -> Buzzer(-)

Software installation:

In order to install the software, you need to use the Arduino IDE.

Tamagotchi-like game on the Raspberry Pi Pico (Pico-Tamachibi)

Why is it called Pico-Tamachibi?

According to Kevin McAleer, the creator of this device, “tama” means “egg” and “chibi” refers to graphics where the character has a big head. 

Creating the Tamachibi is easy because Kevin goes through every step of the way in his 90 minute tutorial.

Build your own gaming machine

If you want to make your own Raspberry Pi Pico gaming machine, there are two general ways you can do that: buy a ready-made kit or build one yourself.

Ready-made kit vs DIY Raspberry Pi Pico gaming hardware

While it’s possible to start from scratch, you might want to skip the hassle of building your own system and just buy a ready-made package.

There are a few RP2040-based kits that allow you to jump straight into playing or developing your own games.

Let’s look at the Pimoroni Picosystem and then compare it to the process of building something similar using individual parts.

Pimoroni Picosystem

Let’s take a look at the Pimoroni Picosystem.

As you can see, it’s much bigger than the Raspberry Pi Pico W, but that’s also because it has a four-way D-pad, four buttons, LCD screen, a lithium-ion battery, piezo speaker and a USB-C port, among other additions.

It has the same processor and RAM, as both the Picosystem and the Pico use the RP2040 chip. Here’s the full specs:

  • Powered by RP2040 (Dual Arm Cortex M0+ with 264kB of SRAM)
  • 16MB of QSPI flash supporting XiP
  • 1.54″ colour SPI IPS LCD (240×240 and 120×120 modes)
  • D-pad and buttons
  • 525mAh LiPo battery (6hrs+)
  • Piezo buzzer/speaker
  • On/off power button
  • RGB LED
  • Programmable and rechargeable via USB-C (cable not included)

Graphics modes

PicoSystem supports two graphics modes.

  • 240×240: the native resolution of the LCD
  • 120×120: pixel doubled mode (saves RAM)

What does gaming on the Picosystem look like?

Gaming on the Picosystem is easy. Just press the power button and you are treated to the preloaded game called Super Square Bros.

The game is a simple platformer much like Mario.

Pimoroni has also included other games:

  • Super Square Bros. by Scorpion Games – A bouncy quadrilateral platformer (preloaded game)
  • Dots – Dot popping puzzler. Create chains of two or more and race to get the biggest score.
  • Rocks and Diamonds – Classic game of dodging rocks and grabbing diamonds.
  • Geometry – Smash up space boulders with lasers to make smaller space boulders!
  • Rainbow Ascent – The Dark Souls of procedurally generated vertical jumping puzzles. Good luck.
  • Super Blit Kart by Daft_Freak – A “Mode7”-based racing game.

In order to install these games, do the following:

  • Download the file.
  • Plug your Picosystem to the PC
  • Press and hold the X button and the press power button.
  • The Picosystem should be mounted as a drive called RPI-RP2
  • Copy the downloaded .uf2 file onto the drive. It will automatically load.

For some reason, my USB-C to USB-C cable didn’t work, but the USB-A to USB-C cable worked with the Picosystem. If you do not see the red LED light up, then try another cable.

Program your own games

The best part about the Picosystem is that it provides a system for you to create your own games.

Rather than coding from scratch, PicoSystem comes with a special API that can help you create your games.

It also takes away a lot of the tedious work required to buy individual parts like an LCD screen, buttons, jumper wires, breadboard and then figuring out the libraries and packages required to get all of these working.

The PicoSystem’s API has functions for drawing stuff on the screen, to output audio, hardware functions and other utility functions. This makes it easier for you to build your game.

Just like the Raspberry Pi Pico, the PicoSystem can be coded in C++ or MicroPython. 

Is it easy to program a game with the Picosystem?

I’d recommend that you have some time and patience in order to build your own game with the Picosystem.

The documentation offers the basics in order to get you started but it’ll be best if you had some prior knowledge of game programming.

The biggest challenge for beginners is that there aren’t many resources out there that teach you how to code sample projects. However, here’s a list of reference that will help you:

Picosystem MicroPython guide (in readme)

Picosystem MicroPython examples

Picosystem C++ Github

Picosystem C++ examples

Picosystem API cheatsheet, plus image, font converter (on sidebar)

DIY system: Creating the hardware

YouMakeTech’s guide walks the reader through how to make a complete gaming console with a case, sound system and permanent soldering.

For our comparison, let’s see how much it would cost to build a DIY unit versus the Picosystem, which is a complete kit.

YMT’s gaming systemPimoroni Picosystem
CaseOptional, 3D printed ($4.47 for STL blueprints, plus filament and 3D-printer rental/operation costs)Included
Raspberry Pi Pico$5 for Pico H because you will need the headers.Included
OLED display$15 (0.96 inch display)Included
ButtonsNegligibleIncluded
Breadboard$15 (breadboard kit)Included
Jumper wiresIncluded in breadboard kitIncluded
ScrewsUp to $1Included
PiezoNegligible Included
Total cost$40.47, excluding 3D printing costs$70

So let’s see the final costs for different tiers of DIY setups:

SetupCosts
No battery$40.47 excluding 3D printing costs
Lipo battery$8
Pimoroni Pico Lipo$16.39 – $4 (since we’re using the Pimoroni Pico replacement, we can deduct the cost of the Raspberry Pi Pico)
Total for a battery-powered kit$60.86 excl. 3D printing costs

Just a caveat – YouMakeTech says that you can build this for less than $20. In my research, however, the costs for a DIY set up that matches the Picosystem don’t really differ that much, especially when you consider the software and convenience.

YouMakeTech’s prototype which has two buttons, a screen and can play Pong

That said, the DIY route is a great learning opportunity. One thing that challenged me was the screen. While YouMakeTech’s example uses an I2C connection, the screen that I had used a 4-pin SPI interface. That either requires a change in coding or a modification to the hardware in order to proceed. If you like challenges, the DIY route is for you.

So, what are the advantages by doing it DIY versus the Picosystem?

Pros/ConsDIYPicosystem
Hardware assemblyYou DIY everythingYou DIY nothing
SoftwareNot much help here. You DIY everything yourself and learn how to operate each component.You have to learn the Picosystem’s API
Learning opportunityLarger learning opportunity because you are piecing together disparate partsSmaller. It’s ready made and software will be the biggest learning opportunity here
ExtendibilitySince you built it, you can change the LCD screen, add more buttons, add LEDs, etc.Not much unless you want to rip a complete system apart.

Creating the Pong-like game on the Picosystem vs DIY system

A curious experiment of mine involves understanding how much effort it’ll take to develop a game using the Picosystem versus doing it from scratch.

In order to compare the two systems, I will be building a one-player Pong-like game on both YouMakeTech’s DIY system and the Picosystem.

The game’s premise is simple. It’s a one-player Pong-like game that gives you 10 points every time your ball bounces off the paddle. If it falls to the bottom of the screen, you get a “Game Over” message.

Creating the game on both systems follows a simple workflow that all leads to Thonny.

You’d need to flash MicroPython onto the Pico and then you will use Thonny to code your program. 

The MicroPython that you’d flash on the Picosystem is different from the official MicroPython UF2 file, so make sure you’re flashing the right one because the Picosystem will run on the official MicroPython release. It just won’t work as intended.

Now, let’s look at some fundamental differences between the two. I am excluding game logic here and only comparing differences in hardware-software interaction and programming patterns.

You can see YouMakeTech’s code here.

First difference: hardware code

Things are very “raw” with the DIY route. Here’s some code to initialize the display, GPIO and buttons that you won’t need to do with the Picosystem:

from machine import Pin, PWM, I2C,
from ssd1306 import SSD1306_I2C

# Buttons
up = Pin(2, Pin.IN, Pin.PULL_UP)
down = Pin(3, Pin.IN, Pin.PULL_UP)
left = Pin(4, Pin.IN, Pin.PULL_UP)
right = Pin(5, Pin.IN, Pin.PULL_UP)
button1 = Pin(6, Pin.IN, Pin.PULL_UP)
button2 = Pin(7, Pin.IN, Pin.PULL_UP)

# Buzzer connected to GP18
buzzer = PWM(Pin(18))

# OLED Screen connected to GP14 (SDA) and GP15 (SCL)
i2c = machine.I2C(1, sda = Pin(14), scl = Pin(15), freq = 400000)
oled = SSD1306_I2C(SCREEN_WIDTH, SCREEN_HEIGHT, i2c)

Second difference: Picosystem’s API

If you are writing code on the Picosystem, you’d have to write within its system.

In YouMakeTech’s example, all game logic is encapsulated within a while True loop. This includes button interaction, collision detection and drawing to the screen.

In the Picosystem, you are required to write within three functions – init(), update() and draw().

In my code, all the game’s logic is written in update() including collision handling and D-pad interaction.

In a simple Pong game, there are a few functions from the API that I used that made things a bit easier:

intersects(x1, y1, w1, h1, x2, y2, w2, h2)  is probably the biggest help here. You’d pass the coordinates and sizes of the two squares and it will return true if there’s an intersection. In this case, the two rectangles are the ball and the bar (a.k.a. paddle). The shortcoming of the intersects() function is that it doesn’t detect which side the collision happened on, so I had to write extra code to deal with collisions on the side of the bar.

The Picosystem’s API will really shine as you develop more complicated games, given that it already has a method for framebuffers, audio output, blending, etc. 

Code for Pimoroni Picosystem Pong-like game

#bar_pos_x = pixels from left, e.g. 0 from left
bar_pos_x = 50
#bar_pos_y = pixels from top, e.g. 100px from top
bar_pos_y = 100
BAR_WIDTH = 30

LENGTH_CONSTANT = 5

ball_speed = 1
ball_pos_x = 10
ball_pos_y = 10
ball_dx = 2
ball_dy = 2

score = 0
game_over = False

def update(tick):
    
    global bar_pos_x
    global bar_pos_y
    global ball_pos_x
    global ball_pos_y
    global ball_dx
    global ball_dy
    global ball_speed
    global score
    global game_over
    
    def reverse_ball_dx():
        global ball_dx
        ball_dx = ball_dx * -1
        
    def reverse_ball_dy():
        global ball_dy
        ball_dy = ball_dy * -1
    
    ball_pos_x += ball_dx
    ball_pos_y += ball_dy
    
    if button(LEFT) and bar_pos_x > 0:
        bar_pos_x -= 1
    
    if button(RIGHT) and bar_pos_x < 120 - BAR_WIDTH :
        bar_pos_x += 1
        
    if ball_pos_x <= 0 :
        ball_pos_x = 0
        reverse_ball_dx()
        
    if ball_pos_x >= 120 - LENGTH_CONSTANT :
        ball_pos_x = 120 - LENGTH_CONSTANT
        reverse_ball_dx()
        
    if ball_pos_y >= 120 - LENGTH_CONSTANT :
        game_over = True
        
    if ball_pos_y <= 0:
        ball_pos_y = 0
        reverse_ball_dy()
        
    if intersects(bar_pos_x,bar_pos_y,BAR_WIDTH,LENGTH_CONSTANT, ball_pos_x, ball_pos_y, LENGTH_CONSTANT,LENGTH_CONSTANT):
        
        reverse_ball_dy()
        score += 10
        
        #main intersection of ball and bar. if they intersect, check if they are intersecting on the sides.
        #if not on sides (i.e. on top) reverse Y direction. Or else, reverse X direction.
        if intersects(bar_pos_x,bar_pos_y,1,LENGTH_CONSTANT, ball_pos_x, ball_pos_y, LENGTH_CONSTANT,LENGTH_CONSTANT):
            
            #intersecting on left
            
            reverse_ball_dx()
            ball_pos_x -= 2
            
        if intersects(bar_pos_x + BAR_WIDTH,bar_pos_y,1,LENGTH_CONSTANT, ball_pos_x, ball_pos_y, LENGTH_CONSTANT,LENGTH_CONSTANT):
            
            #intersecting on right
            
            reverse_ball_dx()
            ball_pos_x += 2

        
def draw(tick):
    
    if game_over:
        pen(0,0,0)
        clear()
        pen(15,15,15)
        text("Game Over", 35, 60)
        
        
    else:
        pen(0, 0, 0)
        clear()
        pen(15,15,15)
    
        #draw bar (paddle)
        frect(bar_pos_x,bar_pos_y,BAR_WIDTH,LENGTH_CONSTANT)
    
        #draw the ball
        frect(ball_pos_x, ball_pos_y, LENGTH_CONSTANT,LENGTH_CONSTANT)
        text(str(score), 80, 20)
    
start()

Got a game to recommend?

If you have a game for the Raspberry Pi Pico, leave a comment below with a URL.

And if you want to check out our Paragon Projects series – go here.

1 Comment

  1. Mt on April 15, 2024 at 12:06 am

    does the pimoroni system have code to allow you to use an external accessory/device like a small fpga to enhance performance?

Leave a Comment