Repository navigation
Play GIF animation on e-paper displays - #11740
Open
mikeysklar wants to merge 58 commits into
Open
mikeysklar wants to merge 58 commits into
mikeysklar wants to merge 58 commits into
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After a refresh finishes, write the same areas again with this command so the controller's previous image RAM matches the screen. This lets SSD168x style partial updates diff against what is actually shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A keep_awake display ends a transaction still holding its bus when the VM ends, since Ctrl-C can leave one open and the stop sequence would otherwise wait for the bus forever. The stop sequence is also guarded when it follows a refresh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous RAM holds frame N-lag instead of N-1, so each changed pixel is driven for lag_frames updates, the same number toward black and toward white. Only the box around changed bytes is sent. clean_sequence runs before the first refresh and when the display is released, leaving the panel white and balanced. A waveform or panel reset cut short leaves the panel dark, so while one is under way an interrupt waits and is raised when it ends. A send it stops starts over. Waits are bounded per update so a stuck panel can't hang shutdown, and the watchdog is fed while interrupts are held. CIRCUITPY_EPAPERDISPLAY_LAG gates it, off by default and on for Feather RP2040 ThinkInk. clean_sequence is accepted on every build. lag_frames raises ValueError where the drive is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings every pixel to white, optionally runs clean_sequence, then drives every pixel frames updates each way. For scripts to remove ghosting while running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
release_displays() lost the owed drive and the stop sequence silently when something held the bus for the whole 30 s bound. Wait for the bus first, and raise with every display untouched, so the script can free it and try again. The end of the VM can't catch an exception, and doesn't need to: nothing can still hold the bus by then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wait used the whole deadline, so a panel a reset would free got no clean. Reset once, wait once more with no renewal, and run the stored waveform if BUSY falls. If it stays high, nothing more is sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Packed pixels with each row padded to a whole byte, so a 1-bit source can stream into a plain buffer. Framebuffer targets stay whole bytes per pixel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A bits_per_pixel argument picks RGB565 or packed 1-bit frames, for e-paper. A pixel is white when its luma is at least half, so a black and white GIF converts exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AnimatedGIF refuses anything wider than 320 pixels, so 400x300 and 800x480 e-paper animations would not open. CIRCUITPY_GIFIO_MAX_WIDTH stays 320 by default, so other boards don't pay for a longer line buffer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy whole bytes when the rects line up and no layer above claimed the pixels. Polarity and bit order already match a monochrome EPaperDisplay: MSB first, 1 = white. Falls back to a per-pixel copy that honors the mask. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This is the board the 1 bit GIF numbers come from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The faster refresh options (write_previous_ram_command, keep_awake and update_refresh_mode's refresh_sequence) cost about 900 bytes, which no longer fits on several SAMD21 and SAMD51 boards. With the flag off, EPaperDisplay builds as it did before. Lag drive needs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
It was only on for the Feather RP2040 ThinkInk, but external panels need it too. It costs about 7 KB of flash and 80 bytes of RAM. The frame memory is only allocated when lag_frames is used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each frame is driven toward once and away from once, lag steps later. Adds a small example of a pixel that changes back early. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # ports/raspberrypi/boards/adafruit_feather_rp2040_thinkink/mpconfigboard.mk
# Conflicts: # shared-module/videogif/GifDecoder.c
epaperdisplay-fast was rebased onto main after #11738 merged, and lag drive now builds with CIRCUITPY_EPAPERDISPLAY_FAST. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tannewt
requested changes
Nov 9, 2026
The AnimatedGIF line buffer was a fixed MAX_WIDTH array in GIFIMAGE, so the widest GIF was a build setting. Make it a pointer and allocate iCanvasWidth bytes after GIF_init(): on the VM heap for gifio.OnDiskGif, with port_malloc for videogif.GifDecoder. This drops CIRCUITPY_GIFIO_MAX_WIDTH and the 320 pixel limit. Reject frames that extend past the right edge of the canvas, since the buffer is now exactly canvas wide. Also trim the VideoBuffer bits_per_pixel docstring per review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tannewt
requested changes
Nov 10, 2026
GIF_init now takes the line buffer and its size, and fails with GIF_TOO_WIDE if the canvas is wider. Passing NULL and 0 only measures the canvas, so OnDiskGif and videogif measure, allocate, then init. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # shared-bindings/videocore/VideoBuffer.c # shared-module/videocore/VideoBuffer.c
Map each screen pixel back to the source the same way the 16-bit copy does. Keep the whole-byte copy when source x runs forward along screen x, and read bit by bit otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gifio line buffer change pushed the ru build 4 bytes over flash. The dongle has no display, so gifio isn't useful there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
Author
|
Merged main and resolved the conflict with #11829. The 1-bit copy now follows display rotation too, using the same mapping as the 16-bit path. Tested on a Feather RP2040 ThinkInk,.
Also turned off
|
My local uncrustify reindented one line of the macro; put it back the way main has it so CI's formatter passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now turns off msgpack on nRF52840 internal-flash boards, which frees far more than the 4 bytes the ru build was over. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What
GIFs can now play as 1-bit video on monochrome e-paper, through displayio.
Why
A stock e-paper update takes about 6 seconds, too slow for animation.
Part 3 of 3, stacked on #11739, which is stacked on #11738.
lag3_nf1_hq_autoclean_wipes.mp4
Feather RP2040 ThinkInk with the 4.2" panel, filmed on an earlier build of this stack. The script also ran a wipe every 4 s and a clean every 15 s.
VideoBuffer(bits_per_pixel=1)ValueErrorTest files
Test GIF:
teapot_1bit_hq.gif(400x300, 120 frames at 20 ms)Test driver:
ssd1683_lag.py(needs a fast build, see #11739)Video uses the fast updates from #11739, so its panel warning applies here.
AI assistance
Written with Claude Code.
🤖 Generated with Claude Code