A handheld game console programmable with (Micro/Circuit)Python.

Similar projects worth following

A small game console directly programmable in Python. I always wanted to make this, and after my work on #PewPew FeatherWing I finally decided that I'm ready.

The first version may be a bit of a stretch — I tried to make it as small as possible, fitting in the 5x5cm limit of PCB manufacturers, so that it will be cheap to make the PCBs. Using the cheap ST7735 TFT display, and a cheap ATSAMD21E chip. I also tried to put all the components on one side of the board, but failed with that — the power and reset switch had to go on the back, as well as the buzzer.

Of course the hard part is writing a game for this, which may be a bit challenging with the amount of ram this thing has, but I have a couple of ideas.

  • The Case for a Case

    Radomir Dopieralski11/11/2017 at 16:53 0 comments

      Just before going on a two week vacation, I decided to try and see what I can do in terms of a case for this device. Why do I even need a case? Well, there are two reasons:

      1. To protect the glass (but not gorilla-glass) screen from scratches, so that I can carry it in my pocket,
      2. To protect the battery both mechanically and electrically from random objects in that pocket.

      It's connected with the fact that I want to use a bigger LiPo battery than the 40mAh button cell battery I use right now.

      With those goals in mind, what are my options?

      1. Use an existing, commonly available container of roughly the right size.
      2. Make the case out of layers of laser-cut transparent acrylic.
      3. 3D-print it, possibly adding laser-cut transparent acrylic as screen protection.

      To see which of those options would be the best, I exported the PCB to Inkscape and prepared a model of the device, with all buttons, switches, sockets and the screen marked.

      Then I tried to fiddle with it a bit, trying to come up with the layers for the laser-cut case. I immediately stumbled on a problem: the power switch (and also the reset switch, but that one could only have a hole to be pressed with a paperclip) only sticks out of the PCB very little — about 1mm. That means that the wall of the case can't be thicker than that, or that it needs to add some kind of an extension of the switch's knob. The USB port has a similar problem, but fortunately in this case it's more like 2mm, so it's not so bad.

      There is also another problem if I decide to go for thin walls — the front panel needs cutouts for the buttons, and those pretty much touch the edge of the PCB, making this arrow-shaped corner of the panel, where the only mounting screw is, very fragile and easy to break off...

      That's the status for now. I will probably keep thinking about this during my vacation, and will try something when I get back.

  • Hardware Version 4 and Sound

    Radomir Dopieralski11/09/2017 at 20:49 0 comments

    The PCBs arrived from @oshpark today (I can't thank them enough for all the help I'm getting from them, including the coupons and fast shipping), so time to assemble the next hardware version. This time there were no surprises, the board seems to work.

    This new version has the buttons spaced a bit farther apart from each other, which makes assembly much easier. It also has an audio amplifier and a tiny speaker. Since I'm still waiting for the 4x4mm speakers to arrive, I used a bigger SMD speaker for now for tests, and it's pretty loud! The small speaker will probably be much quieter, but I think it will still be good enough.

    I still need to connect the battery and test the charging circuit, but I don't expect much trouble there — the first version has that working well.

  • Built-in Sprites

    Radomir Dopieralski11/06/2017 at 20:10 0 comments

    The RAM memory is quite limited on the SAMD21, which means that you can only load about 4 or 5 banks of graphics at once. But there is some free flash memory in the custom CircuitPython firmware, so we can put some stock graphics in there. So I've been working a little on drawing the character sprites for that:

    The colors are all funny, because I tried to make them distinct, so that you can easily re-color the sprites by custom palettes (a palette is only 32 bytes, while a bank is 2048). I'm trying to standardize the color positions in the palette too, so that you can use the same palettes for recoloring multiple banks.

    The characters are mostly inspired by the GameBoy, SNES and NES classics, though they are not exact copies of any game in particular. They should retain the general feel, though.

  • Extra Characters

    Radomir Dopieralski11/05/2017 at 17:35 1 comment

    Initially, my font file contained only 96 characters, ignoring the "control characters" that appear in the first 32 entries of the ASCII table. I realized that this is a waste, and decided to extend my font file to cover all 128 characters, and put some special things in the first 32 glyphs. Here's what I came up with:

    The first four are arrows — always useful. Then there are icons for the two fire buttons this console has — useful when asking the player to press them. Then there is a number of random stuff that you might want to display on a status bar or in the inventory. Finally, some extra punctuation.

    I'm not sure how useful this will turn out to be and if I wouldn't be much better off if I used that space for accented characters from a few European languages — but I can never cover all the languages anyways. In the worst case I can change it, and the users can always provide their own custom fonts too — there is a script in the repository for generating the script data from a BMP file.

  • Text Layers

    Radomir Dopieralski11/04/2017 at 19:08 0 comments

    Today I spent practically whole day coding, and added support for text layers to the tile engine. Behold:

    Initially I didn't want to add another kind of layer just for this — it would have to be quite different than the grid layer, as the squares would be 8x8 pixels and the tile selection would need to be a whole byte, not 4 bits, plus I only need 4 colors in the font, so 2 bits per pixel...

    So I got this idea: what if I make it a standard grid layer, with 16x16 tiles, but then generate a bank that has the text rendered on the tiles, and just display that. I quickly coded the proof of concept for that, and it worked, except it was horrendously slow and used a lot of memory.

    So I decided to go for a new layer type after all. Since I only use 128 charcters from ASCII, I made the highest bit switch between two parts of the palette — so I can have text in two colors. I'm also not using the 32 control charcters at the beginning of ASCII right now, but I could put some extra characters in there, things like symbols for weapons and armor, arrows and buttons, HP and MP, hearts, stars, cat paws, etc.

  • The Stage Library

    Radomir Dopieralski11/03/2017 at 20:47 0 comments

    The hardware is just a very small part of a project like this one. Of course in the game console the most important part are the games that you can play on it. And the most important part for the games is the development environment and libraries available for the game makers. The better and the easier to use the libraries, the more games you can make with the same effort, and the better they are. So software is actually more important here.

    I'm basing my software on the CircuitPython project, which is itself based on MicroPython. But I need to add the parts that are specific to game development to it. One of the most important parts in this case is the tile and sprite engine. There is only so much you can do by drawing pixels directly on the screen, after all.

    The library for that is now published at and the part of it that needs to be compiled into CircuitPython is waiting to be merged into the main repository — you will still need to build your own firmware to enable it, as it's not generally useful on other boards, of course.

    This is just the first version, that supports tile grids and sprites. There is a lot more to add there — advanced dirty rectangles handling, collisions, text layers, menus, etc. I will work on that gradually, as I'm working on the example games.

  • Delays are Inevitable

    Radomir Dopieralski11/03/2017 at 01:16 0 comments

    Both of my prototypes stopped working. Just like that. And that happened just as I was going to show them off in Adafruit's show-and-tell. Oh well, bad luck I guess. I decided it must be the flex ribbon connecting the displays to the PCBs, and I re-did the connection with my soldering iron, inspecting it carefully for shorts, etc. They started to work again. For a moment. Then the newer one stopped responding completely, and no amount of re-soldering helped. So I de-soldered the display from both, and put the one from the old prototype on the new one. It worked for two hours, and then stopped again. This time I decided it must be broken traces on the flex ribbon, because I bent it too much. Since I don't have any more displays with 14 pins, but I have a couple of modules with the same display but with a different connector, I decided to continue work by using one of those modules and a Trinket M0.

    The displays stopped working with the Trinket too, even though I didn't touch the flex ribbon or the connections at all.

    So I began to poke at the non-working display, trying slower SPI speeds, different commands, etc. At some point I got it to work — I was sure then that the problem is not with the display module, but with my code.

    Turns out that the display working or not was a completely random thing. The problem is that some of the SPI commands, such as reset or wake up from sleep, require a lot of time for the display to perform, and delays are needed. I added those, and also lowered the SPI speed during the initialization sequence, and it works on the Trinket every time. So I compiled the firmware for the "dead" prototype, uploaded it — and it works too! I bet that when I solder the other display it will also work.

    One more obstacle out of the way.

  • Another PCB

    Radomir Dopieralski10/30/2017 at 23:53 0 comments

    Today I received a big batch of PCBs from OSHpark, and one of those was the next revision of the µGame PCB. There is a number of improvements there:

    • The PCB is wider (42x50mm) giving me more room, but still fits in the 5x5cm limit of many board houses.
    • The buttons are spaced a little wider.
    • I used non-clicking buttons this time.
    • The only parts on the back side are the battery and the speaker.
    • I used a smaller reset button.
    • The active part of the display is centered on the PCB.
    • There are footprints for 2 different battery holders.
    • An analog pin connected to the battery through a voltage divider, for monitoring charge levels.
    • Two of the button pins are swapped (left and down).

    Immediately after assembling the board I realized one more change: the USB 5V rail is connected directly to GND. Oops. That happened when I moved the button pads around, and made one of them touch the 5V trace. Fortunately cutting the trace and replacing it with a wire fixed it, and there was no damage.

    But that means I need yet another version soon. To not waste my OSHpark coupons, I quickly tested the last feature of the board — sound. This one has a piezo speaker directly connected to the DAC pin. As you can expect, it's really quiet. Hmm, ok, that means that the next version will need a magnetic speaker and an amplifier. But where can I fit them?

    After taking some measurements of the new boards, I found a solution. I moved the fire buttons further from the edge (they aren't very comfortable they way they are now), and put the audio circuit in the freed space. It's not even very cramped — each component has lots of space around it. Of course the tiny 4mm speaker won't have great quality, but should be better than the piezo, and now I only have the battery on the back!

    I need to finish a couple of other boards, and then I'm making another order.

  • The Power of Plain C

    Radomir Dopieralski10/29/2017 at 14:30 1 comment

    I was expecting a considerable speedup from rewriting the whole rendering code as a C module and compiling it into the CircuitPython firmware, but a 50x improvement is much better than anticipated. I was afraid that I will have to limit myself to just a few sprites on the screen at once, and just one or two layers of tiles. But with this speed, there is no such problem. Of course, it will still slow down to around one frame per second if I fill the whole screen with animated sprites, but I think even ¼ of screen is already workable.

  • First Walking Sprite

    Radomir Dopieralski10/29/2017 at 00:26 0 comments

    I'm probably much more excited about this than I should be...

    Traditionally, the colors are completely wrong in the video — they are much nicer in reality.

View all 20 project logs

Enjoy this project?



ia wrote 10/29/2017 at 16:17 point

is possible to programing it using SDL library?

  Are you sure? yes | no

Radomir Dopieralski wrote 10/29/2017 at 18:29 point

No, the microcontroller is much too small for that.

  Are you sure? yes | no

Malik Enes Şafak wrote 10/29/2017 at 15:26 point

Is your screen 160x128? You can use new gamebuino meta libraries (not published yet) for this console. Same screen resolution, same microcontroller. Also check Pokitto, Gamebuino and Arduboy libraries. They all open source and you can learn lot of thing from these consoles. I really like this idea. If you will sell or publish this console open source please let me know. I really like to get one. 

  Are you sure? yes | no

Radomir Dopieralski wrote 10/29/2017 at 18:34 point

Thank you. I will definitely look at their code once it becomes available — what I have so far are tricks I picked up from old platforms, like Gameboy or NES. I expect they will be using similar techniques.

I think that gamebouino libraries won't work for me, because while the display has similar resolution (128x128 for mine) and number of colors, it's connected differently — mine uses SPI, their is most likely connected using parallel protocol — otherwise they wouldn't be able to achieve the speed they are claiming.

I also really want this to be easily programmable in Python, and all the consoles you listed use C, which admittedly is easier performance-wise, but not in the speed of development.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates