Simple test

Ensure your device works with this simple test. It plays examples/testpattern.rv565 on any board with a built-in display (board.DISPLAY).

examples/rv565_simpletest.py
 1# SPDX-FileCopyrightText: 2026 Ayushman Bhattacharya
 2# SPDX-License-Identifier: MIT
 3"""Play an RV565 clip on a board with a built-in display (board.DISPLAY).
 4
 5Copy circuitpython_rv565.py (or .mpy) to CIRCUITPY/lib and
 6examples/testpattern.rv565 to the root of CIRCUITPY, then run this as code.py.
 7"""
 8
 9import board
10
11import circuitpython_rv565 as rv565
12
13clip = rv565.open("/testpattern.rv565")
14print("RV565 %dx%d, %d FPS, %d frames" % (clip.width, clip.height, clip.fps, len(clip)))
15
16player = rv565.Player(clip, board.DISPLAY)
17while True:
18    stats = player.play()
19    print(stats)  # achieved FPS, skipped frames, inflate and draw time per frame

Raspberry Pi Pico 2 and ST7789

A 2.0” 320x240 ST7789 on SPI0, drawn through displayio.

examples/rv565_pico2_st7789.py
 1# SPDX-FileCopyrightText: 2026 Ayushman Bhattacharya
 2# SPDX-License-Identifier: MIT
 3"""Raspberry Pi Pico 2 with a 2.0" 320x240 ST7789 on SPI0, through displayio.
 4
 5Wiring (the same as the RV565 Pico 2 benchmark):
 6SCK GP18, MOSI GP19, CS GP17, DC GP20, RST GP21, BL GP22, plus 3V3 and GND.
 7
 8CIRCUITPY needs:
 9  lib/circuitpython_rv565.py
10  lib/adafruit_st7789.mpy   (from the Adafruit CircuitPython bundle)
11  testpattern.rv565          (from examples/ in this repository)
12
13Keep clips at 180x135 or smaller on the Pico 2: a 320x240 frame needs 150 KiB
14for the inflated bytes and as much again for the bitmap.
15"""
16
17import board
18import busio
19import displayio
20from adafruit_st7789 import ST7789
21
22try:
23    from fourwire import FourWire  # CircuitPython 9 and later
24except ImportError:
25    from displayio import FourWire  # CircuitPython 8
26
27import circuitpython_rv565 as rv565
28
29displayio.release_displays()
30spi = busio.SPI(clock=board.GP18, MOSI=board.GP19)
31bus = FourWire(
32    spi,
33    command=board.GP20,
34    chip_select=board.GP17,
35    reset=board.GP21,
36    baudrate=40_000_000,
37)
38display = ST7789(bus, width=320, height=240, rotation=90, backlight_pin=board.GP22)
39
40clip = rv565.open("/testpattern.rv565")
41clip.build_index()  # validate the whole file before playing
42player = rv565.Player(clip, display)
43while True:
44    print(player.play())

Raspberry Pi Pico 2, direct to the panel

The same wiring with DirectPlayer, which sends frames straight to the controller (about twice the frame rate).

examples/rv565_pico2_direct.py
 1# SPDX-FileCopyrightText: 2026 Ayushman Bhattacharya
 2# SPDX-License-Identifier: MIT
 3"""Experimental fast path: send frames straight to the ST7789 on a Pico 2.
 4
 5RV565 frames are already in the panel's byte order, so DirectPlayer skips
 6displayio and sends each inflated frame with one bus.send(). Same wiring and
 7files as rv565_pico2_st7789.py. displayio is left without a root group while
 8this runs, so nothing else is drawn on the panel.
 9"""
10
11import board
12import busio
13import displayio
14from adafruit_st7789 import ST7789
15
16try:
17    from fourwire import FourWire  # CircuitPython 9 and later
18except ImportError:
19    from displayio import FourWire  # CircuitPython 8
20
21import circuitpython_rv565 as rv565
22
23displayio.release_displays()
24spi = busio.SPI(clock=board.GP18, MOSI=board.GP19)
25bus = FourWire(
26    spi,
27    command=board.GP20,
28    chip_select=board.GP17,
29    reset=board.GP21,
30    baudrate=40_000_000,
31)
32# The driver sends the ST7789 init sequence (rotation, inversion, colour mode).
33display = ST7789(bus, width=320, height=240, rotation=90, backlight_pin=board.GP22)
34
35clip = rv565.open("/testpattern.rv565")
36# displayio's rotation=90 is done in software, so DirectPlayer sets the
37# controller's MADCTL to landscape (0x60, as the RV565 Pico 2 benchmark does)
38# while playing and restores it afterwards. The benchmark's 320x240 module
39# needs no offset that way; if the picture is shifted, upside down or
40# mirrored on yours, pass x_offset/y_offset or madctl=0xA0.
41player = rv565.DirectPlayer(clip, bus, 320, 240, display=display)
42while True:
43    print(player.play())

ESP32-S3 TFT Feather

examples/rv565_esp32s3_tft.py
 1# SPDX-FileCopyrightText: 2026 Ayushman Bhattacharya
 2# SPDX-License-Identifier: MIT
 3"""ESP32-S3 board with a built-in ST7789: the Adafruit ESP32-S3 TFT Feather.
 4
 5Its 240x135 display is already set up as board.DISPLAY, so the 180x135 test
 6pattern fits at native size. Other ESP32-S3 boards with board.DISPLAY work
 7the same way; for a separate SPI panel, set it up as in
 8rv565_pico2_st7789.py with your board's pins.
 9
10The clip can live on CIRCUITPY or on an SD card mounted with sdcardio and
11storage.mount (for example "/sd/clip.rv565"); frames are read from the file
12one at a time, so the clip does not have to fit in RAM.
13"""
14
15import board
16
17import circuitpython_rv565 as rv565
18
19display = board.DISPLAY
20clip = rv565.open("/testpattern.rv565")
21print("RV565 %dx%d, %d FPS, %d frames" % (clip.width, clip.height, clip.fps, len(clip)))
22
23player = rv565.Player(clip, display)
24while True:
25    stats = player.play(loops=3)
26    print(stats)