Stage, a Tile and Sprite Engine

A library for MicroPython for drawing tiles and sprites on a RGB SPI screen.

Similar projects worth following

This is a MicroPython library that provides the means for drawing sprites with tiled background on 16-bit SPI-based displays. It consists of a small part written in C that needs to be compiled into the firmware, and the rest written in Python, usually also included in the firmware as frozen modules.

This library was originally created in CircuitPython for #µGame, but has since been ported onto other platforms.

  • M5Stack Support

    de∫hipu08/01/2019 at 20:02 0 comments

    I added support for the buttons on the game face of M5Stack, (it's very similar to my #D1 Mini X-Pad Shield, I basically just had to change the numbers for the button maping, the I²C address, and negate the output). Together with the automatic 2× scaling, it means you can play the µGame games on it now (and, what is more important, easily make your own).

    What I don't like is the noise from the speakers — for some reason that happens only when the face is connected, and not on USB — perhaps grounding issues? There is no sound from the game, because so far MicroPython doesn't support it (though technically it's possible, someone just needs to write the code).

  • Scaling

    de∫hipu08/01/2019 at 14:00 0 comments

    One problem with supporting devices other than #µGame is that they use different displays. The 160×128 version of ST7735 is not that bad — there is just a strip of 32 unused pixels — but the ILI9341 is almost twice as large, with 320×240 pixels. So you either play the game on a tiny postage stamp, or you adapt it to the platform — but the 16×16 tiles and sprites are still too small.

    That's why I just added a "scale" optional parameter to the Stage object in the library, that allows you to scale the display 2× or more, giving you back the chunky pixels we so love.

  • Proper Repository

    de∫hipu08/01/2019 at 13:53 1 comment

    While the CircuitPython port of this library is being used both on the #µGame and a number of Adafruit boards (see #PyBadge Hacking), and is included in the official repository, the MicroPython port is not as well supported. In fact, if you wanted to use it on MicroPython, you were up for a bit of a challenge, figuring out what files to modify in order to have the C portion of the library compiled in your firmware. But that is no more.

    Recent releases of MicroPython have a primitive but workable way for adding third-party modules, and I finally took the time to follow that guide and make a proper repository for the MicroPython version of Stage, available now at The documentation is still lacking, and the only fully working example is for a D1 Mini with the #D1 Mini X-Pad Shield and an ST7735 display, with some partial support for M5Stack, but I plan to extend that to a couple of third-party devices, including OdroidGo, Meowbit, and maybe even Pokitto.

  • Build for ESP8266

    de∫hipu01/30/2019 at 23:17 0 comments

    If you want to try playing with this, but don't feel like compiling your own MicroPython firmware, I prepared a build for the ESP8266 with the #D1 Mini X-Pad Shield and an ST7735 display module:

    I also updated and rebased the "stage" branch, here:

  • MicroPython Branch

    de∫hipu01/08/2019 at 15:05 0 comments

    I just realized that while this project page links to the repository with the plain python portion of the library, the portion that is written in C is harder to find. So here it is:

    The branch is a little bit dated, since I didn't upgrade it in a while, but if you look at the three last commits, you will see all the required code. It's not much, just enough to make the plain python version fast enough. Enjoy!

  • This Just Arrived

    de∫hipu06/29/2018 at 11:55 0 comments

    The ODROID GO is here:

    For now I just tested the default firmware, which contains all the emulators. It works as advertised, though I have to say that the buttons feel rather cheap — much worse than on the #µGame. The sound is super-loud and kinda annoying, but you can mute it.

  • More Players

    de∫hipu06/20/2018 at 17:37 0 comments

    Looks like my decision to abandon #µGame Turbo and instead focus on improving this library and making it work better on the original #µGame might have been right. New devices are popping up left and right. Adafruit has recently leaked some information about the Arcade FeatherWing they are working on, and now @Jarrett alerted me about a new device made by Odroid:

    From the point of view of hardware, it uses the same stuff as the M5Stack, so this library should already work on it. I ordered one ($48 with shipping for me), and of course will attempt to get my games to run on it. Still a bit more than the $11 I paid for the TTGO 1.0, but this one has the button and a case already. We will see how good those buttons are...

  • Support Larger Resolutions

    de∫hipu03/11/2018 at 18:45 0 comments

    After a bit of work, I can now use the whole 320×240 screen of the M5Stack — unfortunately I had to change the C sources a bit, to use 16-bit variables for the coordinates. That was a lack of foresight on my side, but it's now fixed and the pull requests for the change are up.

    I also optimized the sprite drawing routines a little bit, and fixed a bug that would sometimes make the library fail to refresh some sprites. You can now also use floating point values for the sprite positions, and they will be rounded during the rendering.

  • Porting to M5Stack

    de∫hipu03/10/2018 at 23:39 0 comments

    One of the nicer MicroPython-capable boards with integrated color display out there is the M5Stack. It's a bit pricey, but you get a really nice enclosure, and if you get the "faces" thing, even several keyboards. So I decided to try porting the Stage library to it first. After a day of work, mostly spent writing the driver for the ILI9341 display, I ended up with something like this:

    The small square area is the 128×128 pixels for which the library was originally written. Of course with a bigger screen you can make games that use a larger area. But the rendering doesn't look quite right. After half a day of debugging, I considerably simplified the driver, but I didn't solve the issue until I tried to reduce the speed of the SPI clock down to 40MHz. I have forgotten that ESP32 has really fast SPI, which apparently this display can't handle reliably. With that, I have proper rendering:

    Now, the buttons. The keyboard attachments all use an ATmega328p chip working as an I2C slave on address 0x08 and reporting the pressed keys as a simple bit mask — pretty much like #D1 Mini X-Pad Shield or #LAMEBOY - another ESP12 handheld. That's a problem, because I have to poll the bus, and if I do it only once a frame, I might lose keypresses. For now I used the naive code that just returns the current state of the buttons. I will need to see if I can use a timer to have a proper button handling, with a buffer and all that.

    I also didn't explore the sound yet. The ESP32 has a DAC, and the M5Stack has an amplifier and a speaker — you can tell, because you can hear every single GPIO toggle in that thing. But there is no ready-to-use functionality in MicroPython to simply play WAV files in the background, like there is in CircuitPython, so I might need to do some work there.

View all 9 project logs

Enjoy this project?



Makerfabs wrote 03/12/2018 at 03:48 point

An 3D printer enclosure makes the projects friendly to none-hardware engineers...

  Are you sure? yes | no

de∫hipu wrote 03/12/2018 at 09:50 point

Definitely! Also safer to put in your pocket, etc. 

  Are you sure? yes | no

Ted Yapo wrote 03/10/2018 at 23:43 point

How fast is it?  I guess I could figure it out by the number of bits and SPI speed, but it's easier if you tell me :-)

I assume you update just the dirty areas of the display?

  Are you sure? yes | no

de∫hipu wrote 03/11/2018 at 00:03 point

ESP8266 could do the same speed as the MCU clock, so 80MHz without overclocking, and 160MHz with. The ESP32 has a 240MHz clock, but I'm not sure what the SPI clock limits are. Well, HSPI is limited to 26MHz in full-duplex mode, but VSPI doesn't seem to be.

Yes, I only update the dirty areas, that's how I managed to make it work with 24MHz SPI on the µGame. Of course that mans no scrolling, but the ILI9341 has hardware scrolling in one direction, so I might be able to make use of that.

  Are you sure? yes | no

Josh Lloyd wrote 05/01/2019 at 00:03 point

I believe the SPI Baudrate limit on the ESP32 is 80MHz if you're lucky, I've had the chip fail to perform at 80MHz, and getting 40MHz instead. This applies to the QSPI also that the Flash and PSRAM are on. 

  Are you sure? yes | no

de∫hipu wrote 05/01/2019 at 19:13 point

Before you hit the limitation of the ESP8266, you hit the limitation of the display itself. I'm driving it at 24MHz SPI, but that is already outside of its official limit of 20MHz for writes.

  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