-
Micro:Gamer is now available on Tindie!
01/31/2019 at 21:07 • 0 commentsThat's it, I don't have much more to say :)
A couple months ago, given the feedback I received on the project, I decided to order a batch of 20 Micro:Gamer from Seeedstudio. They are now available on Tindie.
The hardware is 99% the same as revision B, I only moved some components by a few millimeters and added more decoration on the silk screen. Also the PCB is now red!
On the software side, the Micro:Gamer library is integrated in the Arduino library manager. So it is even more easy to start programming.
https://www.tindie.com/products/Fabien-C/microgamer/ -
I'm giving away 4 Micro:Gamer boards!
05/16/2018 at 21:43 • 5 commentsI just received the first batch of Micro:Gamer rev-B from SeeedStudio. It is the first time I have a design made in series, a very small series but a series nonetheless :)
There's a few changes in the design, the first one being the SMD version of the micro:bit connector which allows for a better looking board. I also added a power slide switch and slightly moved some components.
As stated in the title of this post I'm giving away 4 of the boards. I have no use for 5 so if you have a cool idea for a game or feature that you want to try, I will be happy to send one to you (depending on the how much it costs, I might ask you to pay for shipping). Contact me using the private messages if you are interested.
-
TODO list update
04/22/2018 at 19:41 • 0 commentsI think it is time to do an update on the DODO list:
- [DONE] Try audio support with the buzzer
- [DONE: board in production] Some improvements to the PCB (on/off switch, button position)
- [DONE] Add an API for persistent storage (highscores, player data)
- Add an API to read the accelerometer and magnetometer of the micro:bit
- [DONE] Improve performance of screen data transfer
- Design a case for 3D printing
New item:
- Create an example game/project that demonstrate all the features
-
synchronous frame buffer transfer and double buffering
04/18/2018 at 20:59 • 0 commentsOn the Micro:Gamer, the OLED screen is controlled via an I2C bus.
The screen resolution is 128x64, that is 8192 pixels. Since the screen is monochrome, there is only one bit per pixel so the frame buffer size 1024 bytes. We have to transfer all those 1024 bytes over I2C to refresh the screen. Lets calculate how much time it takes.
I2C transfer time
First we have to count the number of bits in an I2C transfer.
- 1 start bit
- 8 address bits
- 1 address ack bit
- 1 stop bit
- 8 bits + 1 ack bit for each byte of data we transferSo the total number of bits for a transfer of N data bytes is:
bits (N) = 1 + 8 + 1 + N * (8 + 1) + 1
or
bits (N) = 11 + (9 * N)
Then we can calculate the speed of the transfer by dividing the number of bits by the speed of the bus in bits per second.
The micro:bit is fitted with an nRF51 microcontroller. On the nRF51 the maximum speed of the I2C controller is 400k bits per second, so the transfer time is:
transfer_time (N) = bits (N) / 400000
For examples, transferring 10 bytes will take
transfer_time (10) = (11 + (9 * 10)) / 400000 = 0.00025 seconds
or
0.25 milliseconds
There are more things to take into account for an accurate estimate of the transfer time, but this is a good approximation.
Arduino library I2C transfer
Now that we have the formula, let's see how much time it takes to transfer the 1024 bytes of our frame buffer.
The Arduino library limits the number of bytes per I2C transfers so the frame buffer has to be sent in multiple transfers. The driver I used, from Adafruit, sends 16 bytes of frame buffer per transfer with an extra byte to specify that we are sending data for the frame buffer, which means 64 transfers of 17 bytes.
So the total time it takes to send the full frame buffer is:
64 * transfer_time (16 + 1) = 26.2 milliseconds
The Arduino library driver is implemented using the polling technique. The CPU just continuously waits in a loop until it can send the next byte. So during the transfer time, the CPU is doing almost nothing.
If we want to run a game at 30 frames per seconds - one frame every 33 milliseconds - a transfer time of 26.2 milliseconds means that 80% of the CPU time will be wasted in I2C transfer. This is not ideal...
Asynchronous frame buffer transfer
The solution to this it to let the CPU do something else during the frame buffer transfer, and it can be done with interrupts. So I implemented an interrupt based I2C driver.
The CPU sends the first byte on the I2C bus and then continues its work, typically it will start to compute the new state of the game and render the next frame.
When the I2C controller is ready to send the next byte, an interrupt is triggered and the CPU will temporarily stop its normal operation to send the byte.
As a result, there's more CPU time available to execute the game code, allowing more complex games to run on the Micro:Gamer.
Double buffering
One potential problem with asynchronous frame buffer transfer is that, as the CPU continues to execute the game code, it can override the frame buffer in the middle of the transfer. This can cause glitches on the display, similar to the rolling shutter effect of digital cameras.
Again there is a solution for that, double buffering! Using two frame buffer instead of one, the CPU can edit frame buffer A while sending frame buffer B, and then it is the opposite, CPU edits frame buffer B while sending frame buffer A. Of course this means that we have to allocate one more frame buffer so it has a significant impact on memory usage.
-
Playing sounds
03/15/2018 at 16:59 • 1 commentAfter the persistent data storage, the next important feature for me was sound.
There is a small buzzer on the Micro:Gamer board which means it can play a single note at a time. It is enough to play little tunes and some sounds effect as shown here:
This time again, I re-use the Arduboy libraries to provide compatibility with the existing games. -
"Memory Card" (Non-volatile memory)
03/14/2018 at 01:28 • 0 commentsMost of the games I ported from Arduboy to the Micro:Gamer use EEPROM to save high score or game state when the console is powered off. I think this is must have feature for a game console so I implemented it for the Micro:Gamer.
There is no EEPROM on the micro:bit board and I don't want to add it as an extra component on my hardware design, so I had to use the flash memory inside the micro-controller.
The interface to use the flash as persistent storage is provided by the MicroGamerMemoryCard class. This class uses two different memory areas:
- The first one is a 1k bytes page in the flash memory, this is where the data will be stored permanently. The reason for a fixed size of 1k bytes is because flash memory have to be erased/written by pages of 1k.
- The second memory area is the temporary RAM buffer. This is where the program will read/write the data before saving it permanently in the flash page. Since there is not a lot of RAM available, the program can decide to have a temporary RAM buffer that is smaller than 1k.
Here is an example of how it looks like in the code:
// Create a memory card of one 32bit word MicroGamerMemoryCard mem(1); // Load the content of the flash page to the temporary RAM buffer mem.load(); // Read a value from the temporary RAM buffer if (mem.read(0) != 42) { // Write a value to the temporary RAM buffer mem.write(0, 42); // Permanently save the RAM buffer into flash memory mem.save(); }
And here is a demo with the game Micro City:
-
The idea and the first prototype
02/25/2018 at 18:37 • 1 commentLike most of you I suppose, I love the micro:bit. It is very affordable, available everywhere, quite powerful and it even has an integrated programming/debugging probe. However, one “disappointing” aspect in my opinion is the 5x5 LED matrix. It can barely display text and cannot be used for anything beyond very very simple “games”. A couple months ago I saw the Adafruit OLED Bonnet for Raspberry Pi and I thought it would be cool to have something similar for the micro:bit, so I decided to give it a try.
One of the design choices for the Micro:Gamer is to embrace the micro:bit edge connector. There are a good number of disadvantages with this connector, it’s big, there is no SMD version (at least I couldn’t find one). But for this project in particular I think it is great because it mimics the cartridge of a retro console like the GameBoy. If you have more than one micro:bit you can program different games and swap between them.
For the batteries, my first idea was to not include any on the board (keep it simple), but then it’s not really a portable device anymore… The next choice was between a coin cell battery and 2xAAA. I decided to use the AAAs because - even if they are bigger - it is easy to find rechargeable ones.
For the software I use the Arduino IDE and a modified Arduboy2 library. Since the Arduboy and Micro:Gamer have the same screen and buttons, it is very easy to port games from the Arduboy to the Micro:Gamer (I already did 6). I will maybe experiment with Python support and probably Ada as well.
The next steps for me are:
- Try audio support with the buzzer
- Some improvements to the PCB (on/off switch, button position)
- Add an API for persistent storage (highscores, player data)
- Add an API to read the accelerometer and magnetometer of the micro:bit
- Improve performance of screen data transfer
- Design a case for 3D printing
That’s it for the first project log. Let me know in the comments what you think about this project.