fix(epd7in5_v2): match Waveshare reference framebuffer polarity#258
Open
m5r wants to merge 1 commit into
Open
Conversation
`update_frame` was sending the buffer verbatim to DTM2 (0x13), causing
every framebuffer to render with bit polarity inverted on the actual
panel: `Color::White` (bit 1) showed as black, `Color::Black` (bit 0)
showed as white. Symmetric test patterns hide this; any image with
asymmetric content does not.
Waveshare's reference C demo
`RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_7in5_V2.c::EPD_7IN5_V2_Display`
sends the user buffer raw to DTM1 (0x10) and bitwise-NOT to DTM2 (0x13).
The Python driver `epd7in5_V2.py::display` does the same on the wire,
just with the opposite user-facing buffer convention (it pre-inverts in
`getbuffer` per its own `e-paper world 0=white, 1=black` comment). The
panel's DTM2 register expects bit 0 = white per the UC8179 datasheet
§22, KW mode with NEW/OLD, DDX=00: `{NEW=0, OLD=0} -> LUTWW`.
This patch:
- adds `DisplayInterface::data_inverted` that streams `~data` via a 256-
byte stack chunk, avoiding heap allocation for the 48 KB framebuffer.
- changes `Epd7in5::update_frame` to write DTM1 raw + DTM2 inverted,
matching the C demo. Writing both forces a full LUTKW/LUTWK transition
for every pixel, producing strong contrast.
- changes `Epd7in5::clear_frame` to write DTM1=0xFF + DTM2=0x00, matching
`EPD_7IN5_V2_Clear`. Previously both were 0x00 which goes through
LUTWW (stays white) — works for a freshly-powered panel but doesn't
force a clean transition from a prior image.
Verified on real hardware: ESP32-S3 driving a Waveshare 7.5" e-Paper V2
(G) panel via the Universal Driver HAT Rev 2.3. Before the patch, the
smoke binary's white-bg + black-text framebuffer rendered as black-bg
with white text. After the patch, it renders correctly without any
app-side color swap.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #256.
Summary
update_frameinEpd7in5(V2) was sending the user buffer verbatim to DTM2 (0x13), causing every framebuffer to render with bit polarity inverted on the actual panel:Color::White(bit 1) showed as black,Color::Black(bit 0) showed as white. Symmetric test patterns hide this; any image with asymmetric content does not.Issue #256 documents the same symptom — the reporter suggested
buffer_mut().iter_mut().for_each(|b| *b = !*b)as a workaround, which is essentially what this PR does inside the driver.Root cause
Waveshare's reference C demo
EPD_7IN5_V2_Display()sends the user buffer raw to DTM1 (0x10) and bitwise-NOT to DTM2 (0x13). The Python driverdisplay()does the same on the wire, just with the opposite user-facing buffer convention (it pre-inverts ingetbufferper its owne-paper world 0=white, 1=blackcomment).The panel's DTM2 register expects
bit 0 = whiteper the UC8179 datasheet §22, KW mode with NEW/OLD, DDX=00:{NEW=0, OLD=0} -> LUTWW. epd-waveshare'sColor::White → bit 1encoding means the buffer must be inverted before reaching0x13.Changes
DisplayInterface::data_inverted— new method, streams~datavia a 256-byte stack chunk (no heap allocation, fits the 48 KB framebuffer comfortably).Epd7in5::update_frame— writes DTM1 raw + DTM2 inverted, matching the C demo. Writing both forces a fullLUTKW/LUTWKtransition for every pixel, producing strong contrast.Epd7in5::clear_frame— writes DTM1=0xFF+ DTM2=0x00, matchingEPD_7IN5_V2_Clear. Previously both were0x00, which goes throughLUTWW(stays white) — works for a freshly-powered panel but doesn't force a clean transition from a prior image.Verification
Tested on real hardware: ESP32-S3 driving a Waveshare 7.5" e-Paper V2 (G) panel via the Universal Driver HAT Rev 2.3, using esp-hal 1.0 + embedded-hal 1.0. Before the patch, a simple
clear(Color::White)+Text "hello world" in Color::Blackframebuffer rendered as solid black with white text. After the patch, it renders correctly white-bg-black-text without any application-side color swap.cargo fmt --check,cargo check --lib, andRUSTDOCFLAGS=-Dwarnings cargo doc --no-depsall pass.Test plan
cargo check --lib)cargo fmt --check)RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps)