ABOUT | BLOG | PROJECTS | MERCH
ilo nena is a purpose-built hardware keyboard that can type sitelen pona Unicode into computers. Its firmware contains a font of Toki Pona language.
The microcontroller behind ilo nena is CH32V003, which only has 16kB of FLASH storage space. With ~200 glyphs, storing the code along with the entire font into the FLASH space is proven to be challenging. I've used the following tricks to keep the font size small:
The screen I'm using is 128x32 monochrome. For a square glyph, the screen would be able to accommodate font resolution of 32x32, which would cost 32*32/8 = 128bytes for each glyph. To save space, I'm using a font with size of 15x15 instead, which would cost me 30bytes uncompressed. It saves a lot of space while still providing an acceptable user experience.
While it isn't exactly a compression mechanism, I found it worth mentioning because it does save space.
Plenty of glyphs has unused boundary on the edge of the image. Therefore, I'm cropping the empty content to save space.

Due to encoding limitation, the cropping is performed on the column only and that cropping is always symmetric.
I've noticed that for many of the glyphs, the column content repeats. In the example below, only 6 red columns need to be encoded uncompressed. The other green columns can just make reference to existing columns to save space:

Due to encoding limitation, only 8 dictionary entries are supported, in which the most recent non-duplicate entries are stored.
The font just happened to have many symmetric glyphs. The right half of the image is a mirrored version of the left half of the image. In this case, only half of the image would be encoded. The other half would be skipped from encoding and would be automatically generated during decoding:

I find this mechanism pretty funny. I like this one the most among other mechanisms being used here. "Oh? The right half is the same as the left half! Let's just draw half of the image and call it a day!" That's bullshit! xD
With the design above, I came up with an encoding scheme on my own. For each of the glyphs:
Below is an example of how a compressed glyph is encoded. The encoded content in hex is [28FEFF0210333302F0]:

The follow data were obtained with the firmware version "nanpa ala":
Control:
My algorithm offers better compression than Huffman and it's almost as good as zlib. Unlike zlib and Huffman, my algorithm also contains metadata that allows reading individual glyph without decoding the entire block of content. On top of that, the code size for the decoder is probably much smaller than zlib and possibly also smaller than Huffman encoding.
I think I can do further space saving by preloading the dictionary with common content across all glyphs. But I haven't implemented that for now.
Unlike uncompressed array, each compressed glyph is having a variable length. Therefore, when the compressed glyph data is placed back-to-back with each others, you can't read a particular glyph without scanning the payload size of all of the previous glyphs. For ilo nena, I found that the performance is good enough even with the scanning. In case there's performance issue for other projects, it could be mitigated by supplying an index inside the codebase for every, says, 16 glyphs.
As for the mirroring compression mechanism, obviously it may not work on other fonts whatsoever. I'm simply lucked out that it worked. :P
The font I'm using is based on leko lili 15x15. I'd like to thank jan Osi for creating this public domain font.
Thank you for viewing this blogpost as well. Stay tuned for more technical blogposts of ilo nena! You can also view other blogposts of this project below.
Copyright (C) 2025 Wong Cho Ching, all rights reserved.