Greetings everyone, and welcome back!
Today I’ve got something super interesting to show you — the Pico VGA Board.
The heart of this project is a Raspberry Pi PICO W paired with a D-SUB15 connector, and with this setup, we can use a regular TFT monitor as a massive display for pretty much anything we want.
Here's a demo of Conway’s Game of Life running on a full-sized monitor.
The whole project is loosely based around an existing VGA library for PICO, which was made to work with CRT monitors. I made some changes to it so it can be used with modern LCD VGA Monitors.
This article covers the complete build process of the PICO VGA Board and walks you through the whole code process.
MATERIALS REQUIREDThese are the materials used in this project
- Custom PCB Board
- D-SUB 15 VGA Connector
- DC Barrel jack
- 330 Ohms Resistor 1206 Package
- 10k Resistor 0805 Package
- 1K Resistor 1206 Package
- LED Green 0603
- Female header Pins CON20 x 2
- PICO 1 or PICO W (any with RP2040)
Before starting this project, we first need to understand how VGA ports actually work. VGA, or Video Graphics Array, is an analog video interface that sends image data from a device, such as our Raspberry Pi Pico, to a monitor. Unlike HDMI or DisplayPort, VGA does not send digital packets; instead, it continuously streams voltages that represent colors and timing.
VGA uses three analog signals: Red, Green, and Blue. Each of these signal lines carries a voltage that typically ranges from 0 to 0.7V. At 0V, there is no intensity, and at 0.7V, the monitor displays full intensity.
By combining these three signal lines, the monitor recreates every pixel color. For example, if red is set to 0.7V while green and blue are at 0V, the result is pure red. If all three are set to 0.7V, the result is white.
In addition to RGB signals, VGA uses two digital signals: HSYNC (Horizontal Sync), which tells the monitor when a new line starts, and VSYNC (Vertical Sync), which indicates when a new frame begins.
The monitor draws the image by first rendering pixels from left to right in a single line. An HSYNC pulse then moves it to the next line, and this process repeats for all lines. A VSYNC pulse starts a new frame. This entire process happens approximately 60 times per second (60 Hz).
A VGA connector, also known as a D-Sub 15 (DB15) connector, consists of 15 pins. Pin 1 is for Red, Pin 2 for Green, Pin 3 for Blue, Pin 13 for HSYNC, and Pin 14 for VSYNC. The remaining pins are used for ground and other auxiliary functions.
PICO VGA LIBRARYThis project started when I came across a really interesting idea of using a VGA monitor with a Raspberry Pi Pico.
While exploring this, I found a Pico VGA library by Pancrea85. However, the original library was designed primarily for CRT monitors and didn’t work reliably with modern LCD VGA displays.
After making several modifications and adding a few example sketches, I created my own version of the library. This version is adapted for better compatibility with modern displays and can be easily installed and used from the GitHub link below.
https://github.com/razorArnov/PICO-VGA-BOARD
D-SUB15 VGA PORT & PICO BASIC CONNECTIONThis is the basic wiring diagram used to interface a VGA monitor with the Raspberry Pi Pico.
- Pin 1 (Red) of the VGA connector is connected to GPIO18, with four 1kΩ resistors in parallel placed between them.
- Pin 2 (Green) is connected to GPIO19, with the same four 1kΩ resistors in parallel.
- Pin 3 (Blue) is connected to GPIO20, again using four 1kΩ resistors in parallel.
The resistance value controls brightness. Higher total resistance results in a dimmer image, while lower resistance increases brightness. An ideal combined resistance is typically in the 200–400Ω range.
- Pins 5, 6, 7, 8, and 10 are all connected to GND.
- Pin 13 (HSYNC) is connected to GPIO16.
- Pin 14 (VSYNC) is connected to GPIO17.
Using the VGA–Pico wiring diagram, we created a simple makeshift breadboard setup. A VGA connector was interfaced using jumper wires, which were connected to a prototype board containing resistor arrays for the RGB and sync lines. These signals were then linked to the Raspberry Pi Pico mounted on a breadboard, forming a complete test setup for VGA output.
BREADBOARD SETUP DEMOAfter completing the wiring, we uploaded a custom demo sketch that recreates a Linux-style terminal inspired by Fallout’s RobCo terminals, featuring the same iconic green color theme.
Below is the demo code.
#include "vga_graphics.h"
// ---------------- CONFIG ----------------
#define BORDER_THICKNESS 4
#define BORDER_MARGIN 14
// Fallout (big text)
#define BIG_CHAR_W 12
#define BIG_CHAR_H 16
// Linux (small text)
#define SMALL_CHAR_W 6
#define SMALL_CHAR_H 8
// Cursor
bool cursor_visible = true;
unsigned long last_blink = 0;
// ---------------- CURSORS ----------------
int big_col = 0;
int big_row = 0;
int small_col = 0;
int small_row = 18; // start lower on screen
// ---------------- BORDER ----------------
void drawBorder() {
for (int t = 0; t < BORDER_THICKNESS; t++) {
drawHLine(t, t, screenWidth - 2*t, GREEN);
drawHLine(t, screenHeight - 1 - t, screenWidth - 2*t, GREEN);
drawVLine(t, t, screenHeight - 2*t, GREEN);
drawVLine(screenWidth - 1 - t, t, screenHeight - 2*t, GREEN);
}
}
// ---------------- TEXT HELPERS ----------------
void big_print(const char* s) {
while (*s) {
if (*s == '\n') {
big_col = 0;
big_row++;
} else {
drawChar(
BORDER_MARGIN + big_col * BIG_CHAR_W,
BORDER_MARGIN + big_row * BIG_CHAR_H,
*s,
GREEN,
BLACK,
2
);
big_col++;
}
s++;
}
}
void small_print(const char* s) {
while (*s) {
if (*s == '\n') {
small_col = 0;
small_row++;
} else {
drawChar(
BORDER_MARGIN + small_col * SMALL_CHAR_W,
BORDER_MARGIN + small_row * SMALL_CHAR_H,
*s,
GREEN,
BLACK,
1
);
small_col++;
}
s++;
}
}
// ---------------- BLINKING CURSOR ----------------
void draw_cursor() {
int x = BORDER_MARGIN + big_col * BIG_CHAR_W;
int y = BORDER_MARGIN + big_row * BIG_CHAR_H;
if (cursor_visible) {
fillRect(x, y + BIG_CHAR_H - 2, BIG_CHAR_W, 2, GREEN);
} else {
fillRect(x, y + BIG_CHAR_H - 2, BIG_CHAR_W, 2, BLACK);
}
}
// ---------------- SETUP ----------------
void setup() {
initVGA();
clearScreen();
drawBorder();
// Fallout header (BIG)
big_print("ROBCO INDUSTRIES UNIFIED OS\n");
big_print("COPYRIGHT 2075-2077 ROBCO\n");
big_print("- VAULT TERMINAL -\n\n");
big_print("> INITIALIZING SYSTEM...\n");
big_print("> MEMORY BANKS: OK\n");
big_print("> VGA INTERFACE: OK\n");
big_print("> RP2040 STATUS: NOMINAL\n\n");
big_print("> ");
// Linux / RPi info (SMALL)
small_print("pico@rp2040:~$ neofetch\n\n");
small_print("OS: Pico Linux (demo)\n");
small_print("Host: Raspberry Pi Pico W\n");
small_print("Kernel: 0.1-retro\n");
small_print("Uptime: just now\n");
small_print("Resolution: 640x480 VGA\n");
small_print("Shell: bash (fake)\n");
}
// ---------------- LOOP ----------------
void loop() {
unsigned long now = millis();
if (now - last_blink > 500) {
last_blink = now;
cursor_visible = !cursor_visible;
draw_cursor();
}
}Here's a small breakout for the code.
First we begin by defining Border thickness and spacing from edges.
#define BORDER_THICKNESS 4
#define BORDER_MARGIN 14Next, we added two font scales, BIG for the fallout header and SMALL for the terminal info.
#define BIG_CHAR_W 12
#define BIG_CHAR_H 16
#define SMALL_CHAR_W 6
#define SMALL_CHAR_H 8Here are the Cursor Variables, which are used to create a blinking cursor effect.
bool cursor_visible = true;
unsigned long last_blink = 0;This is for Text Position Tracking. small_row = 18 pushed the Linux test lower on the screen and prevents overlap with the big header.
int big_col = 0;
int big_row = 0;
int small_col = 0;
int small_row = 18;We use the void drawBorder() function for drawing a rectangular green border around texts. drawHLine() is for horizontal lines, drawVLine() is vertical lines.
Also, this loops to make the border thicker.
for (int t = 0; t < BORDER_THICKNESS; t++)Using the below function, we are able to print large text. (scale 2)
void big_print(const char* s)Similarly, using the below function, small texts are printed, and smaller fonts are used (scale 1).
void small_print(const char* s)For Blinking Cursor, this draws a block-style underline cursor.
void draw_cursor()If Visible, this draws green; if hidden, it erases.
fillRect(x, y + BIG_CHAR_H - 2, BIG_CHAR_W, 2, GREEN);In Setup, VGA is initialized, Border is drawn, and every print job is done, from Big texts to small texts, all are printed in Setup.
initVGA();
clearScreen();
drawBorder();Big Texts
big_print("ROBCO INDUSTRIES...");Small Texts
small_print("pico@rp2040:~$ neofetch\n\n");In the Loop, cursor blinking logic is being run continuously.
if (now - last_blink > 500)After making sure that the breadboard setup is functioning nicely, we next move on to stage two of this project, which is to prepare a proper board for the setup.
PCB DESIGNWe begin the PCB design process by preparing the schematic first. Here, we recreated the connection of the D-Sub 15 connector with the Pico wiring. In this, we paired Pico GPIO18, GPIO19, and GPIO20 with Pin 1, Pin 2, and Pin 3 of the VGA connector, with three resistors placed in between.
We will be adding a single 330Ω resistor on each R, G, and B line. Each RGB line has three resistors connected in parallel, so we can easily adjust the resistance value by adding or removing any resistor. We just need to make sure all three resistor values in R, G, and B are the same.
Pin 13, which is HSYNC, is connected to GPIO16, and Pin 14, which is VSYNC, is connected to GPIO17. The Pins 5, 6, 7, 8, and 10 are all connected to GND.
We have also added a CON15 connector, which is linked to all VGA pins from Pin 1 to Pin 15, in case we need to break out each pin of the VGA D-Sub connector.
For the Pico, we have added a few connectors connected to unused GPIO pins so we can use these pins for future projects.
For power, we added an LM317, which is an adjustable three-pin positive voltage regulator capable of supplying more than 1.5A over an output voltage range of 1.25V to 37V.
https://www.ti.com/lit/ds/symlink/lm317.pdf
We have set up the LM317 in such a way that when we input 12V, we get a stable 5V for powering the Pico.
After completing the PCB schematic and preparing the PCB, we exported the Gerber data and sent it for manufacturing.
NextPCB PCB SERVICEAfter completing the PCB design, Gerber data for the PCB was sent to HQ NextPCB, and an order was placed for RED Solder mask boards with a white silkscreen.
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!
HQDFM: Free Online Gerber Viewer and DFM Analysis ToolAlso, NextPCB has its own Gerber Viewer and DFM analysis software.
Your designs are improved by their HQDFM software (DFM) services. Since I find it annoying to have to wait around for DFM reports from manufacturers, HQDFM is the most efficient method for performing a pre-event self-check.
This is what I see in the online Gerber Viewer. It's decent for a quick look, but not entirely clear. For full functionality—like detailed DFM analysis for PCBA—you’ll need to download the desktop software. The web version only offers a basic DFM report.
With comprehensive Design for Manufacture (DFM) analysis features, HQDFM is a free, sophisticated online PCB Gerber file viewer.
With over 15 years of industry experience, it offers valuable insights into advanced manufacturing processes. If you’re looking for reliable PCB services at a budget-friendly price, HQ NextPCB is definitely worth checking out.
PCB ASSEMBLY PROCESS- 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.
- We then pick and place each SMD component in its correct location.
- 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.
- 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.
- At last, we place the Pico W in its position over the female header pins. This completes the assembly process of the driver board.
Before getting started with the code, we connect our Pico VGA Board to a 24-inch monitor using a VGA cable. 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.
DEMO 1- Hello WorldWe begin the demo of our setup by flashing PICO W with a Hello World code first.
This was a simple print statement like skeytch that prints hello world in three different colours, R, G, and B.
Here's a little code breakdown.
#include "vga_graphics.h"
#include <string.h>
/* ── Screen ───────────────── */
#define SW 640
#define SH 480
/* ── Text scale ──────────── */
#define SCALE 4
/* ── Centered print ───────── */
void printCentered(const char* text, int y, char color) {
int len = strlen(text);
int textWidth = len * 6 * SCALE;
int x = (SW - textWidth) / 2;
for (int i = 0; i < len; i++) {
drawChar(x + i * 6 * SCALE, y, text[i], color, BLACK, SCALE);
}
}
/* ── CRT Scanlines ───────── */
void drawScanlines() {
for (int y = 0; y < SH; y += 2) {
drawHLine(0, y, SW, BLACK); // dark line every other row
}
}
/* ── Setup ─────────────── */
void setup() {
initVGA();
clearScreen();
int lineHeight = 8 * SCALE;
int totalHeight = lineHeight * 3 + 20; // spacing included
int startY = (SH - totalHeight) / 2;
// Line 1 (RED)
printCentered("HELLO WORLD 1", startY, RED);
// Line 2 (GREEN)
printCentered("HELLO WORLD 2", startY + lineHeight + 10, GREEN);
// Line 3 (BLUE)
printCentered("HELLO WORLD 3", startY + (lineHeight + 10) * 2, BLUE);
// CRT overlay
drawScanlines();
}
/* ── Loop ─────────────── */
void loop() {
}We begin by defining VGA resolution.
#define SW 640
#define SH 480We defined the size of text scaling that enlarges the font size. Default fonts are 6x8 pixels, with a scale of 4; each character becomes 24x32 pixels.
#define SCALE 4This is a center text function that does three major things.
void printCentered(const char* text, int y, char color)It first calculates the width of the text, then centers it horizontally, and then draws each character.
int textWidth = len * 6 * SCALE;
int x = (SW - textWidth) / 2;
drawChar(x + i * 6 * SCALE, y, text[i], color, BLACK, SCALE);Also, I added a CRT Scanline effect using the following function.
void drawScanlines()How it works is super simple, it just draws a black horizontal line every 2 pixels, which creates a retro CRT Look.
void drawScanlines()
for (int y = 0; y < SH; y += 2)
drawHLine(0, y, SW, BLACK);In Setup, we print 3 coloured lines.
printCentered("HELLO WORLD 1", startY, RED);
printCentered("HELLO WORLD 2", startY + lineHeight + 10, GREEN);
printCentered("HELLO WORLD 3", startY + (lineHeight + 10) * 2, BLUE);We apply the CRT effect using below function.
drawScanlines();The loop is kept empty because this is a static display.
DEMO 2- Snake GameWe then prepared a snake game sketch for this setup. The snake game code was taken from one of my previously created snake game console projects, in which we are able to control the movement of the snake.
For this VGA demo, we made the snake move randomly, but button controls can be added, and perhaps we can prepare a Snake Game Console XL project with this setup, but that’s a bit off topic.
Here’s the code breakdown.
#include "vga_graphics.h"
/* ── Screen ───────────────── */
#define SW 640
#define SH 480
/* ── Grid ───────────────── */
#define CELL 12
#define GRID_W (SW / CELL)
#define GRID_H (SH / CELL)
/* ── Snake ─────────────── */
struct Segment {
int x;
int y;
};
Segment snake[200];
int snakeLength = 5;
int dx = 1, dy = 0;
int foodX, foodY;
int prevTailX, prevTailY;
/* ── Random food ───────── */
void placeFood() {
foodX = random(2, GRID_W - 2);
foodY = random(2, GRID_H - 2);
}
/* ── Reset ─────────────── */
void resetGame() {
clearScreen();
snakeLength = 5;
dx = 1; dy = 0;
for (int i = 0; i < snakeLength; i++) {
snake[i].x = GRID_W / 2 - i;
snake[i].y = GRID_H / 2;
}
placeFood();
}
/* ── Random movement ───── */
void randomMove() {
if (random(0, 10) < 3) { // 30% chance
int dir = random(0, 4);
if (dir == 0 && dy == 0) { dx = 0; dy = -1; } // up
if (dir == 1 && dy == 0) { dx = 0; dy = 1; } // down
if (dir == 2 && dx == 0) { dx = -1; dy = 0; } // left
if (dir == 3 && dx == 0) { dx = 1; dy = 0; } // right
}
}
/* ── Collision ─────────── */
bool selfCollision() {
for (int i = 1; i < snakeLength; i++) {
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
return true;
}
}
return false;
}
/* ── Draw one cell ─────── */
void drawCell(int gx, int gy, char color) {
fillRect(gx * CELL, gy * CELL, CELL - 1, CELL - 1, color);
}
/* ── Setup ─────────────── */
void setup() {
initVGA();
clearScreen();
randomSeed(analogRead(26)); // Pico randomness
resetGame();
}
/* ── Loop ─────────────── */
void loop() {
// random AI movement
randomMove();
// store tail
prevTailX = snake[snakeLength - 1].x;
prevTailY = snake[snakeLength - 1].y;
// move body
for (int i = snakeLength - 1; i > 0; i--) {
snake[i] = snake[i - 1];
}
// move head
snake[0].x += dx;
snake[0].y += dy;
// wrap screen
if (snake[0].x >= GRID_W) snake[0].x = 0;
if (snake[0].x < 0) snake[0].x = GRID_W - 1;
if (snake[0].y >= GRID_H) snake[0].y = 0;
if (snake[0].y < 0) snake[0].y = GRID_H - 1;
// self collision
if (selfCollision()) {
delay(500);
resetGame();
return;
}
// food
if (snake[0].x == foodX && snake[0].y == foodY) {
snakeLength++;
placeFood();
}
// erase tail
drawCell(prevTailX, prevTailY, BLACK);
// draw snake
for (int i = 0; i < snakeLength; i++) {
drawCell(snake[i].x, snake[i].y, GREEN);
}
// draw food
drawCell(foodX, foodY, WHITE);
delay(120);
}We first define the screen and grid setup.
#define SW 640
#define SH 480We also define VGA Resolution, where each cell consists of 12x12 pixels, and each grid becomes 53 columns x 40 rows.
#define CELL 12
#define GRID_W (SW / CELL)
#define GRID_H (SH / CELL)Here is the structure of a snake.
struct Segment {
int x;
int y;
};Each snake segment stores its position.
Segment snake[200];
int snakeLength = 5;Snake can grow up to 200 segments and start with a length of 5.
This is the Movement variables.
int dx = 1, dy = 0;This places food randomly with safe grid bounds, also avoiding edges slightly.
void placeFood()This is the Reset Game function that clears the screen, resets the snake's length and direction, places the snake at the center, and spawns new food.
void resetGame()This is the Random Movement function, which has like 30% chance to change direction, and the setup prevents reversing direction.
void randomMove()
if (random(0, 10) < 3)Food is drawn by the following section.
drawCell(foodX, foodY, WHITE);We control the speed of snake using delay(120);
DEMO 3- Conway's Game of LifeNext is the Game of Life sketch, and here's a little code breakdown.
#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 480We 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 * CELLThis 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);CONCUSIONThis setup works quite well, and with this, I’m even preparing a game project and a couple of sensor interface display-like projects. One of the reasons for making this Pico VGA Board was to use a full-size monitor with the Pico as a display for showing XYZ stuff, and with the help of our hardware, this is now super simple.
We just need to download and install my custom library, prepare the VGA Pico Board setup (whose details are all attached in this article), make your own VGA Pico Board, and just display XYZ stuff on a monitor. Super simple.
The board can be powered via the DC Barrel jack with a 12V Adaptor.
For now, this project has been completed, and it’s been a success. Make sure to check out the video I prepared for this project, and if you are interested in these display-related projects, check out my older work.
Thanks for reaching this far in the article, and I will be back with a new project real soon.
















Comments