Skip to content

Auto-detect OLED controller type (SSD1306/SH1106/SH1107/SSD1309) - #11849

Open
sensei-hacker wants to merge 7 commits into
iNavFlight:maintenance-10.xfrom
sensei-hacker:feature/oled-auto-detection
Open

Auto-detect OLED controller type (SSD1306/SH1106/SH1107/SSD1309)#11849
sensei-hacker wants to merge 7 commits into
iNavFlight:maintenance-10.xfrom
sensei-hacker:feature/oled-auto-detection

Conversation

@sensei-hacker

Copy link
Copy Markdown
Member

Summary

The OLED dashboard driver (display_ug2864hsweg01.c) probes the connected
controller's status register at init and adjusts addressing/geometry to
match — instead of assuming SSD1306 for every board. SH1106 panels (132-wide
GDDRAM, only 128 visible) get the correct +2 pixel column offset applied
throughout, and clearing now uses page-by-page addressing since SH1106
doesn't support the horizontal addressing mode the old code relied on.

Supersedes #10975 and #10760, which worked around the same underlying
SH1106/garbage-on-last-line symptom without detecting the controller type.

Changes

  • detectOledController(): reads the status register, maps it to
    SSD1306 / SH1106 / SH1107 / SSD1309, falls back to SSD1306 (previous
    behavior) on read failure or an unrecognized value
  • SH1106 column offset applied via one shared helper in
    i2c_OLED_set_xy(), i2c_OLED_set_line(), and both clear functions
  • i2c_OLED_clear_display()/_quick() switched from a single horizontal-
    addressing write to page-by-page clearing for all controllers (required
    by SH1106; harmless on SSD1306/SSD1309)
  • common_hardware.c: fixed busRead() sending a spurious command byte
    before the status-register read (DEVFLAGS_USE_RAW_REGISTERS)

SH1107 detection works, but the geometry code still assumes the
128x64/8-page layout shared by SSD1306/SH1106 (SCREEN_HEIGHT is fixed at
64) — a true 128x128 SH1107 panel would only get its top half addressed.
Flagged in a code comment; untested, since I don't have SH1107 hardware.

Testing

  • Built BROTHERHOBBYF405V3 successfully (FLASH 77.0%, RAM 98.3%)
  • Hardware test on BROTHERHOBBYF405V3: SH1106 module — detected as SH1106,
    displayed correctly (no offset/garbage issues)
  • Hardware test on BROTHERHOBBYF405V3: SSD1306 module — detected as
    SSD1306, displayed correctly
  • SH1107 not tested (no hardware available)

Code Review

Reviewed with inav-code-review agent; all CRITICAL/IMPORTANT findings
(leftover debug I2C probe with a real bus-reinit side effect, a dead
test-pattern function, duplicated offset logic) addressed before this PR.

sensei-hacker and others added 7 commits August 29, 2026 13:29
Detect OLED controller type by reading status register 0x00 during
initialization. Based on ss_oled library detection algorithm.

Detection identifies:
- SSD1306: status bits 0x03 or 0x06 (most common 128x64/128x32)
- SH1106: status bits 0x08 (132x64, needs +2 pixel X offset)
- SH1107: status bits 0x07 or 0x0F (128x128 displays)

Adds LOG_ERROR debug messages to show detection results for
troubleshooting display issues.

Note: Drawing code updates for SH1106 X offset still needed.

Reference: https://github.com/bitbank2/ss_oled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SH1106 controller has 132-column GDDRAM but only 128 are visible;
the first 2 columns are hidden. Without the offset, text and graphics
render shifted 2 pixels to the left and the rightmost 2 columns are
written into the invisible region.

Also fixes clearing on SH1106: it only supports page addressing mode
and ignores the horizontal addressing mode command (0x20/0x00) used by
the previous i2c_OLED_clear_display(). The old code only cleared one
page on SH1106 instead of all 8.

Changes:
- i2c_OLED_set_xy: add +2 pixel column offset for SH1106
- i2c_OLED_set_line: add +2 pixel start column for SH1106
- i2c_OLED_clear_display: switch to page-by-page clear (works on all
  controllers); apply SH1106 column offset; remove horizontal mode cmd
- i2c_OLED_clear_display_quick: same fix
- detectOledController: downgrade informational LOG_ERROR to LOG_DEBUG;
  keep LOG_ERROR only for actual failure paths
- ug2864hsweg01InitI2C: remove empty SH1106 init placeholder stub;
  downgrade status LOG_ERROR messages to LOG_DEBUG
ug2864hsweg01TestPattern() draws a double-outline rectangle:
  - col 0: outer border, col 1: gap, col 2: inner border
  - symmetric on the right side
  - 1-pixel horizontal lines at top (page 0 bit 0) and bottom (page 7 bit 7)

Uses i2c_OLED_set_line() so the controller offset is applied transparently —
the same code works on SSD1306 (offset 0) and SH1106 (offset 2).

How to read it on hardware:
  Correct offset  : outer border flush at screen edge, 1-px gap, inner border
  Offset off by 1 : one border merges or a gap doubles
  Offset off by 2 : outer border invisible (off the left edge of the display)

Call once after ug2864hsweg01InitI2C() for hardware verification only.
Do not call from production code.
Add I2C address probe in detectOledController() that reports which
addresses ACK (0x3C and 0x3D) via LOG_DEBUG. Useful when diagnosing
hardware issues without an I2C scanner — visible in bootlog after
setting log_level=DEBUG and configuring a log serial port.

Also:
- AOCODARCH7DUAL: add USE_BOOTLOG 4096 for bootlog debugging
- ORBITF435: USE_BOOTLOG 4096 already in previous commit
- Revert "Bus device found" message back to LOG_DEBUG (was bumped
  to LOG_ERROR temporarily during hardware debugging session)
- Mark ug2864hsweg01TestPattern() call in init as TODO: remove before PR

Note: NAND flash (flash_w25n.c) had an unrelated local change that
was intentionally excluded from this commit.
Remove the hardware-test-only test pattern call from init (was drawing
a diagnostic rectangle on every boot) and the two targets' temporary
USE_BOOTLOG additions used only to debug I2C detection on hardware
without a scanner. Also note that SH1107 detection is unverified on
real 128x128 hardware, since the geometry code still assumes the
128x64/8-page layout used by SSD1306/SH1106.
The prior cleanup commit removed the test-pattern call site but left
the 85-line function itself dangling with no callers, plus a debug
I2C probe (0x3C/0x3D) that ran on every boot and triggered a real
bus reinit on the expected NAK, and several progress-narration log
lines with no diagnostic value. Also collapses the four duplicated
SH1106 column-offset checks into one helper.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

RAM / Flash usage vs. base branch — commit 738970b

No size baseline is available yet for this PR's base commit (no per-commit baseline has been published for it). This comment will show deltas once one exists — rebasing the PR refreshes its base commit.

Target Flash Δ RAM Δ
MATEKF405 701303 B (no baseline) 149524 B (no baseline)
MATEKF722 467995 B (no baseline) 125292 B (no baseline)
MATEKF765 741459 B (no baseline) 165600 B (no baseline)
MATEKH743 775487 B (no baseline) 168064 B (no baseline)

See RAM/flash optimization guide for techniques to reduce usage.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Test firmware build ready — commit 738970b

Download firmware for PR #11849

247 targets built. Find your board's .hex file by name on that page (e.g. MATEKF405SE.hex). Files are individually downloadable — no GitHub login required.

Development build for testing only. Use Full Chip Erase when flashing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant