Overview
The display service is a global, thread‑safe wrapper around the U8G2 driver for a 128×64 SSD1306 OLED. You use it to render text and graphics from any task without flicker or tearing. A FreeRTOS mutex guarantees exclusive access while you draw; helper functions handle region clearing, partial refresh, clipping, and text caching.This page documents the firmware‑level developer API used across our devices. For user‑facing display behavior (for example, hiding remaining time or device state screens), see the related pages at the end.
Prerequisites
- ESP32 with hardware I2C available
- U8G2 library integrated in your firmware build
- FreeRTOS (for the display mutex)
- Pins configured for SDA/SCL in your board’s
Pins.h
Hardware configuration
| Property | Value |
|---|---|
| Display | SSD1306 OLED |
| Resolution | 128×64 pixels |
| Interface | I2C (hardware) |
| Rotation | U8G2_R0 (0°) |
| I2C address | 0x3C |
| Contrast | 255 (max) |
Some U8G2 constructors expect the 8‑bit I2C address. If so, pass
0x3C << 1. Verify this matches your constructor signature.Layout model
The screen is treated as a grid of 8×8‑pixel cells:- Grid: 8 rows × 16 columns
- Origin: (0,0) at the top‑left
- Cell size: 8×8 pixels
Regions
Header (row 0)
Header (row 0)
- Cells 0–12: Header text (13 cells = 104 px)
- Cells 13–15: State icons (3 cells = 24 px)
Page area (rows 1–6)
Page area (rows 1–6)
- 6 rows tall (48 px)
- 16 cells wide (128 px)
- All main content should render here
Footer (row 7)
Footer (row 7)
Thread safety
The display service exposes a FreeRTOS mutex. Always lock before drawing and unlock when done.display_mutex.h
Basic usage pattern
example_usage.cpp
Initialization
CallinitDisplay() once at startup.
display_init.h
Create resources and configure the panel
initDisplay() creates the display mutex, initializes the U8G2 display instance, sets addressing/rotation/contrast, and clears the buffer.After initialization, the screen should be blank and backlit, and
displayMutex must be non‑null.Clearing helpers
Efficiently clear only what you plan to redraw. All helpers use an internalupdateDisplayArea() to perform a partial refresh of the affected region.
| Function | Description | Region cleared |
|---|---|---|
clearHeader() | Clears header text only | Row 0, cells 0–12 |
clearIcons() | Clears icon area only | Row 0, cells 13–15 |
clearFooter() | Clears footer text only | Row 7, cells 0–14 |
clearTimeout() | Clears timeout indicator | Row 7, cell 15 |
clearPage(includeFooter=false, includeHeader=false) | Clears page area; optional header/footer | Rows 1–6 (plus header/footer when requested) |
clear_helpers.h
clearPage() sets a clipping window to keep content from spilling into the header or footer.Refresh helpers
Call a refresh helper after you modify a region. These perform minimal updates to the display.| Function | Description | Region updated |
|---|---|---|
refreshHeader() | Pushes header text | Row 0, cells 0–12 |
refreshIcons() | Pushes icon area | Row 0, cells 13–15 |
refreshFooter() | Pushes footer text | Row 7, cells 0–14 |
refreshTimeout() | Pushes timeout indicator | Row 7, cell 15 |
refreshPage(includeFooter=false, includeHeader=false) | Pushes main content; optional header/footer | Rows 1–6 (plus header/footer when requested) |
refresh_helpers.h
Content helpers
setHeader()
Sets the header text. The service uppercases and caches the last value to avoid redundant redraws.
header.h
setFooter()
Sets left‑ and right‑aligned footer text. Both are uppercased and cached.
footer.h
- Left string aligns to the left edge of the footer region
- Right string aligns to the right edge of the footer region
drawWrappedText()
Draw text with automatic word wrapping and optional center alignment.
wrapped_text.h
Starting x‑coordinate in pixels.
Starting baseline y‑coordinate in pixels.
Text to render. Supports literal
\n for line breaks.Center each wrapped line within the page area when
true.Number of lines drawn.
Common patterns
Draw a complete screen
draw_screen.cpp
This pattern clears only the page area, draws new content, and performs a partial refresh for speed.
Update the header only
update_header.cpp
Draw wrapped, centered text
wrapped_text.cpp
Drawing guidelines
Lock the mutex for every drawing sequence
Wrap drawing and refresh in a critical section guarded by
displayMutex.lock_and_draw.cpp
Prefer region helpers over full clears
Minimize bus traffic and flicker by using
clear*() and refresh*() helpers.Respect boundaries
Keep content within:
- Header: row 0, cells 0–12
- Icons: row 0, cells 13–15
- Page: rows 1–6
- Footer: row 7, cells 0–14; timeout at cell 15
clearPage() to clip page content away from header/footer.Performance considerations
- Partial updates only redraw the regions you changed
- Text caching avoids unnecessary draw/refresh cycles
- Clipping keeps drawing inside the intended region and reduces overdraw
- Mutex‑guarded sequences prevent mid‑frame tearing across tasks
Troubleshooting
Nothing appears after init
Nothing appears after init
- Confirm
initDisplay()is called once - Verify the I2C address (try
0x3Cand0x3C << 1depending on constructor) - Ensure SDA/SCL match your board’s
Pins.h
Display updates are slow or flicker
Display updates are slow or flicker
- Use region clears/refreshes instead of full‑buffer clears
- Batch your drawing into one mutex‑protected block
- Avoid unnecessary font changes between draw calls
Text appears misaligned vertically
Text appears misaligned vertically
- Remember U8G2 uses a baseline for
y - Start the first 8‑px font line at
y = 8or compute from font ascent
Deadlock or blocked tasks
Deadlock or blocked tasks
- Always release the mutex in error paths
- Prefer RAII‑style wrappers or
goto cleanuppatterns
Dependencies
| Dependency | Purpose |
|---|---|
| U8G2 | SSD1306 rendering and font handling |
| FreeRTOS | Mutex for thread safety |
| ESP32 HAL | Hardware I2C interface |
Pins.h | Board pin definitions for SDA/SCL |

