What is an OLED Display?
An OLED (Organic Light Emitting Diode) display is a grid of microscopic LEDs — each of the 128 × 64 = 8,192 pixels on your kit's screen makes its own light. There's no backlight, which is why OLED black is truly black: those pixels are simply off.
Your kit's panel: 0.96", 128×64 monochrome, SH1106 controller chip, I2C interface.
Connection (I2C)
I2C is a two-wire bus: one wire for data (SDA), one for the clock (SCL). Every device on the bus has an address — your display answers at 0x3C — so multiple I2C devices can share the same two pins.
| OLED Pin | HERO Pin | |----------|----------| | VCC | 5V | | GND | GND | | SDA | A4 | | SCL | A5 |
Four wires total, two of them power. That's the whole hookup for 8,192 pixels.
SH1106 vs SSD1306 — Read This Before Copying Tutorials
Most online OLED tutorials assume the SSD1306 chip. Yours is an SH1106. They're near-twins, but the SH1106's internal memory is 132 columns wide while the panel shows 128 — SSD1306 code writes into the wrong columns, so you get a screen that's shifted, wrapped, or showing a band of garbage while compiling perfectly.
The fix is one line — use the SH1106 constructor:
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); // ✔ your display
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C ... // ✘ shifted garbage
How U8g2 Works: The Buffer Cycle
The _F_ in the constructor means full framebuffer: U8g2 keeps a complete copy of the screen (128×64 ÷ 8 = 1,024 bytes) in the HERO's SRAM — that's half your 2KB of RAM. You draw into that buffer, then ship it to the display in one go:
u8g2.clearBuffer(); // 1. wipe the canvas
u8g2.drawStr(0, 12, "Hi"); // 2. draw everything for this frame
u8g2.sendBuffer(); // 3. push the frame to the glass
Nothing appears until sendBuffer(). If your screen stays blank but the code runs, this is the first thing to check.
Short on RAM? U8g2 has _1_ and _2_ page-mode constructors that use 128/256 bytes instead, at the cost of a redraw loop.
Drawing Toolbox
| Call | Draws | |------|-------| | drawStr(x, y, "text") | Text — y is the baseline (bottom of the letters), not the top | | setFont(u8g2_font_...) | Pick from hundreds of built-in fonts | | drawLine / drawFrame / drawBox | Lines, outlines, filled rectangles | | drawCircle / drawDisc | Outlined / filled circles | | drawXBM(x, y, w, h, bitmap) | Bitmap images — how Days 26–28 draw the autopilot graphics |
Display Coordinates
(0,0) ────────────── (127,0)
│ │
│ 128 x 64 pixels │
│ │
(0,63) ───────────── (127,63)
Top-left is (0,0); x grows right, y grows down. The classic beginner bug: drawStr(0, 0, "Hello") prints above the screen because y=0 is the text baseline. Use y ≥ the font height (e.g. 12).
Where You'll Use It
| Mission | What it does | |---------|--------------| | Day 21 | "Hello New World" — first pixels | | Day 22 | Display panel layouts and fonts | | Day 23–24 | Launch system readouts | | Day 26 | Bitmap graphics (drawXBM) — HERO_AUTOPILOT.EXE | | Day 27–29 | Autopilot + landing gear animation sequences |
Tips
- A full
sendBuffer()over I2C takes ~30ms — don't redraw frames that haven't changed - Draw everything between clear and send; anything drawn after
sendBuffer()waits for the next frame - Text wrapping is manual — measure with
getStrWidth()if you need to fit text
Common Mistakes
- Blank screen: forgot
sendBuffer(), wrong constructor, or SDA/SCL swapped - Shifted / garbage columns: SSD1306 constructor on this SH1106 panel (see above)
- Sketch suddenly unstable after adding the display: you're out of SRAM — the framebuffer took 1KB; trim big arrays and wrap literal strings in
F()