Skip to content

Rework SSD1677 4-gray refresh into per-mode single-activation waveforms - #231

Merged
lovyan03 merged 3 commits into
m5stack:developfrom
ainyan03:develop
Jul 27, 2026
Merged

Rework SSD1677 4-gray refresh into per-mode single-activation waveforms#231
lovyan03 merged 3 commits into
m5stack:developfrom
ainyan03:develop

Conversation

@ainyan03

Copy link
Copy Markdown
Contributor

Summary

Rework the SSD1677 4-gray refresh so that quality / text / fast dispatch to a shared absolute refresh path (Mode 2 face-parity recovery, parity-aware full-frame transfer, one Mode 1 activation) whose only per-mode difference is a static LUT, while fastest stays a differential monochrome update with a static LUT and software-computed transition groups.

  • quality: oscillation prefix erases image history with a group-balanced net drive, preventing ghost accumulation over repeated refreshes; the tone-forming tail runs twice so the endpoints stay as stable as the vendor waveform ones
  • text: white-first waveform, forms the four levels without a black flash
  • fast: absolute 4-gray waveform derived from the community SDK, with the black darken return shortened to 28 frames (the excess overdrive rebounds toward gray during later undriven holds)
  • fastest: 2-frame reverse-polarity prepulse plus 8-frame dose with state-aware holds outside the updated region; VCOM matches the panel offset so held pixels sit field-free
  • absolute refreshes wait on the BUSY line without the 400 ms refresh-minimum floor
  • the fastest fallback now records its display baseline, so fastest-only usage no longer degrades into a full refresh on every update

Two small library fixes ride along:

  • Make QOI_DEBUG opt-in: lgfx_qoi.c unconditionally defined it, so error paths always called fprintf(stderr), pulling newlib stdio into every build; the png/jpg decoders reference no stdio, and this aligns qoi with them (define QOI_DEBUG externally to restore the output)
  • Fix a -Wsign-compare warning in Touch_CST226::getTouchRaw(): the loop counter was int while count is uint_fast8_t, which warns on architectures where uint_fast8_t is unsigned int

Hardware validation

Waveform tuning and regression tests were run on an M5PaperMono SSD1677 panel. The quality / fast / fastest waveforms in this PR are the settled versions from that work (fast full refresh measures ~341 ms with the vendor-derived LUT; fastest keeps untouched black/gray/white pixels stable across repeated dirty-rect updates). The text waveform keeps the white-first structure; its group balance is inherently uneven, which is a known power-off ghosting trade-off of that structure.

Checks

  • PlatformIO esp32s3 (pioarduino) build with the SSD1677 test firmware
  • LUT group-balance decoder check (ssd1677_lut_balance.py) for the static LUTs
  • git diff --check

ainyan03 added 3 commits July 24, 2026 21:20
Panel_SSD1677_4Gray now dispatches quality/text/fast to a shared absolute
refresh path (Mode 2 face-parity recovery, parity-aware full-frame
transfer, one Mode 1 activation) whose only per-mode difference is a
static LUT, and fastest to a differential monochrome update with a static
LUT and software-computed transition groups.

- quality: oscillation prefix erases image history with a group-balanced
  net drive, preventing ghost accumulation over repeated refreshes; the
  tone-forming tail runs twice so the endpoints stay as stable as the
  vendor waveform ones
- text: white-first waveform, forms the four levels without a black flash
- fast: absolute 4-gray waveform derived from the community SDK, with the
  black darken return shortened to 28 frames (the excess overdrive
  rebounds toward gray during later undriven holds)
- fastest: 2-frame reverse-polarity prepulse plus 8-frame dose with
  state-aware holds outside the updated region; VCOM matches the panel
  offset so held pixels sit field-free
- absolute refreshes wait on the BUSY line without the 400 ms
  refresh-minimum floor
- the fastest fallback now records its display baseline, so a fastest-only
  usage no longer degrades into a full refresh on every update
lgfx_qoi.c unconditionally defined QOI_DEBUG, so error paths always
called fprintf(stderr). This pulls in newlib stdio and can fail to
link on cores that do not provide the _write syscall. The png/jpg
decoders reference no stdio; this aligns qoi with them.
Define QOI_DEBUG externally to re-enable the debug output.
The loop counter was int while count is uint_fast8_t. On ARM cores
uint_fast8_t is unsigned int, so the comparison triggers
-Wsign-compare (on xtensa/riscv it is unsigned char, promoted to int,
which is why ESP32 builds never warned). Harmless at runtime; use the
same type as count.
@lovyan03
lovyan03 merged commit 0f4a63b into m5stack:develop Jul 27, 2026
23 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.

2 participants