---
title: "The monitor forgot what black looked like"
locale: "en"
url: "https://irz.fr/en/articles/pico-vga-scanvideo-six-pins-en"
markdown_url: "https://irz.fr/en/articles/pico-vga-scanvideo-six-pins-en.md"
category: "tech"
tags: ["RP2040", "VGA", "PIO", "Scanvideo", "ZX Spectrum", "Arduino"]
published_at: "2026-08-25T17:00:00.000Z"
author: "Léa Perrin"
translation: "https://irz.fr/fr/articles/pico-vga-scanvideo-six-pins-fr.md"
---

# The monitor forgot what black looked like

Dissecting the RP2040 scanvideo library, Kevin went from seventeen VGA pins down to six, enough for the ZX Spectrum palette. And one missing black pixel was enough to dim the whole screen.

The screen did show the ZX Spectrum colors. None of them looked right, though: everything seemed washed into a dirty gray, including what should have been bright white. Neither the monitor, nor the resistor DAC, nor the video library was at fault. One single black pixel was missing from the end of each line.

That detour through a dull screen is the latest stop in *Simplified Pico VGA*, a series Kevin has been publishing since July [1](https://emalliab.wordpress.com/2026/07/25/simplified-pico-vga/). His goal fits in one sentence: do VGA on a Raspberry Pi Pico without treating the `scanvideo` library like a black box. With a personal constraint that complicates things a bit: staying inside the Arduino environment [2](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/). Adafruit picked up the series in late July, then again on August 24 [3](https://blog.adafruit.com/2026/08/24/simplified-raspberry-pi-pico-vga/).

## Seventeen pins

The official starting point spares no expense. The RP2040 hardware design manual documents an example board that produces VGA with three resistor DACs, five bits per red, green and blue channel. Five pins per color, plus HSYNC and VSYNC: seventeen GPIO for video alone [4](https://github.com/raspberrypi/pico-playground/tree/master/scanvideo). A stock Pico exposes twenty-six pins, so that doesn't leave much room for anything else.

It's the design behind Pimoroni's Pico VGA Demo Base, which wraps it with an SD slot and I2S audio output [5](https://shop.pimoroni.com/products/pimoroni-pico-vga-demo-base). For breadboard work, each channel wires up as a five-resistor ladder — 8K, 4K, 2K, 1K, 500R — with two 47R resistors on the sync lines [2](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/).

> Illustration: Two DAC setups side by side on a VGA test board: five resistors per channel on the left, RGBY1111 configuration with diodes on the right. On the left, the full RGB555 DAC with five resistors per channel. On the right, the RGBY1111 variant: four color wires and some diodes. Credit: [Kevin / diyelectromusic](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/).

Seventeen pins is the price of convenience. The rest of the series spends its time haggling over it.

## Hunting wires

Before writing anything, Kevin surveyed what already existed, and every project tells a different trade-off story.

Miroslav Nemecek's PicoVGA gets down to nine pins by moving to R3G3B2: three bits of red, three of green, two of blue, plus composite sync. Its author owns the math: with 264 KB of RAM, anything beyond 8 bits per pixel makes little sense on RP2040, and dithering claws back part of the loss [6](http://www.breatharian.eu/hw/picovga/index_en.html). That project has since been superseded by DispHSTX, which uses the RP2350's HSTX peripheral to drive DVI and VGA alike [7](http://www.breatharian.eu/hw/disphstx/index_en.html). Another route, another purpose: MCEBlaster reads period-correct TTL signals from MDA, CGA and EGA cards and converts them for a modern VGA monitor, using eight pins — two bits per color plus both syncs [8](https://github.com/scrapcomputing/MCEBlaster).

The breakthrough came from somewhere else entirely. While trying to recreate the ZX Spectrum palette, Kevin stumbled onto pico-zxspectrum, which drives VGA in a mode called RGBY1111: blue, green, red on one pin each, and a fourth pin carrying brightness [9](https://github.com/fruit-bat/pico-zxspectrum). That Y is inherited straight from the 1982 Spectrum architecture: its color attributes apply to eight-by-eight blocks, and brightness hits the whole block. Fifteen genuinely distinct colors — black exists in a "bright" version, hence duplicated — were already enough for the games of the era.

> **Count pins before colors**
> - RGB555: five bits per channel, two syncs.: 17
> - R3G3B2: three, three, two bits and composite sync.: 9
> - CGA/EGA TTL conversion: two bits per channel.: 8
> - Kevin's final RGBY1111: four color wires, two syncs.: 6
> IRZ survey: Raspberry Pi/Pimoroni designs, PicoVGA, MCEBlaster, and Kevin's documented final build.

From seventeen down to six. What you pay with is nuance: no soft orange or pale blue here, just fifteen blunt shades.

## Pixels as instructions

What remained was understanding how `scanvideo` actually drives those pins, and that's where the series gets really good.

The library lives in pico-extras [10](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/README.adoc). The CPU never touches the pins. It fills buffers with sixteen-bit tokens, DMA pushes them toward a PIO state machine, and the PIO streams pixels out at whatever rate the mode demands. For the default mode the docs assume 5-5-5 plus an optional transparency pin, all movable through build definitions [10](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/README.adoc).

The trick hides inside the PIO program named `video_24mhz_composable_default` [11](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/scanvideo.pio). Its first useful instruction is `out pc, 16`: it takes sixteen bits from the data stream and loads them into... the program counter. Every token chooses what runs next. A COLOR_RUN token jumps to the block that puts a color on the pins, reads a pixel count, loops over it, then fetches the next token. Flat areas become very compact — the docs describe it as run-length encoding for solid color regions [10](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/README.adoc) — and two timing parameters even get rewritten at runtime to stretch pixels for the target resolution [11](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/scanvideo.pio).

> pico_scanvideo
> **A video line becomes a token stream**
> - The CPU writes 16-bit tokens into a scanline buffer.: Fill
> - DMA pushes the buffer into the PIO FIFO.: Move
> - Each token jumps the program counter somewhere new.: Decode
> - The PIO places colors on the pins, cycle by cycle.: Drive
> Mechanism of the pico-extras composable program.

I've rarely seen a data bus play the role of a program this literally. The image and the instructions that draw it live in the same memory.

## The Arduino detour

Officially, you consume `scanvideo` in C with the Raspberry Pi SDK. Kevin insists on his Arduino IDE, so he moved the library over by hand onto Earle Philhower's Arduino-Pico core [12](https://github.com/earlephilhower/arduino-pico).

The files go flat into the sketch folder. The two PIO programs must be assembled first: he pushes the `.pio` files through Wokwi's pioasm tool and pastes the result into two headers. And since video modes are configured through preprocessor definitions compiled deep into the library's C files, a simple `#define` before the include isn't enough: he grafts a small `vgamode.h` straight into `scanvideo.h`. The function that ran on the second core splits between `setup()` and `loop()`, the Arduino way of saying "initialization" and "infinite loop".

Kevin also designed a test board sitting between the Pico and the VGA socket, published along with its schematic [13](https://github.com/diyelectromusic/sdemp_pcbs/tree/main/PicoVGABreakout). One honest detail from his post: the printed text recommends 300R + 100R for RGBY1111, but the correct value is 330R, as silkscreened right next to the parts.

> Illustration: Render of the PicoVGABreakout PCB connecting a Raspberry Pi Pico to a VGA socket with resistor footprints. Kevin's PicoVGABreakout test board, built to try several DACs without rewiring the breadboard each time. Credit: [Kevin / diyelectromusic](https://github.com/diyelectromusic/sdemp_pcbs/tree/main/PicoVGABreakout).

## Everything went gray

First attempt at RGBY1111: the right colors show up, but all too dark. The bright white bar at the bottom of the test pattern comes out a dingy gray.

The investigation runs three acts. First, Kevin suspects buffer structure: his line was one big run where the official example chopped every line into thirty-two chunks. He mimics the chunking and the image looks correct. Then the oscilloscope shows something sharper: on the failing version the blue pin stays constantly high, while the working version drops back to zero, synchronized with each line [2](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/).

The real culprit isn't the chunking. It's the black pixel that comes with it: the working version ends its line with a RAW_1P token in black, the broken one doesn't. And rereading the documentation turns up a warning in capital letters: every scanline must end with at least one black pixel, otherwise your color "will bleed into the blanking" [10](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/README.adoc).

Why does that dim everything? Here Kevin admits he doesn't know exactly. A reader sent him a note from Ken Shirriff describing the same symptom: after forgetting to blank the areas outside the picture, his image stayed visible but "very dim because the monitor got confused about what voltage represented 'dark'" [14](https://www.righto.com/2018/04/#fn:blanking). The likeliest reading: the monitor uses the blanking porch to calibrate what "off" means. If that region carries a color, the whole reference slides. Some shadow remains, and Kevin shares it willingly: the precise electrical mechanism is not proven anywhere in the series.

## Black, restored

Third version of the code, one black token added at the end of the line: all fifteen colors land exactly right, brightness included [2](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/).

> Final build
> **A Spectrum on VGA, done by hand**
> - GPIO pins used: 6
> - distinct colors: 15
> - pixel clock at 640×480: 25 MHz
> RGBY1111 mode as documented in the series; clock taken from pico-zxspectrum timings.

In the end, six pins do the job: four color wires and both syncs, since Kevin keeps VSYNC where pico-zxspectrum does without it [1](https://emalliab.wordpress.com/2026/07/25/simplified-pico-vga/)[2](#ref-2].

What this series describes goes beyond retro fun. A video signal designed in 1986 for analog TV sets still gets negotiated today in pins, resistors and cycles: every saved wire costs color depth, and one forgotten pixel can make the whole screen lie. You can use `scanvideo` without knowing any of this. But whoever follows the descent — tokens, DMA, blanking — can now invent their own video mode instead of copying a `#define`. Kevin, for one, kept going: the series has since spilled over into a Spectrum-compatible video output for the RC2014 hobby computer.

## References

1. [Kevin, Simplified Pico VGA (part 1), July 25, 2026](https://emalliab.wordpress.com/2026/07/25/simplified-pico-vga/)
2. [Kevin, Simplified Pico VGA – Part 2, August 1, 2026](https://emalliab.wordpress.com/2026/08/01/simplified-pico-vga-part-2/)
3. [Adafruit, Simplified Raspberry Pi Pico VGA, August 24, 2026](https://blog.adafruit.com/2026/08/24/simplified-raspberry-pi-pico-vga/)
4. [Raspberry Pi, ScanVideo examples and wiring schematic, pico-playground](https://github.com/raspberrypi/pico-playground/tree/master/scanvideo)
5. [Pimoroni, Pico VGA Demo Base](https://shop.pimoroni.com/products/pimoroni-pico-vga-demo-base)
6. [Miroslav Nemecek, PicoVGA](http://www.breatharian.eu/hw/picovga/index_en.html)
7. [Miroslav Nemecek, DispHSTX (RP2350 / HSTX)](http://www.breatharian.eu/hw/disphstx/index_en.html)
8. [scrapcomputing, MCEBlaster (MDA/CGA/EGA TTL to VGA)](https://github.com/scrapcomputing/MCEBlaster)
9. [fruit-bat, pico-zxspectrum](https://github.com/fruit-bat/pico-zxspectrum)
10. [Raspberry Pi, pico_scanvideo README, pico-extras](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/README.adoc)
11. [Raspberry Pi, video_24mhz_composable_default PIO program, scanvideo.pio](https://github.com/raspberrypi/pico-extras/blob/master/src/common/pico_scanvideo/scanvideo.pio)
12. [earlephilhower, Arduino-Pico core](https://github.com/earlephilhower/arduino-pico)
13. [diyelectromusic, PicoVGABreakout (schematic and PCB)](https://github.com/diyelectromusic/sdemp_pcbs/tree/main/PicoVGABreakout)
14. [Ken Shirriff, note on blanking, April 2018](https://www.righto.com/2018/04/#fn:blanking)
