Skip to content

Text Rendering on E-Ink

Text Rendering on E-Ink

This section covers text rendering on e-paper displays using the GxEPD2 and AdaFruit GFX libraries. Proper text layout is essential for creating readable factory dashboards. After completing this section, you will be able to:

  • Display text at various positions on the e-paper screen
  • Change font size and style using built-in fonts
  • Align text horizontally and vertically
  • Combine multiple text elements on a single screen

Before starting this section, please ensure:

  • GxEPD2 library is installed (see 02-03)
  • Display is wired and verified
  • Basic understanding of display coordinates

The e-paper display uses a standard Cartesian coordinate system with the origin at the top-left corner:

(0,0) ──────────────────────────── X (width)
│ +-------------------+
│ | |
│ | Display Area |
│ | |
│ +-------------------+
Y (height)

For a 2.13” display (250×122 pixels):

  • X range: 0 to 249 (horizontal)
  • Y range: 0 to 121 (vertical)
  • Text is placed using display.setCursor(x, y)

The AdaFruit GFX library provides several built-in fonts:

Font NameSizeUse Case
(default)5×7 pxMinimal text, debug output
&FreeMono9pt7b9pt monospaceTabular data
&FreeMonoBold12pt7b12pt bold monoHeaders, KPIs
&FreeMonoBold18pt7b18pt bold monoLarge numbers
&FreeMonoBold24pt7b24pt bold monoVery large values
&FreeSans9pt7b9pt sans-serifBody text
&FreeSansBold12pt7b12pt bold sansSection titles
&FreeSerif12pt7b12pt serifDecorative text
&TomThumb3×5 pxUltra-small labels

Font naming convention: &FontNameSizept7b where:

  • & is required prefix when referencing the font
  • 7b means 7-bit character encoding (standard ASCII)
#include <GxEPD2_BW.h>
#define EPD_CS 5
#define EPD_DC 17
#define EPD_RST 16
#define EPD_BUSY 4
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void setup() {
Serial.begin(115200);
display.init(115200);
display.setRotation(1); // Landscape orientation
// Clear screen
display.fillScreen(GxEPD_WHITE);
// Draw text at specific coordinates
display.setCursor(10, 20);
display.print("Line 1: Factory Display");
display.setCursor(10, 35);
display.print("Line 2: Temperature: 25.5C");
display.setCursor(10, 50);
display.print("Line 3: Humidity: 60%");
// Push to display
display.display();
}
void loop() {}

Expected Result: Three lines of small text displayed at the left side.

#include <GxEPD2_BW.h>
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void setup() {
display.init(115200);
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
// Default 5x7 font
display.setCursor(0, 10);
display.print("Default font (5x7)");
// 9pt monospace
display.setFont(&FreeMono9pt7b);
display.setCursor(0, 30);
display.print("9pt Mono");
// 12pt bold monospace
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(0, 55);
display.print("12pt Bold");
// 18pt bold monospace (large numbers)
display.setFont(&FreeMonoBold18pt7b);
display.setCursor(0, 85);
display.print("42.5");
display.display();
}
void loop() {}

Note: After changing font with setFont(), the cursor position behavior changes. Font-based cursors use the font’s baseline as the Y reference point, while default font uses top-left.

To center text horizontally, calculate the position using text bounds:

#include <GxEPD2_BW.h>
GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(
GxEPD2_213_B72(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY)
);
void centerText(const char* text, int y, const GFXfont* font) {
display.setFont(font);
// Get text bounds
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
// Calculate centered X position
int16_t x = (display.width() - w) / 2;
// Draw text at centered position
display.setCursor(x, y);
display.print(text);
}
void setup() {
display.init(115200);
display.setRotation(1);
display.fillScreen(GxEPD_WHITE);
// Header centered
display.setTextColor(GxEPD_BLACK);
display.setFont(&FreeMonoBold12pt7b);
centerText("FACTORY STATUS", 25, &FreeMonoBold12pt7b);
// Temperature value centered
centerText("Temperature: 25.5C", 60, &FreeMono9pt7b);
// Humidity value centered
centerText("Humidity: 60%", 85, &FreeMono9pt7b);
display.display();
}
void loop() {}

E-paper displays support 4 rotation modes:

// Rotation values
display.setRotation(0); // 0° - Portrait (default)
display.setRotation(1); // 90° - Landscape
display.setRotation(2); // 180° - Inverted portrait
display.setRotation(3); // 270° - Inverted landscape

For factory dashboard typically use:

  • Rotation 1 (landscape): For wider data table displays
  • Rotation 0 (portrait): For KPI-style single-value displays
void displayText(const char* title, const char* value1, const char* value2) {
display.fillScreen(GxEPD_WHITE);
// Title
display.setFont(&FreeMonoBold12pt7b);
display.setCursor(5, 25);
display.print(title);
// Horizontal separator line
display.drawFastHLine(0, 35, display.width(), GxEPD_BLACK);
// Value 1
display.setFont(&FreeMono9pt7b);
display.setCursor(5, 55);
display.print(value1);
// Value 2
display.setCursor(5, 80);
display.print(value2);
display.display();
}
// Usage in setup():
// displayText("PLANT A", "Temp: 25.5C", "Humi: 60%");

After uploading the text rendering sketch, verify:

  • Text appears at the expected positions
  • Different fonts display correctly
  • Centered text is properly aligned
  • Rotation changes orientation as expected
  • Text is readable (black on white background)

Symptom:

  • Random characters instead of readable text

Solution:

  • Ensure font is referenced with & prefix (e.g., &FreeMono9pt7b)
  • Check that font is defined within the sketch scope
  • Don’t use setFont(NULL) accidentally between font changes

Symptom:

  • Text extends beyond the display boundary
  • Bottom of text is missing

Solutions:

  • Use display.getTextBounds() to measure text width before drawing
  • Ensure Y position accounts for font height (larger fonts need more vertical space)
  • Reduce font size or line length

Symptom:

  • Centered text is not truly centered
  • Multiple lines don’t align vertically

Solution:

// Use a helper function for consistent alignment
int16_t getCenteredX(const char* text, const GFXfont* font) {
display.setFont(font);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
return (display.width() - w) / 2;
}
  • Use monospace fonts for tabular data — Ensures columns align properly
  • Prefer bold fonts for KPIs — Better readability at a distance
  • Calculate text bounds before positioning for reliable centering
  • Avoid small fonts (< 9pt) for factory floor viewing
  • Don’t mix too many font sizes on one screen — Keep to 2-3 maximum
  • Avoid unnecessary font changes — Each setFont() call adds processing overhead

Template 1: Single KPI (factory KPI board)

┌─────────────────────────────────────┐
│ PRODUCTION LINE A │ ← 12pt bold, centered
├─────────────────────────────────────┤
│ │
│ 25,847 │ ← 24pt bold, centered
│ Units Today │ ← 9pt, centered
│ │
│ Target: 30,000 │ +5.3% YoY │ ← 9pt mono, two columns
└─────────────────────────────────────┘

Template 2: Multi-Sensor Readout

┌─────────────────────────────────────┐
│ ENVIRONMENT MONITOR │ 14:30 │ ← Header with time
├─────────────────────────────────────┤
│ Temperature │ 25.5°C │ Normal │
│ Humidity │ 60% │ Normal │
│ Pressure │ 1013hPa │ Stable │
│ Light │ 450 lux │ Good │
└─────────────────────────────────────┘
  1. Text rendering uses AdaFruit GFX primitivessetCursor(), setFont(), print()
  2. Font selection affects cursor behavior — Font-based fonts use baseline Y coordinates
  3. Use getTextBounds() for accurate positioning — Essential for centering and alignment
  4. Display rotation changes coordinate system — Set once at initialization
  5. Keep text layouts simple — 2-3 font sizes maximum for readability

Target Audience: Alibaba.com IoT Pre-sales Engineers
Status: ✅ Completed