logo elektroda
logo elektroda
X
logo elektroda

Arduino R4 WiFi - how to display text on matrix display? DIY LedMatrix Font

p.kaczmarek2  0 4431 Cool? (+12)
📢 Listen (AI):

TL;DR

  • Builds a DIY ASCII font system for the Arduino Uno R4 WiFi LED matrix, with support for animated moving text.
  • Ports font data from MD_Parola by searching variable-width characters, reading each character’s size, and copying column bytes into the Arduino frame buffer.
  • Uses a byte array format where each character is preceded by its size in bytes, and one byte represents 8 pixels in a column.
  • Keeps the implementation beginner-friendly by using one byte per pixel for the matrix array, even though it could be 8x more compact.
Generated by the language model.
Arduino Uno R4 WiFi with connected LED matrix.
Today I will present a simple font system for ASCII characters designed for a matrix display with Arduino Uno R4 WiFi. By the way, I will also demonstrate how to animate moving text based on the codes placed here. The implementation of the font will be 100% DIY, we will write it together and put it in our sketch, although we will already have the font itself - we will borrow it from the MD_Parola library.

Hello world LED Matrix
Arduino R4 contains ready-made examples of LED arrays, which I recommend to read before reading the topic:
Arduino IDE example menu with LED_Matrix examples expanded for Arduino UNO R4 WiFi.
However, I will not describe them here, because it would be pointless. We'll do something new together. Let's start by displaying an array on a matrix:
Code: C / C++
Log in, to see the code

Result:
Arduino Uno R4 WiFi board with an illuminated LED matrix display powered by a USB-C cable.
as you can see, we've got everything nicely organized here into a two-dimensional array of bytes. One byte is one pixel. It could be done better, 8x better to be exact, where the pixel would be a bit, but the subject is for beginners, so I didn't want to complicate it that much.

New font for LED matrix
A font system would be nice. You could create each character manually from pixels yourself, but why? We have ready-made fonts for this, for example the one from MAX7219 from the Parola library:
https://github.com/mrWheel/ESP_ticker/blob/master/parola_Fonts_data.h
Let's try to port it from ESP MAX7219 to our Arduino.
First you need to note that each character can have a different width .
This is due to the data recording format:
A fragment of C code showing the definition of a g_font byte array containing font data for an LED matrix display.
The font is a byte array, where each character is preceded by its size in bytes, and then we have data bytes, where each byte represents the state of 8 pixels in a given column.
We will have to:
- search for a character in the font data (since each can have a different number of bytes, we will not count its offset)
- read its size
- copy its pixels from bits to Arduino bytes
Let's start with the search. Based on MD_Parola:
Code: C / C++
Log in, to see the code

The above code sets the pointer to the beginning of the font data and then counts down the ASCII characters until it hits the one we are looking for, while skipping the data of the characters we are not interested in. The result will be a pointer to the ASCII character data we are looking for.
Now the function that iterates the string and prints it character by character (with support for printing on a given position):
Code: C / C++
Log in, to see the code

This function goes through the string character by character (through a pointer to char, the end of a character is a byte zero) and sequentially fetches the font of the given character and if it is available, it first prints that character and then adds a space of one column.
The function additionally counts how many columns were actually displayed, later I will explain why I added it.
Now let's see the display of one character:
[syntax=c]
int LED_displayArray(byte *p, int devs, int ofs)
{
int drawn = 0;
for(int i = 0; i < devs; i++) {
int di = ofs + i;
if(di < 0)
continue; // skip
if(di >= TOTAL_COLUMNS)
break; //dont go outside array
for(int j = 0; j < 8; j++) {
frame[j][di] = !!(p[i] & (1

About Author
p.kaczmarek2
p.kaczmarek2 wrote 14570 posts with rating 12586 , helped 654 times. Been with us since 2014 year.

Comments

FAQ

TL;DR: For Arduino Uno R4 WiFi users, this method turns the built-in 8x12 LED matrix into a text display with a DIY ASCII font. It uses 1 byte per pixel and adapts MD_Parola font data because "each character can have a different width," then scrolls text by changing the horizontal offset. [#20703376]

Why it matters: It shows a beginner-friendly way to print and animate text on the Uno R4 WiFi even without a built-in text API.

Approach Pixel storage Ease of learning Memory efficiency Best use
Simple 2D frame buffer 1 byte per pixel Easier Lower Beginner text rendering
Packed bit representation 1 bit per pixel Harder About 8x better Tight-memory projects

Key insight: The core trick is not the display call itself. The real work is finding each variable-width glyph in a byte array and expanding its bit columns into the 8x12 frame buffer before calling renderBitmap().

Quick Facts

  • The example frame buffer is uint8_t frame[8][12], so the Uno R4 WiFi matrix is handled as 8 rows by 12 columns. [#20703376]
  • The beginner format stores 1 byte per pixel, while a packed layout could store 1 bit per pixel, making it about 8x more memory-efficient. [#20703376]
  • The setup example starts Serial at 115200 baud, waits 1500 ms, calls matrix.begin(), then renders the bitmap with matrix.renderBitmap(frame, 8, 12). [#20703376]
  • The font parser walks a byte array until it reaches the sentinel value 255, because each glyph starts with its own width byte and can use a different number of columns. [#20703376]

How do I display custom text on the Arduino Uno R4 WiFi LED matrix using Arduino_LED_Matrix?

You display custom text by drawing glyph data into an 8x12 frame buffer and then sending that buffer to ArduinoLEDMatrix::renderBitmap(). The post builds characters from a DIY ASCII font, writes pixels into frame[8][12], and prints full strings through LED_print(). That avoids any missing built-in text API and gives full control over spacing and scrolling. [#20703376]

What is the Arduino_LED_Matrix library and how does it handle an 8x12 bitmap on the Uno R4 WiFi?

Arduino_LED_Matrix is the library that drives the Uno R4 WiFi’s built-in LED matrix from a bitmap buffer. In the example, it takes a two-dimensional uint8_t frame[8][12], where each byte represents one pixel state, then displays it with matrix.renderBitmap(frame, 8, 12). The sketch initializes the hardware with matrix.begin() after a 1500 ms delay. [#20703376]

How can I create a DIY ASCII font for the Arduino R4 WiFi matrix display without relying on a built-in text API?

You can create it by storing ASCII glyphs in a byte array, then converting each glyph into matrix pixels at draw time. The post uses borrowed font data, but keeps the rendering code fully DIY: LED_GetFontStart() finds the glyph, LED_displayArray() expands column bits into pixels, and LED_print() assembles the string. This gives character-by-character control over width and spacing. [#20703376]

What is MD_Parola and how can its MAX7219 font data be adapted for the Arduino Uno R4 WiFi LED matrix?

"MD_Parola is a font and display library that stores LED glyphs as variable-width column data, optimized for matrix text effects such as scrolling." The post adapts its MAX7219-style font by reading each glyph’s width byte, then copying every column’s 8 bits into the Uno R4 WiFi frame[8][12] buffer. That reuses existing font data without needing the MAX7219 hardware format directly. [#20703376]

Why does the font format store a width byte before each character, and how does variable-width text work on an LED matrix?

The width byte tells the renderer how many columns belong to the next character. That matters because letters do not all need the same width. A narrow symbol can use fewer columns, while a wider one uses more. LED_print() reads that width, draws exactly that many columns, then adds one extra blank column as spacing. This makes text tighter and more natural than a fixed-width grid. [#20703376]

How do I search through a byte-array font table to find the start of an ASCII character when every glyph has a different size?

You search it sequentially instead of calculating a fixed offset. The post starts at g_font, tracks the current ASCII code, and skips each glyph by adding its stored width plus 1 more byte for the width field itself. The loop stops when it finds the requested code or reaches the end marker 255. That works because every glyph can have a different column count. [#20703376]

What does the LED_GetFontStart() function do when parsing font data for an Arduino matrix display?

LED_GetFontStart() returns a pointer to the start of one glyph inside the font table. It initializes p = g_font, compares the requested ASCII code against a current counter, and advances through the table by *p data bytes plus 1 size byte per glyph. If it reaches 255, it returns 0, which signals that no glyph was found. [#20703376]

How does the LED_print() function render a whole string character by character and add spacing between letters?

LED_print() walks through a null-terminated C string and draws one glyph at a time. For each character, it calls LED_GetFontStart(*p), renders *font columns starting at font+1, then draws one blank column from zero to separate letters. It also updates ofs after every glyph and returns the total number of drawn columns. That total is useful for later animation logic. [#20703376]

How can I convert font columns stored as bits into the byte-per-pixel frame format used by ArduinoLEDMatrix::renderBitmap()?

You convert each font byte into 8 vertical pixels and write them into the frame buffer column by column.
  1. Read one glyph column byte from the font table.
  2. Test each bit from row 0 to row 7.
  3. Write the result into frame[j][di] as 0 or 1.
The post’s LED_displayArray() does exactly that, turning compact bit columns into the 8x12 byte-per-pixel format required by renderBitmap(). [#20703376]

Why would someone choose a simple byte-per-pixel 2D array instead of a packed bit representation for an LED matrix font?

They choose it because it is easier to understand and debug. The post explicitly uses one byte for one pixel, even though a packed format would be about 8x more efficient. That tradeoff helps beginners see rows, columns, and pixel states directly inside frame[8][12]. For teaching or quick prototypes, clarity can matter more than memory savings. [#20703376]

Arduino Uno R4 WiFi matrix font rendering vs MAX7219 with MD_Parola — which approach is easier for scrolling text projects?

The Uno R4 WiFi frame-buffer approach is easier to learn, while MD_Parola-style data is better as a ready-made font source. The post keeps the rendering simple with frame[8][12] and manual offsets, but borrows the proven MAX7219 font table because it already contains ASCII glyphs and width bytes. For a first scrolling-text project, that combination reduces complexity without losing flexibility. [#20703376]

How do I animate moving or scrolling text on the Arduino R4 WiFi LED matrix using a custom frame buffer?

You animate scrolling text by redrawing the string with a changing horizontal offset. The post adds an ofs parameter to LED_print() and LED_displayArray(), so text can start off-screen, move across visible columns, and continue until it exits the TOTAL_COLUMNS area. Because the code also returns the number of drawn columns, you can know when the whole message has fully passed. [#20703376]

What is an ASCII character set in the context of LED matrix fonts, and how does it affect printable symbols?

"ASCII is a character encoding set that maps text symbols to numeric codes, letting a font table match letters, digits, and punctuation to stored glyph data." In this project, the code increments a current character value while scanning the font array, so printable output depends on whether that ASCII code exists in the table. Missing codes return 0 and are not drawn. [#20703376]

How can I troubleshoot text drawing that goes outside the matrix width or disappears when the offset becomes negative?

Check the clipping logic first. In LED_displayArray(), a negative di value triggers continue, so columns left of the visible area are skipped. If di >= TOTAL_COLUMNS, the loop stops with break, so columns beyond the right edge are never written. Text can seem to disappear when the offset is too negative or when TOTAL_COLUMNS is smaller than the rendered message width. [#20703376]

What is the TOTAL_COLUMNS limit for an Arduino LED matrix frame buffer, and how should I handle clipping when drawing characters?

TOTAL_COLUMNS is the maximum drawable width of your frame buffer, and the code uses it as a hard clipping boundary. The post does not assign a numeric value in the shown fragment, but it enforces two rules: skip columns when di < 0, and stop drawing when di >= TOTAL_COLUMNS. Set TOTAL_COLUMNS to your actual buffer width and keep all glyph writes inside that range. [#20703376]
Generated by the language model.
%}