Skip to content

Add SSD1363 256x128 greyscale OLED driver#421

Merged
thijstriemstra merged 12 commits into
rm-hull:mainfrom
nimarchetti:add-ssd1363
May 26, 2026
Merged

Add SSD1363 256x128 greyscale OLED driver#421
thijstriemstra merged 12 commits into
rm-hull:mainfrom
nimarchetti:add-ssd1363

Conversation

@nimarchetti

@nimarchetti nimarchetti commented May 22, 2026

Copy link
Copy Markdown
Contributor

What

Adds ssd1363 device class and luma.oled.const.ssd1363 constants for the
SSD1363 256×128 4-bit greyscale OLED controller, tested on the ZJY270S0700XG21
2.7" module wired to a Raspberry Pi 4 via SPI0.

Why two overrides are needed

DC-pin protocol

The SSD1363 treats DC as a per-byte signal rather than a mode signal. Only
the command opcode byte uses DC-LOW; all parameter bytes and pixel data use
DC-HIGH. Sending parameter bytes at DC-LOW causes them to be misinterpreted as
new command opcodes — for example, a row-address end value of 47 (0x2F)
activates hardware scroll and prevents the row window from being set.

command() is overridden to route parameter bytes through data() (DC-HIGH).
This is the same pattern used by ssd1322.

Byte-pair swap

Within each 2-byte column address the bytes must arrive in reverse order due to
the panel's column-remap wiring. display() is overridden to swap adjacent
byte pairs in the output buffer before writing. This matches the swap shown in
the manufacturer's er_oled_bitmap_gray() reference implementation for this
module.

Because command() already handles the DC protocol correctly, the base-class
contrast() works without a further override.

Other hardware differences from SSD1362

Feature SSD1362 SSD1363
SETCONTRAST opcode 0x81 0xC1
Mux ratio command 0xA8 0xCA
IREF command 0xAB 0xAD
Column address formula pixel_x // 2 pixel_x // 4 + 8
Write-RAM before burst not needed 0x5C required

Testing

Tested on Raspberry Pi 4 + ZJY270S0700XG21 2.7" OLED via SPI0 at 8 MHz.
Gradient fill, greyscale bars, anti-aliased text, and contrast sweep (0–255)
all render correctly across the full 256×128 pixel area.

Unit tests in tests/test_ssd1363.py follow the existing test_ssd1362.py
pattern and cover: init sequence, invalid dimensions, hide/show, contrast,
greyscale display, and monochrome display.

111 passed, 0 failed

fixes #401

The SSD1363 has two non-obvious hardware differences from SSD1362/SSD1306
that required reverse-engineering against the manufacturer's example:

1. DC-pin protocol: the SSD1363 treats DC as a per-byte signal, not a
   mode signal.  Only the command opcode byte uses DC-LOW; all parameter
   bytes and pixel data use DC-HIGH.  Without this, parameter bytes land
   as command opcodes — for example, a row-end value of 0x2F activates
   hardware scroll, preventing the row window from ever being set.
   Overriding command() to route parameter bytes through data() fixes this
   (same pattern as ssd1322).

2. Byte-pair swap: within each 2-byte column address the pair must arrive
   in reverse order due to the panel's column-remap wiring.  display() is
   overridden to swap adjacent byte pairs in the output buffer before
   writing.  This matches the manufacturer's er_oled_bitmap_gray()
   reference implementation for the ZJY270S0700XG21 2.7" module.

Other differences from SSD1362:
  - SETCONTRAST = 0xC1 (not 0x81)
  - 0xCA for mux ratio (not 0xA8)
  - 0xAD for IREF (not 0xAB)
  - Column addresses: pixel_x // 4 + 8  (panel has a +8 hardware offset)
  - 0x5C Write-RAM required before each pixel burst

Tested on Raspberry Pi 4 + ZJY270S0700XG21 via SPI0.  Gradient, greyscale
bars, anti-aliased text, and contrast sweep all render correctly across the
full 256x128 pixel area.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for the SSD1363 OLED display, implementing its specific initialization sequence, command protocol, and byte-swapping requirements for rendering. The feedback identifies a need for 4-pixel column alignment via _inflate_bbox to support partial updates correctly and suggests optimizing the byte-swapping logic in the display method for better efficiency.

Comment thread luma/oled/device/__init__.py
Comment thread luma/oled/device/__init__.py Outdated
nimarchetti and others added 2 commits May 22, 2026 10:13
Remove extra spaces used for visual alignment of assignment operators
in the ssd1363 constants and _set_position method, per PEP8 E221.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the explicit Python loop with bytearray slice assignment.
buf[0::2], buf[1::2] = buf[1::2], buf[0::2] produces the same
byte-pair swap in a single operation, avoiding the O(n) loop overhead
on a 16 KB buffer and the intermediate list conversion.

Suggested by code review on PR rm-hull#421.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread tests/test_ssd1363.py Outdated
Comment thread luma/oled/device/__init__.py Outdated
Comment thread luma/oled/device/__init__.py Outdated
@thijstriemstra

Copy link
Copy Markdown
Collaborator

can you also add the datasheet pdf to https://github.com/nimarchetti/luma.oled/blob/add-ssd1363/doc/intro.rst

@rm-hull rm-hull left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me. Happy to merge when all comments resolved. When merged I'll push out a new version

@thijstriemstra thijstriemstra left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! I also added some doc updates.

@thijstriemstra thijstriemstra merged commit 15004f7 into rm-hull:main May 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for SSD1363

3 participants