Summary of 1K LCD Tinyfont: A 383-Byte Variable-Width Font and a 930-Byte Display Application
This 930-byte project displays UART messages on a Nokia 5110 LCD using a custom 383-byte pixel font. Built with an Atmega328pu microcontroller, it utilizes assembly language to achieve extreme code size efficiency while supporting variable-width characters and word-wrapping. The system unpacks compressed font data into a buffer for rendering, enabling full text display on the low-power dev board without external libraries.
Parts used in the 1K LCD Tinyfont Project:
- Atmega328pu microcontroller
- Nokia 5110 LCD display
- Sparkfun dev board
- Custom-made board (Eagle CAD design)
- USBTiny programmer
- Atmel Studio 7
- Homemade small font designer software
- USB connection
A Small Font for a Small Display
The 1K LCD Tinyfont project, published on Hackaday.io by the project owner credited as Zach and submitted to The 1kB Challenge, describes a custom pixel font and a small program that prints received text on a Nokia 5110 LCD. The owner reports a 383-byte font and a 930-byte application: his own measurements of his build, not of a reproduction, and not a prediction for a different compiler, library set, or target board.
The owner’s own summary describes a “tiny pixel font rendered to an LCD display, in under 1K program space.” What follows examines the documented mechanism and the questions it leaves open.
Reported Program and Font Sizes
The font “weights in at 383 bytes” and was built with the author’s Small Font Designer. A size table splits the build into a 930-byte full application, the 383-byte compressed font, and 547 bytes of code for decompression, the LCD driver, and UART handling.
The owner reports the final size “was determined by pulling the program from flash and checking the bytes,” and publishes the byte-and-address listing as program_map.txt, so the figure is a direct read rather than a compiler estimate.
Two arithmetic checks follow, both derivations rather than new measurements. The components reconcile: 383 plus 547 equals the reported 930. Against a 1 KiB budget the font occupies 383 / 1024 = 37.4 percent, and a 930-byte image leaves 1024 – 930 = 94 bytes of headroom. Those numbers describe capacity only; any edit to the message buffer, the wrapping routine, or the driver would move them.
Variable-Width Glyphs and the Packed Table
Glyphs are “variable-width characters 8 pixels tall,” a choice that suits byte-oriented storage: one byte holds one column, one bit per row, so no glyph crosses a byte boundary. The owner says “the characters are packed to indicate their width, and each active pixel.”
One worked example is published: the letter A, five columns wide, stored as 0x05, 0x01, 0x14, 0xa7, 0x46, 0x20. The first byte is the width and the rest expand to a dot pattern resembling the letter.
That example limits what can be claimed about compression. A plain five-by-eight bitmap stored one byte per column would also take five bytes; this encoded glyph takes six, because it carries a width byte ahead of five data bytes. The saving therefore comes not from the letter A but from narrow characters, such as a period or an i, which need fewer than five data columns, and from avoiding a fixed cell padded to the widest character. Whether the table as a whole beats a fixed-width font depends on the character mix, and no per-glyph accounting is published.
The text does not document the bit-to-row mapping inside the data bytes, or the role of the trailing 0x20. Whether that byte is glyph data, a terminator, or spacing is not established, so no specific bit layout is asserted here.
Buffer Capacity and Undefined Input
Rendering is a per-character pipeline: the current character is looked up, decompressed into a 64-byte buffer, then written into the LCD display buffer. Sixty-four bytes is 512 bits, or 64 columns of eight pixels, a derivation from the buffer size rather than a statement about indexing. The display buffer is then sent over SPI.
Input validation is not described. Messages arrive over the UART at 9600 bps; a newline byte, 0x0A, prints the message and resets the buffer, and the program inserts further newlines during word wrapping. The font covers both letter cases, the digits, and “most punctuation.” That qualifier matters: a received byte with no table entry still has to be handled, and the material says nothing about a bounds check, a skip, a substitute glyph, or whether an oversized glyph can overrun the 64-byte staging buffer. These are the first questions to answer when inspecting the source, since the receive path accepts whatever a sender, such as the Bluetooth link in the demonstration, transmits.
Flash, RAM, and the Cost of Table Lookup
The 930 bytes is program memory, measured by reading the image back from flash. The font table shares that space, and the current character is found by “slowly looping to save space,” trading execution time for not keeping a decoded copy resident. No timing figures are reported, so the size of that penalty is unknown.
RAM is a separate budget. The decompression buffer and the LCD display buffer occupy RAM, and no RAM total is reported. A 930-byte flash figure, or fitting under 1 KiB of program space, says nothing about static or peak RAM use.
The ATmega328PU Target
The build uses an ATmega328PU, a Nokia 5110 LCD on a Sparkfun development board, and a custom board documented with Eagle files and photographs, programmed with a USBTiny. The software was written in assembly in Atmel Studio 7 after earlier C versions were “far too large.” The site’s notes on a stand-alone AVR programmer and on AVRDUDESS as a GUI for AVRDUDE cover tooling in this style.
The part designation is the owner’s and is preserved as written. Nothing in the supplied evidence shows the ATmega328PU to be register-identical to an ATmega328P for this code, so no device-specific register behavior is claimed here; any such comparison is a hypothesis to be tested. The byte counts likewise belong to the owner’s board, toolchain, and source revision.
What a Reader Should Verify
The approach is reproducible in principle, but details needed for a faithful reimplementation are missing from the public description. A reader should obtain program_map.txt and the source, confirm the bit ordering inside glyph bytes, identify the terminator and spacing convention, and check how bytes outside the font table and overlong words are handled at the buffer boundary. Measuring RAM use and re-measuring the flash total with a current toolchain would separate the owner’s 2016 figures from what the same source produces today. The project page is the primary reference: 1K LCD Tinyfont on Hackaday.io.
- What is the final program size of this project?
The final program size is 930 bytes. - How was the software written for this project?
The software was written in assembly because initial versions in C were far too large. - Does the font include lowercase letters?
Yes, the font includes all uppercase and lowercase letters, numbers, and most punctuation. - Can the application perform word-wrapping?
Yes, the application has the ability to perform word-wrapping. - What tool was used to create the custom font?
The font was created using a homemade small font designer. - How are the characters stored in the font file?
Characters are packed to indicate their width and each active pixel within 64-byte buffers. - Is the project compatible with standard Arduino boards?
Yes, the project will function on an Arduino with the same microcontroller as the Sparkfun dev board. - How many bytes does the custom font weigh?
The font weights at 383 bytes.
