Recent Blogposts of Programming

Announcing the Commencement of Portable Game Console Project

Photo of the portable game console

If you know me personally, you'd probably heard of this portable game console. I have been working on this project for almost two months! I decided not to blog about this until now because I wasn't confident about the completion of this project. My main concern was the hardware design of my portable game console isn't going to work at all. Now that I've tested and proven that it's possible to do whatever I need to for this project. Therefore, it's now the right time to announce this project in this blog! :)

Introducing Portable Game Console Project! It is a minimalist, low-cost portable game console. It isn't an emulator of existing game console. It's a brand new game console system. It doesn't have a name yet. Until it's getting named, I'll just call it portable game console.

Motivation

It's mostly a "because I can" project. I aim to learn stuffs from this project, including drawing PCB board, electronic design, a little bit mechanic design by drawing the case of the console, embedded programming, etc.

This is an open source project. There're already many existing game consoles. I don't think anyone would be interested in getting this one. Commercialization is out of the question. Instead, upon the completion of this project, I plan to do free giveaway of this console (and hopefully someone would be interested in developing games for this console). Waste all of the time! Lose all of the money! Hooray! :P

Feature

  • Open source (after the completion of this project)
  • Low-cost
  • Minimalist - single color LCD, 1-bit audio.
  • Open design - Anyone can build their own. The software will be made open source
  • Supports loading games from SD card
  • Cross platform compatibility of games - the API will be ported so that PC, and hopefully web browsers can run the games developed for this console

Specs

  • Microcontroller: STM32F030F4P6
  • Graphical interface: Nokia 5110 LCD. 48x84 monochrome
  • Audio playback device: Buzzer
  • Input: 6 push buttons. Left, right, up, down, A and B.
  • microSD card slot (may be replaced with SD card slot in the future. I haven't decided yet)

Development Flow

  1. [Done]Hardware design
  2. [Done]Purchase prototyping material
  3. [Done]Solder a prototype of the circuit on a perfboard
  4. [WIP]Developing the API
  5. Developing Games, mainly for testing the API
  6. Drawing PCB
  7. Making the container case for the game console. Probably by 3D printing
  8. Port the API to PC platforms and possibly browser (Optional)
  9. Small scale production and giveaway

Hardware Wiring

I haven't drawn a schematic diagram. So I'd just write down the wiring of STM32F030F4P6 to other hardware here. It's enough for anyone to reconstruct the circuit

  • BOOT0 -> GND
  • PF0 -> Button Up -> GND
  • PF1 -> Button Left -> GND
  • NRST -> Vcc
  • V -> Vcc
  • PA0 -> Button Right -> GND
  • PA1 -> Button Down -> GND
  • PA2 -> Button A -> GND
  • PA3 -> Button B -> GND
  • PA4 -> Current-limiting resistor -> Buzzer -> GND
  • PA5(SPI1_SCK) -> LCD_SCK and SD_SCK
  • PA6(SPI1_MISO) -> SD_MISO
  • PA7(SPI1_MOSI) -> LCD_Din and SD_MOSI
  • PB1 -> LCD_CE and -parallely-> transistor to invert the signal -> SD_SS
  • VSS -> GND
  • V -> Vcc
  • PA9 -> LCD_DC
  • PA10 -> LCD_RES
  • PA13(SYS_SWDIO) -> JTAG for programming and debugging
  • PA13(SYS_SWCLK) -> JTAG for programming and debugging

Here's how the connection looks like on the prototype hardware:

Photo of the back of the portable game console, showing the soldering trace on perfboard

Software Development Environment

I've never used most of these tools and software before this project.

  • Compiler: gcc ARM cross-compiler
  • IDE: SW4STM32
  • Code template generator: STM32CubeMX
  • Library: STM32F0 LL driver (uses less Flash memory compared with HAL driver)
  • USB-to-JTAG adapter
  • Hardware prototype of the portable game console

OS Design

STM32F030F4P6 is the microcontroller of this portable game console. It's a low-end ARM Cortex-M0 microcontroller.

It has 4kB of RAM and 16kB of Flash. In our design, the flash memory is split into two parts. The first part is the bootloader. The second part is the application (game). The bootloader contains the implementation of the API for accessing the LCD, sound system, buttons and SD card. The game is a playable that calls those API functions to access the hardware function of the game console.

The RAM is also split into two parts. A small part is exclusively used by the API. The other part is available for the application.

In addition to that, the bootloader will show a menu for the user to pick a game stored in the SD card. When the game is chosen, self-flashing will be performed to the application part of the flash memory. Then the BX instruction will be called to set the program counter to the starting point of the application, which will caused the game to be launched. There's, unfortunately, no protection of access. Although there's no API for that, it's technically possible for the application to, says, implement their own function to erase the SD card.

The bootloader will probably take 8kB of flash and very small amount of RAM (like 100 bytes).

Implemented API Calls

The API call can be made by using a software interrupt. There's a fixed-address, 8-bytes storage inside the RAM. The API can be accessed by the application by first manipulating the content of the RAM of that address, then trigger a software interrupt. The interrupt EXTI line 15 is used for software interrupt. This design is inspired by int 80h of unix kernel.

Keys Input System

Three functions are available:

  • void keysSetDebouncePeriod(uint8_t milliseconds);
  • uint8_t keysGetPressedState();
  • uint8_t keysGetJustChangedState();

keysSetDebouncePeriod() is used for setting the software debounce period. The longer it is, the slower the reaction time, and less noisy the response is.

For keysGetPressedState() and keysGetJustChangedState(), each bit represent the state of a button.

For keysGetPressedState(), pressed button would have its bit set to 1. The non-pressed one would be 0.

For keysGetJustChangedState(), pressed button that had changed would have its bit set to 1. Otherwise 0. For example, if the keysGetJustChangedState() of a button is 1, and the keysGetPressedState() is 0, that implies that the button was just released. After calling this function, the justChanged state of all buttons would reset to zero.

Sound Synth System

The sound system consists of two identical 1-bit synthesizer. One of them is for sound effect (foreground), another of them is for background music. Only one of them can output sound at one time. Depending on the configuration, it's possible to pause the background music while the sound effect is being played, or have the sound effect played during its effective duration, replacing the part of background music.

The sound synth has the following capability:

  • Playback duration (10 millisecond per step, range: 0-2.55 seconds)
  • Frequency (32-suboctave frequency scale)
    • Frequency sweep control: shape: saw, triangle, bipolar, noise; repeat: yes/no; fast sweep: 1x/256x
  • Duty cycle (Possible value: (1-1/(n^2)) * 100%. n is a value between 0 and 15. Example: n=2 would be 75%)
    • Duty sweep control: shape: saw, triangle, bipolar, noise; repeat: yes/no
  • Fast sweep mode: reduces the duration of each sweep step to 1/4 of both frequency and duty cycle.

In addition, a musical playback format is defined for this game console, which enables the application to play music by calling an API function.

Sound Synth System: Frequency

Piano uses a 12-suboctave scale, which means that each octave is divided by 12 notes.

However, in this game console, a 32-suboctave frequency scale is used instead. It means that each octave is divided by 32 notes. This game console is able to generate more fine frequency compared with piano, mainly useful for sounds effects. Since 32 isn't divisible by 12, some of the piano notes has to be substituted with a close enough frequency. Fortunately, this is not a problem because "Humans can notice a difference in pitch of about 5 to 6 cents" according to a paper by Beatus Dominik Loeffler. For a 32-suboctave system, the maximum error compared with piano note would be 64-suboctave, which is 1/64*100=1.5625 cent of error, which is far less than 5~6 cents. I've also personally listened to a piece of music played on the game console. It sounds good. So the frequency error isn't a problem. :)

During frequency sweeping, the 32-suboctave is further subdivided into 16 frequencies, forming 512-suboctaves. Each step of sweep would increase/decrease the frequency by a 512-suboctave until the final frequency is reached.

The frequency of the sound to be played is 2^(5+n/32) Hz, where n can be any value from 0 to 255.

Sound Synth System: Duty Cycle

Generation of tone requires vibration of audio signal. For a 1-bit synth, the duty cycle determines the duration of the signal to be LOW or HIGH. Let's take a 1000Hz sound wave as an example. It takes 1ms to complete a period. If the duty cycle is 50%, 0.5ms would be spent on LOW, and another 0.5ms would be spent on HIGH. If the duty cycle is 75%, the signal would be LOW for 0.25ms, and HIGH for 0.75ms.

Although this synth is 1-bit synth, it's possible to control the volume of the synth by using duty cycle. That's because the duty cycle affects the RMS value of the waveform. The closer the duty cycle to 50%, the louder the sound is.

The duty cycle can be adjusted (1-1/(n^2)) * 100%, where n can be any value from 0 to 15.

Unlike frequency, the duty cycle sweep does not have any subdivide mechanism.

Sound Synth System: Music Format

The format is simple. It's a mix of command and data. Data starts with a non-zero byte. Command starts with a byte of zero. It has 6 modes. They are STOP, DF, DCF, FULL, FULL->DF, FULL->DCF.

  • STOP: end of music. No more command to be accepted.
  • DF: Two bytes. duration, frequency. Use the previous values for other parameters
  • DCF: Three bytes. duration, initial frequency, final frequency. Use the previous values for other parameters
  • FULL: Seven bytes. duration, init freq, final freq, freq sweep period, init duty cycle(half byte), final duty cycle(half byte), duty sweep period, sweep control flags
  • FULL->DF: Same as FULL. However, after playing this FULL musical note, it'll get back to DF mode
  • FULL->DCF: Same as FULL. However, after playing this FULL musical note, it'll get back to DCF mode

To switch mode, set the first byte (duration) to 0, then set the second byte to the command ID. The command ID for STOP is 0, DF is 1 and so on. Here's an example of a piece of music:

uint8_t musicArray[] = {
0, 4,  //Switch to FULL->DF mode
20, 97, 97, 0, 0x11, 0, SYNTH_FREQ_SWEEP_TRIANGLE|SYNTH_DUTY_SWEEP_REPEAT_ENABLE, //Play a sound with full parameters specification and switch to DF mode
20,102, //Now that we're in DF (duration+frequency) mode. We play a sound in DF mode
65,105, //Play another sound in DF mode
20,97, //ditto
20,105, //ditto
45,102, //ditto
100,97, //ditto
0, 0 //Switch to STOP mode. It's like a NULL character for string.
};

Sound Synth System: API Functions

The following functions are available:

  • void synthPlayOne(bool foreground, struct SynthData synthData);
  • void synthPlayCommand(bool foreground, uint8_t *command);
  • void synthSetFgFreezeBg(bool freeze);
  • uint8_t synthGetStatus();

Sound Synth System: Demonstration

Here's a piece of recorded music generated with the game console by using the music format:

Unimplemented APIs:

  • [Research performed, but not implemented]SD card interfacing system
  • [Research performed, but not implemented]Graphical system
  • Misc (e.g. changing the clock rate, sleep, etc)

Future

I'll continue be developing this game console. It'll probably be completed some time in 2019. I'll update you guys about any progress! :)


Arduino 1602 Snake Game - Snake Game on Alphanumeric LCD!

I'm thinking about making an AVR (non-Arduino) portable game console. I'm evaluating the type of display to be used (including multiple 8x8 LED matrix, graphical LCD, TFT/OLED screen, alphanumeric LCD and combination of them). Then I came up with a weird idea. What if I use a alphanumeric LCD as a graphical LCD? That'd cut me quite a bit of the cost compared with using graphical LCD of the same physical dimension.

I'm a bit bored today. I feel like tinkering around with Arduino and 1602 LCD that has been around in my home. Here's what I've got as a result of hours of boredom. An Arduino-based 1602 Snake Game:

Source Code

Check out the source code in this github repository!

Gameplay

  • Just like other snake games.
  • Controlled with two push buttons. One for turning clockwise, another for turning counterclockwise
  • The length of the snake starts at 4
  • Game field: 16x4 (yes, I split each character into two rows so that you get 16x4 instead of 16x2)
  • The game gets approximately 1.1x faster whenever an apple is eaten.
  • There's no wraping. You die if you hit the wall.
  • If the snake had grown enough to fill the entire game field, you win

Hardware List

The hardware is roughly based on this official Arduino LCD Hello World tutorial, with an addition of two push buttons.

  • Arduino Uno
  • Current-limiting resistor for LCD backlight
  • Potentiometer for LCD contrast adjustment
  • HD44780-compatible 1602 LCD
  • Two push buttons
  • Two pull-down resistors for the push buttons
  • Breadboard or PCB or whatever similar to connect everything above properly

The left push button is connected to D8, while the right push button is connected to D9. Both push buttons are pulled-down. For other connections, please refer to the schematics in the tutorial.

Turning an Alphanumeric LCD into a Graphical LCD

HD44780-compatible LCD driver supports up to 8 custom characters. By carefully defining those 8 characters, it's possible to subdivide each character into multiple "pixels". That can effectively turn the alphanumeric display into a graphical LCD display.

My design subdivides each character two rows. Each row on the character can be either empty, snake, or apple as shown below:

Custom characters defined in HD44780

There're two "pixels" in each character. Each pixel can have three possible values. Therefore, the total combination is 3^2 = 9. Since one of these combination is visually empty, a space character were used to represent that. At the end only 8 custom characters are needed. So the 8 available characters in CGRAM of HD44780 are just enough for our purpose.

To reduce RAM usage, each pixel is represented by 2 bits. So a byte can store 4 pixels. Everything is cramped into a uint8_t graphicRam[GRAPHIC_WIDTH*2/8][GRAPHIC_HEIGHT]. At width of 16 and height of 4, only 16 bytes of RAM are taken for the graphic! Had I used a uint8_t for each pixel, 64 bytes of RAM would be required.

After the completion of this project, I've found other designs like spliting each character into three rows, or try making use of all pixels by generating the CGRAM on-the-fly. I'll consider using these techniques for my future projects.

Randomization of the Apple Position

To make the position looks random, we need to somehow seed the random number generator. For computer programs, we usually seed it with the current time of the machine. However, this couldn't be done on Arduino because it doesn't have a real time clock.

My solution is to make a menu screen of the game. When the user start the game, the time of the moment that the user pressed the button is used to seed the random number generator. The micros() method of Arduino Time library were used. This has the equivalent effect of using system time.

Funny Failure: Bug Went Unnoticed for Hours

I was having fun playing with this game. I thought that it was reasonably bug-free because I had played it for a while. I've also asked one of my family members to try it out. I swear. We haven't spotted any bug.

Until I tried to record a video of the game play, something funny happened. I realized that I haven't implemented self-collision detection of the snake. I was like "Wow. How come no one had notice that earlier?". Hah. What a terrible failure!

Upon the discovery of the bug, it was fixed in no time.

Future Development

Seems that using alphanumeric LCD as graphical LCD is promising. I'll consider going for this solution for the portable game console project. Of course, I won't be using Arduino for that. Arduino is good for prototyping. But it isn't as efficient as lower-level C/C++ programming.

I've played this game for many times. While it's technically possible to win, I haven't managed to do so. And I haven't tested the code of winning the game. I doubt that anyone could beat it anyway. I guess I'd just leave the code there as it is. :P

Game Over photo of Arduino 1602 Snake showing the text "Boo! You lose!" and "Length: 14" in the other line

Alright. That's enough fun for today. Gotta sleep.


Removing Unused Glyphs of a Font

Dec. 7, 2015, 11:38 a.m. Programming Simple Tools

As you might have know, CJK fonts are huge in size. If the characters to be used are known, the file size of the font file can be greatly reduced by removing the unused glyphs.

I'll probably encounter this issue when I use HaxeFlixel to display CJK characters in my next project. Then I Googled for a solution. Unfortunately, there is no such thing searchable in Google.

That's why I've written the script below with the use of FontForge:

#!/usr/bin/python2
import sys
import fontforge

if len(sys.argv) == 4:
    font = fontforge.open(sys.argv[1])

    f = open(sys.argv[2], "r")

    for i in f.read().decode("UTF-8"):
        font.selection[ord(i)] = True
    f.close()

    font.selection.invert()

    for i in font.selection.byGlyphs:
        font.removeGlyph(i)

    font.generate(sys.argv[3])
else:
    print "WARNING: Check the license of the source font\nbefore distributing the output font generated by this script.\nI'm not responsible for any legal issue caused by\ninappropriate use of this script!\n"
    print "Usage: {} [source font] [file with glyphs NOT to be removed] [output]".format(sys.argv[0])
    print "Example: {} /path/to/ukai.ttc chineseTranslation.txt ukaiStripped.ttf".format(sys.argv[0])

Mind you, ensure to check the license of the source font. It may not be legal to use this script under certain condition with certain source fonts. I'm not responsible for any legal issue cause by fonts generated with this script.

I've also posted this code to stackoverflow. Hopefully the internet would find it useful!


Java String Split Gotcha

Oct. 6, 2015, 2:12 p.m. Programming

I was fixing a networking-related bug in Koloniigo. I did something like this:

String[] fields = data.split(";"); //data contains something like "a;b;;"
foo(fields[3]);

Then the program gave IndexOutOfBoundsException

I wonder what's wrong. After a few hours of debugging, I found this thingie in the documentation of split()

Trailing empty strings are therefore not included in the resulting array.

Oh well, wtf? A few hours wasted.

You may think that I'm an idiot that I didn't notice such an obvious mistake. Actually, the real code is way more complicated and there was very many possible causes of the issue. That's why it took me so long to figure out that it's the issue of the split(). :(


Gotcha of Rendering libgdx NinePatch

Sept. 15, 2015, 1:22 p.m. Gamedev Programming libgdx

Today I ran into a gotcha of libgdx. I was trying to render a NinePatch packed with texture packer by constructing a NinePatch using this:

new NinePatch(assetManaget.get("pack.atlas", TextureAtlas.class).findRegion("path/to/ninepatch"));

Then I tried to render the object using its draw() method. Didn't work. Instead, the NinePatch image was just stretched.

Then I read the documentation about the constructor of new NinePatch(TextureRegion)

Construct a degenerate "nine" patch with only a center component.

What? This is obviously not what I was expecting.

Turned out that the proper way to do this is:

assetManaget.get("pack.atlas", TextureAtlas.class).createPatch("path/to/ninepatch");

See also: TextureAtlas.createPatch(java.lang.String)