Skip to content

examples/parallel/tufty: add Displayer, faster bus, animated demo - #58

Merged
conejoninja merged 1 commit into
tinygo-org:mainfrom
davecheney:davecheney-tufty-display-improvements
Sep 12, 2026
Merged

conejoninja merged 1 commit into
tinygo-org:mainfrom
davecheney:davecheney-tufty-display-improvements

Conversation

@davecheney

@davecheney davecheney commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

Approach

  • ST7789 now implements a small local Displayer interface (Size, SetPixel, Display) backed by a static .bss framebuffer ([320*240*2]byte, ~154 KB, high-byte-first RGB565). A compile-time assertion pins the interface. No dependency on tinygo.org/x/drivers — deliberately keeping go.mod zero-require; the interface is trivial and matching upstream can happen later if we ever pull the driver into the module.
  • Framebuffer is stored as []byte and streamed via Tx8 rather than []uint16/Tx16, because piolib.NewParallel uses BitsPerPull: 8 and shifts LSB-first, so 16-bit words would silently drop the high byte. Storing high-byte-first + Tx8 matches RAMCTRL byte order.
  • busBaud is now a named constant at 15 MHz. The PIO parallel program is 3 instructions, so PIO SM clock = 3 x baud = 45 MHz. On RP2040 that gives an actual WR cycle of ~66.6 ns, just inside the ST7789 8080-II 66 ns minimum, and confirmed visually on hardware.
  • The demo cycles three animations (bouncing rectangles, a slowly-zooming Mandelbrot in Q6.26 fixed-point with no math, and a sin-LUT plasma) under all four rotations, printing per-run FPS over UART.

Notes for review

  • Display() sends the full framebuffer as a single RAMWR stream, followed by a 10us settle before dc.High(). This matches the same Tx8-return / WR-edge race we fixed in command() and FillRectangle in examples/parallel/tufty: fix ST7789 parallel display init #55: helperPushUntilStall returns on TxStall, which fires a couple of PIO cycles before the last WR falling edge propagates through the pads, so flipping DC immediately can corrupt the trailing byte.
  • Pin configuration (CS/DC/RD outputs at idle-high) is moved before piolib.NewParallel in main(), and removed from CommonInit. This closes an intermittent init race where PIO SM startup would clock zeroed OSR contents onto floating pins while CS was still an input, causing the panel to occasionally latch stray bytes and refuse to init.
  • The rotation-cycling outer loop was added on rebase to sit alongside the geometry/rotation rework in examples/parallel/tufty: fix ST7789 parallel display init #55; it exercises configureDisplayRotation end-to-end. FPS is unchanged vs the pre-rotation-cycling tip.

Verification

Hardware verified on a real Tufty 2040:

Demo FPS
bouncing rects ~40
Mandelbrot ~0.9
plasma ~14

gofmt -l . clean. tinygo build -target=tufty2040 succeeds. go.mod remains zero-require.

@davecheney

Copy link
Copy Markdown
Contributor Author

@conejoninja this PR adds Display support -- note the duplication of the Displayer interface, I dunno if you want to take a dependency there -- as well as some demos. Please let me know if you want me to break it out into smaller pieces -- just take the Display interface, etc.

@conejoninja
conejoninja requested a review from soypat September 9, 2026 12:38
@conejoninja

Copy link
Copy Markdown
Member

Is Displayer really needed? For the example I think it can be removed.

Should we create a driver in https://github.com/tinygo-org/drivers for this? If so, a new one like st7789-pio-parallel or try to use the existing driver and adding a new bus?

@soypat

soypat commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Hmmm I hadn't looked at this PR before merging the other that also adds Display method 😅
I'm ok with adding Displayer here.

As for drivers, I'm interested in future drivers evolving towards a more performant API which means reformulating tinygl and the display API to be more like this https://github.com/soypat/tinygo-seeed-grove/tree/main/drivers/ssd1306
Have not had time to actually work on the proposal though

Implement SetPixel and Display on ST7789 backed by a fixed
[320*240*2]byte framebuffer in .bss (~154KB, ~58% of RP2040 SRAM). The
buffer is stored high-byte-first so it streams straight to the panel
(RAMCTRL=0xC0, big-endian) via Tx8 with no per-frame byte swap. Add a
compile-time assertion that ST7789 satisfies the local Displayer
interface, whose signatures match tinygo.org/x/drivers.Displayer so
downstream code can substitute that interface trivially without adding
the dependency here.

Expose the PIO bus rate as a top-level busBaud constant. The PIO
program is three instructions long, so the state machine clock runs at
3 * busBaud. The ST7789 8080-II parallel interface has a 66ns minimum
write cycle (~15.15 MHz); run at 15 MHz, verified visually clean on
Tufty 2040 hardware.

Replace the solid blue fill in main() with a cycling animated demo:
bouncing rectangles, a Mandelbrot fractal zoom (fixed-point Q6.26), and
a sin-LUT plasma. Each demo reports measured FPS over UART. Measured
on Tufty 2040 at 15 MHz: bouncing rects ~40 FPS (bus-saturated
full-frame transfer), plasma ~14 FPS, mandelbrot ~0.8 FPS.
@davecheney
davecheney force-pushed the davecheney-tufty-display-improvements branch from 8ff98bd to 30f787b Compare September 10, 2026 08:16
@davecheney

Copy link
Copy Markdown
Contributor Author

@conejoninja @soypat not ignoring your comments, just rubbing my chin on what this might look like.

In my brief soirée I’ve found displays that need a frame buffer larger than sram — presto, that’s you — frame buffers that can be upscale on the fly — I have some scanvideo demos to publish — and frame buffers connected to devices that are to slow to matter — badger and st7789 over spi.

In the middle is the tufty with its Pio parallel display, which is both performant and memory hungry. I don’t have enough experience to know how the tufty generalises to other displays. Istm that anything smaller/slower benefits from the current set pixel api where the displays GRAM holds the goods.

Maybe a middle ground is to promote ST7789-parallel to drivers as is and see where their forks take it. For example, I have a branch where I yolo blocking tx because I know my frame time is longer than the 10ish ms it takes to push the fb over dma.

@conejoninja

Copy link
Copy Markdown
Member

I'm rooting for this to be promoted to drivers ... because I want to add the tufty to badges firmware 🤣

And I don't want to start a discussion here, In my opinion there could be different flavors of drivers, for example the ssd1306 uses a framebuffer and that's too big for a attiny (like gopherArcade) so I needed a bufferless version. I also consider tinygl learning step a bit to high for beginners, so again, I'm in favor of having multiple versions/flavors like driver, driver-performance, ...

In resume, if it works (and it follows as much as possible the API of similar drivers ), I'm green for it

@soypat

soypat commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

So this looks good to me, do we want to merge or are we thinking some other thing with the promotion? (I assume you are talking of tinygo-org/drivers)

@conejoninja

conejoninja commented Sep 12, 2026 •

Copy link
Copy Markdown
Member

Merging now this and then we could re-use the code to create the driver in tinygo.org/drivers . Thanks for your contribution.

@davecheney since you are the author, do you want to create the driver or are working on other displays?

@conejoninja
conejoninja merged commit 63e15d5 into tinygo-org:main Sep 12, 2026
1 check passed
@davecheney

Copy link
Copy Markdown
Contributor Author

Merging now this and then we could re-use the code to create the driver in tinygo.org/drivers . Thanks for your contribution.

@davecheney since you are the author, do you want to create the driver or are working on other displays?

I'm working on a branch now to bring the st7789 over to drivers/

@davecheney
davecheney deleted the davecheney-tufty-display-improvements branch September 13, 2026 07:49
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.

3 participants