Pico VGA BLASTER

by Arnov Sharma in Circuits > Raspberry Pi

243 Views, 2 Favorites, 0 Comments

Pico VGA BLASTER

I Made a Retro VGA Game Console with Raspberry Pi Pico
24.gif
28.gif
31.gif
25.gif
IMG_8879.JPG

Greetings everyone, and welcome back.

This is PICO VGA BLASTER, a DIY Retro Console that runs arcade-style games on a VGA Monitor.

This project was based on my previously created PICO VGA Board, in which a Raspberry Pi Pico is connected to a DSUB15 connector for driving a VGA monitor and using it as a regular display. By taking that project and adding a button board along with a few edits, I was able to create this retro-styled console.

I prepared a custom game (PICO VGA BLASTER) specially made for this console. The game is loosely based on the original Space Invaders, but with a little twist: the aliens are VGA port-shaped entities that have invaded Earth, and we have to defend it.

My console contains six buttons: four directional buttons for controlling the spacecraft and two buttons for firing missiles and bullet projectiles.

A game without lore feels boring, so I also created a complete backstory and intro sequence for the game, giving the whole experience a retro arcade campaign feel.

For power, we need a 12V input provided by the DC barrel jack on the VGA board, and for the monitor, we are using a regular 27-inch LED Monitor.

For the housing, I even designed a custom enclosure, then 3D printed the parts and assembled everything together. This article covers the entire build process of this project, so let’s get started with the build.

Supplies

These are the components used in this project

  1. VGA PICO BOARD PCB (Provided by NEXTPCB)
  2. BUTTON BOARD (Provided by NEXTPCB)
  3. 12x12 tactile push buttons
  4. WS2812B LEDs
  5. 100nF Capacitors
  6. 3D Printed parts
  7. 12V Adaptor
  8. D-SUB 15 VGA Connector
  9. DC Barrel jack
  10. 330 Ohms Resistor 1206 Package
  11. 10k Resistor 0805 Package
  12. 1K Resistor 1206 Package
  13. LED Green 0603
  14. Female header Pins CON20 x 2
  15. PICO 1 or PICO W (any with RP2040)

PICO VGA BOARD 1.0

IMG_E6775.JPG
03.gif

The star of our project is the previously created PICO VGA BOARD 1.0, in which I paired a D-SUB15 connector with a Raspberry Pi Pico for driving a VGA monitor and using it just like any OLED or LCD screen. With this board, we can integrate a full-size VGA monitor into our projects.

For more information on the setup and working of this VGA Board, check out its article using the link below.

https://www.instructables.com/Pico-VGA-Board-10/

PCB DESIGN - PICO VGA BOARD 1.0

Screenshot 2026-04-06 233603.jpg
VGA SCH_page-0001.jpg
Screenshot 2026-04-06 233408.jpg

Let’s have a look at the PICO VGA BOARD 1.0 PCB Design. I connected a D-Sub 15-pin VGA connector directly to the Raspberry Pi Pico to generate VGA video output.

VGA works using three analog signals: Red, Green, and Blue. Each signal line carries a voltage ranging from 0V to 0.7V, where 0V means no intensity and 0.7V means full intensity. By combining these three signals, the monitor can reproduce different colors for every pixel. For example, setting only the red line to 0.7V produces pure red, while setting all three lines to 0.7V produces white.

Apart from RGB signals, VGA also requires two digital synchronization signals: HSYNC (Horizontal Sync) and VSYNC (Vertical Sync). HSYNC tells the monitor when a new horizontal line starts, while VSYNC indicates the start of a new frame. The monitor continuously draws pixels line by line, refreshing the entire screen around 60 times per second.

I connected Pico GPIO18, GPIO19, and GPIO20 to Pin 1, Pin 2, and Pin 3 of the VGA connector for the Red, Green, and Blue signals. Between these connections, I added resistor networks for proper voltage control. Each RGB line uses three 330Ω resistors connected in parallel, allowing the resistance value to be adjusted easily by adding or removing resistors while keeping all RGB channels balanced.

For synchronization, Pin 13 of the VGA connector, which is HSYNC, is connected to GPIO16 of the Pico, while Pin 14, which is VSYNC, is connected to GPIO17. Pins 5, 6, 7, 8, and 10 are all connected to ground.

I also added a CON15 breakout connector linked to all 15 VGA pins, making it easier to access individual VGA signals for testing or future expansion. Alongside that, I included additional headers connected to unused GPIO pins of the Pico so they can be used later for other peripherals or future projects.

For power regulation, I added an LM317 adjustable voltage regulator to the board. This regulator is capable of supplying more than 1.5A of current and supports an adjustable output voltage range from 1.25V to 37V.

We have set up the LM317 in such a way that when we input 12V, we get a stable 5V for powering the Pico.

https://www.ti.com/lit/ds/symlink/lm317.pdf

PCB DESIGN - BUTTON BOARD

Screenshot 2026-04-28 120823.jpg
SCH BUTTON BOARD_page-0001.jpg
Screenshot 2026-04-28 120321.jpg

The second PCB I used in this project was the Button Board, which I reused from my Motorola DynaTAC project. Here, I added six buttons onto a custom PCB. All buttons are connected to GND, while their other pins are routed to a CON7 connector, which is used to interface the buttons with the microcontroller, in this case, the PICO VGA Board.

We also added six WS2812B RGB LEDs for additional lighting effects and visual feedback.

NextPCB PCB SERVICE

06.gif
07.gif

Gerber data for both PCBs was sent to HQ NextPCB, and an order was placed for a Red solder mask and one board with a green solder mask.

After placing the order, the PCBs were received within a week, and the PCB quality was pretty great.

In addition, I have to bring in HQDFM to you, which helped me a lot through many projects. Huaqiu’s in-house engineers developed the free Design for Manufacturing software, HQDFM, revolutionizing how PCB designers visualize and verify their designs.

Take advantage of NextPCB's Accelerator campaign and get 2 free assembled RP2040-based PCBs for your innovative projects.

https://www.nextpcb.com/blog/rp2040-free-pcba-prototypes-nextpcb-accelerator

This offer covers all costs, including logistics, making it easier and more affordable to bring your ideas to life. SMT services can be expensive, but NextPCB is here to help you overcome that hurdle. Simply share your relevant project, and they'll take care of the rest. Don't miss out on this amazing opportunity to advance your tech creations!

PCB ASSEMBLY PROCESS - VGA DRIVER

PCB Surface Mount/Through Hole Assembly Process—PICO VGA PROJECT
IMG_E6719.JPG
IMG_E6725.JPG
IMG_E6727.JPG
IMG_E6730.JPG
IMG_E6736.JPG
  1. We begin the PCB assembly process by first adding solder paste to each component’s pads one by one using a solder paste dispensing needle. Here, we are using 63/37 SnPb solder paste.
  2. We then pick and place each SMD component in its correct location.
  3. The PCB is then placed on a reflow hotplate, which heats the PCB from below up to the solder paste melting temperature. As soon as the PCB reaches that temperature, the solder paste melts, and all components are secured in their positions.
  4. For the through-hole assembly process, we added the D-Sub 15 connector in its position, followed by the barrel DC jack and two CON20 female header pins in place of the Pico. By turning the board over and using a soldering iron, we solder all the through-hole component leads, securing everything in position.
  5. At last, we place the Pico W in its position over the female header pins. This completes the assembly process of the driver board.

VGA DRIVER DEMO

04.gif

To run the DEMO CODE on our VGA Board, we plug the VGA cable from the monitor into the VGA port of our circuit, and then connect the power adapter via the DC barrel jack connector.

Here's the Code we used for DEMO, and it's a simple one.

#include "vga_graphics.h"
/* ── Screen ───────────────── */
#define SW 640
#define SH 480
/* ── Grid ───────────────── */
#define CELL 8
#define GRID_W (SW / CELL)
#define GRID_H (SH / CELL)
/* ── Buffers ───────────── */
bool grid[GRID_W][GRID_H];
bool nextGrid[GRID_W][GRID_H];
/* ── Draw cell ─────────── */
void drawCell(int x, int y, bool alive) {
fillRect(
x * CELL,
y * CELL,
CELL - 1,
CELL - 1,
alive ? YELLOW : BLACK
);
}
/* ── Random init ───────── */
void randomizeGrid() {
for (int x = 0; x < GRID_W; x++) {
for (int y = 0; y < GRID_H; y++) {
grid[x][y] = random(0, 2);
drawCell(x, y, grid[x][y]);
}
}
}
/* ── Count neighbors ───── */
int countNeighbors(int x, int y) {
int count = 0;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
if (dx == 0 && dy == 0) continue;
int nx = x + dx;
int ny = y + dy;
// wrap around edges
if (nx < 0) nx = GRID_W - 1;
if (nx >= GRID_W) nx = 0;
if (ny < 0) ny = GRID_H - 1;
if (ny >= GRID_H) ny = 0;
if (grid[nx][ny]) count++;
}
}
return count;
}
/* ── Update simulation ─── */
void updateGrid() {
for (int x = 0; x < GRID_W; x++) {
for (int y = 0; y < GRID_H; y++) {
int neighbors = countNeighbors(x, y);
if (grid[x][y]) {
// alive
nextGrid[x][y] = (neighbors == 2 || neighbors == 3);
} else {
// dead
nextGrid[x][y] = (neighbors == 3);
}
}
}
// apply + redraw only changes
for (int x = 0; x < GRID_W; x++) {
for (int y = 0; y < GRID_H; y++) {
if (grid[x][y] != nextGrid[x][y]) {
drawCell(x, y, nextGrid[x][y]);
}
grid[x][y] = nextGrid[x][y];
}
}
}
/* ── Setup ─────────────── */
void setup() {
initVGA();
clearScreen();
randomSeed(analogRead(26)); // Pico randomness
randomizeGrid();
}
/* ── Loop ─────────────── */
void loop() {
updateGrid();
delay(80); // speed control
}

Code begins by defining the screen resolution, which is the following.

#define SW 640
#define SH 480

We next define the grid size for cells. Each cell is 8x8 Pixels, the grid becomes 640/8 = 80 columns and 480/8 = 60 rows.

#define CELL 8
#define GRID_W (SW / CELL)
#define GRID_H (SH / CELL)

Below is the buffer or core of our simulation. This prevents overwriting data while calculating.

bool grid[GRID_W][GRID_H];
bool nextGrid[GRID_W][GRID_H];

Next up is drawing a cell logic. This first converts the grid position into screen pixels.

void drawCell(int x, int y, bool alive)

Using this, a square is drawn.

x * CELL, y * CELL

This is a random function that fills the grid randomly when the code starts.

void randomizeGrid()

This is the core logic of the game of life, which is counting neighbours. It checks all 8 surrounding cells.

int countNeighbors(int x, int y)

Game Rules are set with the following.

Alive Cell survives if there are 2 or 3 neighbours. Dead cells become alive if there are exactly 3 neighbours.

if (grid[x][y]) {
nextGrid[x][y] = (neighbors == 2 || neighbors == 3);
} else {
nextGrid[x][y] = (neighbors == 3);
}

Using the section below, we only redraw the cells that are changed instead of a full-screen redraw.

if (grid[x][y] != nextGrid[x][y]) {
drawCell(x, y, nextGrid[x][y]);
}

This is the copy state that moves next from the current frame.

grid[x][y] = nextGrid[x][y];

In the setup, VGA is initialized, randomness is added, and the simulation starts.

initVGA();
clearScreen();
randomSeed(analogRead(26));
randomizeGrid();

In the loop, the simulation is updated continuously, and its speed is controlled. Lower delay means fast evolution, and higher delay results in a slower, easier-to-see evolution.

updateGrid();
delay(80);

PCB ASSEMBLY PROCESS- BUTTON BOARD

  1. Button board assembly begins by applying solder paste to the SMD LED and capacitor pads.
  2. All the SMD components are then placed in their correct positions, six 100 nF decoupling capacitors and six WS2812B RGB LEDs, using ESD-safe tweezers.
  3. The entire board is then placed on a reflow hotplate, which heats the PCB from below up to the solder paste’s melting temperature. Once the PCB reaches this temperature, the solder paste melts, and all the SMD components are securely soldered in place.
  4. We place 12×12 mm push buttons in their designated location.
  5. After placing the through-hole switches, we flipped the boards over and soldered each lead using a soldering iron.

This completed the Button Board assembly process.

MAIN ELECTRONICS SETUP

02.gif
04.gif
VGA_BLASTER_SCH_page-0001.jpg

For the main wiring of our setup, we first connected the GND of the VGA Board with the GND of the Button Board so both PCBs could share a common ground connection.

The button connections were done as follows:

  1. Fire Button to GPIO0
  2. UP Button to GPIO1
  3. Missile Button to GPIO2
  4. LEFT Button to GPIO3
  5. DOWN Button to GPIO4
  6. RIGHT Button to GPIO5

For the RGB lighting setup, the DIN pin of the WS2812B LED was connected to GPIO6, while its VCC pin was connected to the 5V output of the Raspberry Pi Pico.

For all the wiring connections, we used single-core silver copper wire along with a soldering iron to securely solder every connection in place.

GAME CODE

The main code for our project is attached, which contains the game logic and functionality.

The code is long, but the core functionality is super simple. Let me explain.

#include "vga_graphics.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"

We use the above libraries in our code. The VGA graphics library is used for generating VGA video output, while the hardware libraries are used for PWM audio, GPIO button input, clock handling, and synchronization.

#define SW 640
#define SH 480

Here, we define the VGA screen resolution. Our setup runs at 640×480 resolution.

#define BTN_FIRE 0
#define BTN_MISSILE 2
#define BTN_LEFT 3
#define BTN_RIGHT 5
#define BTN_UP 1
#define BTN_DOWN 4

Four buttons are used for directional movement, while the remaining two are used for firing bullets and missiles.

#define LED_PIN 6
#define NUM_LEDS 8

We define the RGB LED strip used for lighting effects during gameplay. The LEDs glow whenever enemies are destroyed or special events occur.

enum State { INTRO, LORE, PLAYING, GAMEOVER };

The game is divided into multiple states, including the intro screen, lore screen, gameplay, and game over screen.

char* loreLines[] = {
"YEAR 2187.",
"",
"THEY CAME FROM THE SIGNAL.",
"",
"BEINGS BORN FROM CORRUPTED DATA,",
"SHAPED LIKE THE VERY SCREENS",
"THEY INVADED THROUGH.",
"",
"THE VGA ARMADA WIPED OUT",
"EARTH'S DEFENCES IN 72 HOURS.",
"",
"ONE PILOT. ONE SHIP.",
"ONE LAST CHANCE.",
"",
"YOU ARE HUMANITY'S FINAL PIXEL."
};

I also added a splash screen with a complete game lore sequence. Before gameplay starts, the game displays a cinematic intro story using animated typewriter-style text.

void drawIntroScreen()

This function renders the main splash screen of the game with the “PICO VGA BLASTER” title and animated background stars.

void tickLoreTypewriter()

This function creates the typewriter animation effect for the lore screen, where text appears character by character along with sound effects.

void buttonsInit()

This function initializes all button GPIO pins and enables internal pull-up resistors so the Pico can detect button presses correctly.

void updatePlayer()

This is the main player control function. It reads directional button inputs and updates the spaceship movement and attacks.

if (btnPressed(BTN_LEFT)) pX -= pSpeed;
if (btnPressed(BTN_RIGHT)) pX += pSpeed;

This part handles the horizontal movement of the spaceship.

if (fireNow && !lastFireBtn && !bActive)

This creates a bullet projectile whenever the fire button is pressed.

void drawHUD()

This renders the game HUD, including score, lives, missile ammo, and boss health bar.

void drawGameOverScreen()

This function displays the final game-over screen with the player’s score and restart animation.

3D DESIGN

untitled.748.png
untitled.745.png
untitled.746.png
untitled.747.png
untitled.749.png

For the design of this project, my goal was to create an enclosure that could house both the PICO VGA Board and the Button Board together. The VGA port and DC jack for power needed to remain visible from one end, so the VGA cable and power input could be accessed easily. I also wanted the device to feature large buttons that would be comfortable and easy to use.

The enclosure design itself was kept very minimal, but to improve the aesthetics, the directional buttons were designed as triangles rotated according to the direction of the D-pad. The Fire and Missile buttons were modeled in round and square shapes, respectively.

To further enhance the look, I added four greeble parts, O, Plus, and X-shaped elements, along with a separate part featuring the legendary Konami Code: “Up Up Down Down Left Right Left Right B A Start.”

My idea was to print the main enclosure in orange color and use black PLA for the rest of the parts, creating a dual-tone aesthetic for the final design.

ENCLOSURE DESIGN

Screenshot 2026-05-24 153813.jpg

For the enclosure, we modeled two parts: the housing and the lid. All the components, including the PICO VGA Board, Button Board, switches, and greeble parts, are housed inside the main housing.

The switch triangles were positioned inside the housing and are held in place once the Button PCB is mounted over them, keeping everything securely locked in position. When these switch triangles are pressed, they activate the switches on the Button Board, and the Pico detects the button press and performs the corresponding function.

The VGA Board is also mounted inside the housing on dedicated screw bosses, allowing it to be fixed in place using M2 screws. Similarly, screw bosses were added for securing the Button Board using M2 screws as well.

From the back side, a separate lid part was modeled to close the housing. We added four mounting holes, two on each side, which use four M2 screws to securely fasten the housing and lid together.

GREEBLES

Screenshot 2026-05-24 153436.jpg
Screenshot 2026-05-24 153525.jpg

Some greeble parts were also modeled to improve the aesthetics of the design. I designed regular-shaped O, Plus, and X symbols, which were added to the front face of the housing. I even created dedicated slots where all three parts fit perfectly into position.

Next, as an easter egg for gamers, I added the legendary Konami Code. I modeled a separate part featuring the physical shapes of Up, Down, Left, Right, A, B, and Start and positioned it slightly above the square button.

3D PRINTED PARTS

05.gif
06.gif
07-Trim.gif
08.gif
09.gif

For the 3D prints, the housing was the only part printed in Orange Hyper PLA using a 0.4mm nozzle, 0.16mm layer height, and 25% infill. I printed the part face down, which allowed me to avoid using any support material.

Using the same print settings but with Black Hyper PLA, I first printed the lid part separately and then printed all the greeble parts together.

The switch parts were printed separately, as they required support material, for which I used tree supports.

ENCLOSURE ASSEMBLY

10.gif
11.gif
12.gif
13.gif
14.gif
15.gif
16.gif
17.gif
  1. The enclosure assembly begins by placing all the switches into position from inside the housing.
  2. Over the switches, we position the Button Board by aligning its mounting holes with the screw bosses of the housing.
  3. Similarly, we also place the VGA Board onto its dedicated screw bosses.
  4. M2 screws were used throughout the assembly, two for securing the Button Board and three for securing the VGA Board in place.
  5. Finally, we place the lid from the bottom side and use four M2 screws to permanently secure the lid to the housing.

GREEBLES ASSEMBLY

18.gif
19.gif
20.gif
21.gif
22A.gif
  1. We begin the greeble assembly by applying super glue to the mounting spots and then placing the O-shaped part into position.
  2. Similarly, we followed the same process for the Plus and X greeble parts, first applying super glue to their mounting points and then positioning each part.
  3. Finally, we added the Konami Code part by applying super glue to the back side of the piece and positioning it slightly above the square switch.

RESULT

I Made a Retro VGA Game Console with Raspberry Pi Pico
24.gif
25.gif
27.gif
28.gif
29.gif
30.gif
31.gif
32.gif
33.gif

Here’s the end result of this build: the PICO VGA BLASTER, a retro-styled console that runs my custom-made game.

To use this console, we connect it to a VGA monitor. In this case, we are using a regular LED monitor that supports VGA connectivity, and power the setup using a 12V power adapter connected through the DC jack.

The console runs my own version of Space Invaders, where the enemies are designed to look like VGA ports. Using the D-pad, we can control our spacecraft, and there are two attack options: a normal fire mode and a missile launcher. After defeating one fleet of enemies, a boss fight begins, followed by another fleet where the VGA enemies can now fire back at the player. After that comes a second boss fight, which is twice as difficult. If all three players' lives are lost, the game-over sequence is triggered.

I created this project for an event where I will be showcasing the setup on a large display so people can try the game themselves.

For Version 2 of this project, I would like to add controller support, make the console smaller, and possibly even add multiplayer support, and not to forget, improved sound functionality as well.

Special thanks for making it this far, and I’ll be back with another new project very soon.