Pimoroni’s documentation for the HyperPixel 2.1 Round says this:
> Note that the kernel drivers for Round do not include touch support.
That sentence is accurate, and it cost me an evening. It’s accurate about the *kernel* drivers. It is not the whole story, and the way I eventually got a five-point multitouch screen working on Bookworm has, as far as I can tell, never been written down.
I tried both official sources first, to the letter. The getting started guide walks you through a working display and then tells you touch isn’t available. The hyperpixel2r installer runs without a single error and changes nothing that matters, because it writes to a file Bookworm no longer reads. And hyperpixel2r-python, the touch library itself, dies on startup looking for an I2C bus that isn’t there.
Neither document is wrong. Both assume an environment that stopped existing after Bullseye. Following them, I never got touch working once.
Short version: touch works. It needs the legacy display driver instead of the modern KMS one, and it needs the *deprecated* GPIO library rather than the one the docs tell you to use. Here’s why, because the “why” is the interesting part.
The kernel driver really can’t do it
Raspberry Pi OS ships an overlay for this display, vc4-kms-dpi-hyperpixel2r. Enable it and you get a working 480×480 screen with the modern KMS stack. No touch, exactly as advertised.
But decompile that overlay and you find the touch controller is right there:
i2c@0 {
compatible = "i2c-gpio";
status = "disabled";
gpios = <&gpio 10 0 &gpio 11 0>;
edt-ft5x06@15 {
compatible = "edt,edt-ft5406";
interrupts = <27 2>;
};
};
A FocalTech FT5x06 at address 0x15, on a bit-banged I2C bus using GPIO 10 and 11, with its interrupt on GPIO 27. Everything you need — declared, then switched off with status = "disabled".
So I wrote a two-line overlay to flip it back on. The touchscreen appeared immediately as a proper input device. The display died just as immediately:
vc4-drm soc:gpu: [drm] Cannot find any crtc or sizes
vc4-drm went into an endless probe loop. Thousands of retries, no DRM card, CPU pegged.
My first theory was a conflict with the DPI data lines. Wrong. The pin group in use is dpi_18bit_cpadhi_gpio0:
0 1 2 3 4 5 6 7 8 9 12 13 14 15 16 17 20 21 22 23 24 25
GPIO 10 and 11 are deliberately skipped — “cpadhi” exists precisely so those two pins stay free for I2C. The real conflict was elsewhere:
gpio-10 (GPIO10 |mosi ) gpio-11 (GPIO11 |sck )
They were held by the panel’s *bit-banged SPI*, which the same overlay declares so the kernel st7701 driver can send the display’s initialisation sequence.
That SPI is only needed once, at startup. So — release it afterwards?
echo spi3.0 | sudo tee /sys/bus/spi/drivers/st7701/unbind
The screen went black instantly. The st7701 driver doesn’t just initialise the panel, it owns its power management. Detach it and the display powers down.
That closes the case: with the kernel driver, GPIO 10 and 11 can never be freed while there is an image on screen. Pimoroni’s sentence is not an omission, it’s a structural fact.
The legacy driver solves it differently
Pimoroni’s own hyperpixel2r drivers take a completely different route. Their overlay declares no panel and no SPI node at all, and enables the touch I2C bus with no disabled status. Instead, the display is driven by the firmware:
enable_dpi_lcd=1 dpi_group=2 dpi_mode=87 dpi_output_format=0x7f216 dpi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6
and the panel is initialised by a systemd oneshot running a 412-line Python script that bit-bangs the ST7701 init sequence over GPIO, then exits.
That’s the whole trick. A kernel driver holds its pins for as long as it’s bound. A userspace script hands them back when it terminates. Same hardware, same pins, opposite lifetime.
Trap 1: fake KMS isn’t fake any more
Their installer doesn’t touch your vc4 overlay line, because on the Pi 4 they targeted, vc4-fkms-v3d was typically already in place. Fake KMS leaves display setup to the firmware, which is what those dpi_timings need.
On a Pi Zero under Bullseye I dutifully switched vc4-kms-v3d to vc4-fkms-v3d. Black screen. The logs said:
vc4-drm soc:gpu: bound 20206000.pixelvalve vc4-drm soc:gpu: [drm] Cannot find any crtc or sizes
Binding pixelvalve and HVS is *full* KMS behaviour. On late Bullseye releases, vc4-fkms-v3d has become an alias for the full KMS driver. The rename didn’t do what its name implies.
The fix is not to swap the overlay. It’s to have no vc4 overlay at all:
#dtoverlay=vc4-kms-v3d #dtoverlay=vc4-fkms-v3d
With both commented out, the old bcm2708_fb driver takes over and everything falls into place:
bcm2708_fb soc:fb: FB found 2 display(s) Console: switching to colour frame buffer device 60x30 bcm2708_fb soc:fb: Registered framebuffer for display 0, size 480x480
You lose 3D acceleration. On a Pi Zero W with no desktop, that costs nothing.
Bookworm still has the legacy stack
I assumed this pinned me to Bullseye forever, since Bookworm went all-in on KMS. It doesn’t. bcm2708_fb is still there — it just isn’t a module any more, so looking for a .ko finds nothing. It’s built into the kernel:
ls /sys/bus/platform/drivers/ | grep bcm2708_fb
If that prints, the legacy path is available. It does on Bookworm’s 6.12 kernel.
Two path adjustments are needed, since the installer was written for Bullseye. /boot/overlays already exists as a symlink, so the overlay lands correctly. But /boot/config.txt on Bookworm is a decoy file that says “DO NOT EDIT THIS FILE” — the installer happily appends its six lines to it and they’re never read. Add them to /boot/firmware/config.txt by hand instead, and restore the decoy.
Trap 2: the recommended GPIO library is the wrong one
With everything in place, the init service failed:
lgpio.error: 'GPIO not allocated' at GPIO.setup(clkPin, GPIO.OUT)
Since Bookworm, the guidance everywhere is to replace RPi.GPIO with python3-rpi-lgpio, a drop-in that reimplements the API on top of lgpio. It is the modern, correct, well-behaved choice.
And that’s exactly the problem. rpi-lgpio goes through the kernel’s GPIO subsystem, so it respects other drivers’ claims — and the touch i2c-gpio bus has legitimately claimed GPIO 10 and 11. It refuses to touch them.
The old RPi.GPIO writes straight to the registers via /dev/gpiomem and ignores kernel bookkeeping entirely. Which is precisely what this board needs, since the panel’s init SPI and the touch I2C are *designed* to share those pins.
sudo apt remove python3-rpi-lgpio sudo apt install python3-rpi.gpio
Worth knowing: the widely repeated “RPi.GPIO is broken on Bookworm” applies to the Pi 5 and its RP1 chip. On a BCM2835 Pi Zero it works fine.
The result
Input device name: "11-0015 generic ft5x06 (00)" ABS_X 0 → 479 ABS_Y 0 → 479 ABS_MT_POSITION_X 0 → 479 ABS_MT_POSITION_Y 0 → 479 ABS_MT_SLOT 0 → 4
Five-point multitouch, coordinates matching the panel exactly, exposed as a standard Linux input device on /dev/input/event0. Not a Python library you have to poll — a real evdev device, usable by anything.
That last point is worth emphasising, because Pimoroni’s README says touch is “only supported via the Python library”. Via the legacy driver, it isn’t: the kernel edt-ft5x06 driver binds to it and you get mouse0 and event0 for free.
One more thing that will waste your time
The ST7701 keeps its internal state across a warm reboot. If you get the configuration wrong once, then fix it, reboot will not bring the display back. Everything will look correct — connector connected, mode set, backlight on, a plane scanning out at 480×480 — and the panel will still show nothing.
Only a full power cycle clears it. Unplug, wait ten seconds, plug back in.
I spent a while chasing a ghost before working that out.
The complete procedure
From a fresh Raspberry Pi OS Bookworm, 32-bit (armhf), Lite install on a Pi Zero W, with SSH access. Every step matters; the two marked ⚠ are the ones that cost me the evening.
1. Check the legacy framebuffer driver is present. If this prints nothing, stop — nothing below will work on your kernel.
ls /sys/bus/platform/drivers/ | grep bcm2708_fb
2. Install git.
sudo apt update sudo apt install -y git
3. ⚠ Get the GPIO library right. The init script writes to the GPIO registers directly. rpi-lgpio goes through the kernel and will refuse the pins, because the touch I2C bus has already claimed them.
sudo apt remove -y python3-rpi-lgpio sudo apt install -y python3-rpi.gpio
4. Install the Pimoroni display driver.
git clone https://github.com/pimoroni/hyperpixel2r cd hyperpixel2r sudo ./install.sh
This installs the overlay, the init script and its systemd service. It also appends six lines to /boot/config.txt, which on Bookworm is a placeholder file nothing reads. The next two steps deal with that.
5. Restore the placeholder file the installer overwrote.
printf 'DO NOT EDIT THIS FILE\n\nThe file you are looking for has moved to /boot/firmware/config.txt\n' | sudo tee /boot/config.txt
6. ⚠ Disable every vc4 overlay. Not swap it for fake KMS — remove it. On late Bullseye and on Bookworm, vc4-fkms-v3d behaves as full KMS, and full KMS has no panel to drive here.
sudo cp /boot/firmware/config.txt ~/config.txt.backup sudo sed -i 's/^dtoverlay=vc4-kms-v3d/#dtoverlay=vc4-kms-v3d/' /boot/firmware/config.txt sudo sed -i 's/^dtoverlay=vc4-fkms-v3d/#dtoverlay=vc4-fkms-v3d/' /boot/firmware/config.txt
7. Add the display settings to the real config file.
sudo tee -a /boot/firmware/config.txt > /dev/null <<'EOF' # Pimoroni HyperPixel 2.1 Round - firmware-driven DPI dtoverlay=hyperpixel2r enable_dpi_lcd=1 dpi_group=2 dpi_mode=87 dpi_output_format=0x7f216 dpi_timings=480 0 10 16 55 480 0 15 60 15 0 0 0 60 0 19200000 6 EOF
8. Reboot.
sudo reboot
9. Verify. The framebuffer, the init service and the touch device:
ls -l /dev/fb0 cat /sys/class/graphics/fb0/virtual_size journalctl -b -u hyperpixel2r-init.service grep -E '^N: Name=' /proc/bus/input/devices
You want 480,480, a service that reports *Finished*, and an input device named generic ft5x06. Then test touch for real:
sudo apt install -y evtest sudo evtest
Pick the ft5x06 device and drag a finger across the screen. Coordinates should run 0 to 479 on both axes.
If the screen is black at this point, power cycle before debugging anything. The ST7701 survives a warm reboot with its previous state intact. Unplug, wait ten seconds, plug back in. Only then start looking for a real problem.
In short
Three things, and none of them are in the official docs: no vc4 overlay at all, the config lines in /boot/firmware/config.txt rather than /boot/config.txt, and python3-rpi.gpio instead of the rpi-lgpio everyone now recommends.
You get a 480×480 display and five-point multitouch, as a standard Linux input device, on a distribution supported until 2028.