You want to run your own custom Linux on a Raspberry Pi. Not Raspbian — a fully custom OS built entirely from source, tailored to your needs.
This guide walks you through building a custom Linux image for Raspberry Pi 3/4 using Yocto Scarthgap 5.0 LTS — from downloading the source layers all the way to booting on real hardware, including Wi-Fi, SSH, and GPIO configuration.
What You'll Need
- Build machine: Ubuntu 22.04/24.04, 16+ GB RAM, 200+ GB disk
- Raspberry Pi 3 or 4
- microSD card: 16 GB+ (Class 10 recommended)
- SD card reader
- HDMI monitor + keyboard (for initial boot verification)
Downloading Layers and Initializing the Build Environment
# Create a working directory
mkdir -p ~/yocto && cd ~/yocto
# Download Poky (scarthgap = LTS branch)
git clone -b scarthgap git://git.yoctoproject.org/poky
# Download meta-raspberrypi
git clone -b scarthgap git://git.yoctoproject.org/meta-raspberrypi
# Download meta-openembedded (required by meta-raspberrypi)
git clone -b scarthgap git://git.openembedded.org/meta-openembedded
Use the same branch (scarthgap) for all three repositories. Mixing branches is a common source of mysterious compatibility errors.
# Initialize the build environment
cd ~/yocto/poky
source oe-init-build-env build-rpi
Adding Layers
# Add meta-oe (dependency required by meta-raspberrypi)
bitbake-layers add-layer ../../meta-openembedded/meta-oe
# Add meta-python (optional — needed if using Python packages)
bitbake-layers add-layer ../../meta-openembedded/meta-python
# Add meta-networking (optional — needed for networking tools)
bitbake-layers add-layer ../../meta-openembedded/meta-networking
# Add meta-raspberrypi
bitbake-layers add-layer ../../meta-raspberrypi
# Verify all layers are active
bitbake-layers show-layers
Configuring local.conf
Edit conf/local.conf with Raspberry Pi-specific settings:
# Target board
MACHINE = "raspberrypi4-64"
# Parallel build settings (tune to your CPU core count)
BB_NUMBER_THREADS = "8"
PARALLEL_MAKE = "-j 8"
# Generate SD card image in wic format
IMAGE_FSTYPES = "wic.bz2 wic.bmap"
# GPU memory allocation (MB)
GPU_MEM = "64"
# Enable UART for serial console debugging
ENABLE_UART = "1"
# Enable SSH server (Dropbear)
IMAGE_FEATURES += "ssh-server-dropbear"
# Allow root login without a password (development only — disable for production)
EXTRA_IMAGE_FEATURES += "debug-tweaks"
# Use U-Boot bootloader
RPI_USE_U_BOOT = "1"
Supported MACHINE Values
| MACHINE | Target Board | Architecture |
|---|---|---|
raspberrypi5 | Raspberry Pi 5 | 64-bit (aarch64) |
raspberrypi4-64 | Raspberry Pi 4 | 64-bit (aarch64) |
raspberrypi4 | Raspberry Pi 4 | 32-bit (armhf) |
raspberrypi3-64 | Raspberry Pi 3 | 64-bit (aarch64) |
raspberrypi3 | Raspberry Pi 3 | 32-bit (armhf) |
raspberrypi2 | Raspberry Pi 2 | 32-bit (armhf) |
raspberrypi0-2w-64 | Raspberry Pi Zero 2 W | 64-bit (aarch64) |
I recommend 64-bit targets for Pi 3 and newer. If you're targeting Raspberry Pi 5, there are U-Boot issues to work around — see the dedicated RPi5 guide.
Building the Image
# Build a minimal image (smallest footprint)
bitbake core-image-minimal
# Or build a base image with slightly more tooling
bitbake core-image-base
# Expected build times (first run):
# - 8 cores / 32 GB RAM: ~1.5–2 hours
# - 4 cores / 16 GB RAM: ~3–4 hours
Verifying the Build Output
ls tmp/deploy/images/raspberrypi4-64/
core-image-minimal-raspberrypi4-64.wic.bz2 # Compressed SD card image
core-image-minimal-raspberrypi4-64.wic.bmap # Block map for fast flashing
Image # Kernel image
bcm2711-rpi-4-b.dtb # Device tree blob
Flashing the SD Card
bmaptool (Recommended — Much Faster)
bmaptool uses the .bmap file to skip empty blocks during writing. It's significantly faster than dd for sparse images.
# Install bmaptool
sudo apt install bmap-tools
# Check which device is your SD card
lsblk
# Flash the image (replace /dev/sdX with your actual device)
cd tmp/deploy/images/raspberrypi4-64/
sudo bmaptool copy core-image-minimal-raspberrypi4-64.wic.bz2 /dev/sdX
sync
dd (Traditional)
bzcat core-image-minimal-raspberrypi4-64.wic.bz2 | sudo dd of=/dev/sdX bs=4M status=progress
sync
Booting on Raspberry Pi
- Insert the SD card into your Raspberry Pi
- Connect an HDMI monitor and keyboard
- Connect power and let it boot
- When the login prompt appears, log in as
root(no password)
Poky (Yocto Project Reference Distro) 5.0 raspberrypi4-64 ttyAMA0
raspberrypi4-64 login: root
root@raspberrypi4-64:~# uname -a
Linux raspberrypi4-64 6.6.x-yocto-standard #1 SMP ... aarch64 GNU/Linux
root@raspberrypi4-64:~# cat /etc/os-release
NAME="Poky (Yocto Project Reference Distro)"
VERSION="5.0 (scarthgap)"
Wi-Fi, SSH, and GPIO Configuration
Enabling Wi-Fi
Add to conf/local.conf:
IMAGE_INSTALL:append = " linux-firmware-rpidistro-bcm43455 wpa-supplicant"
linux-firmware-rpidistro-bcm43455 is the Wi-Fi firmware for Raspberry Pi 4's BCM43455 chip. Raspberry Pi 5 uses a different Wi-Fi chip — see the dedicated RPi5 guide for that.
You can pre-configure Wi-Fi credentials with a wpa_supplicant.conf file included via a .bbappend on the wpa-supplicant recipe.
SSH Remote Login
Since you already added ssh-server-dropbear to IMAGE_FEATURES, SSH is ready to go.
# Check the IP address (with wired connection)
root@raspberrypi4-64:~# ip addr show eth0
# Connect from your development machine
ssh root@192.168.1.xxx
In practice, use SSH for all day-to-day work after the first boot. The HDMI monitor is just for verifying the initial boot.
GPIO Control
# Add GPIO tools to local.conf
IMAGE_INSTALL:append = " libgpiod libgpiod-tools"
After rebuilding and reflashing:
root@raspberrypi4-64:~# gpioinfo
root@raspberrypi4-64:~# gpioset -c gpiochip0 17=1 # Set GPIO17 HIGH
root@raspberrypi4-64:~# gpioget -c gpiochip0 27 # Read GPIO27
Troubleshooting
Black Screen — Nothing on HDMI
Cause: HDMI output configuration doesn't match your monitor.
Fix: Add to conf/local.conf:
HDMI_FORCE_HOTPLUG = "1"
HDMI_GROUP = "2"
HDMI_MODE = "82"
Kernel panic — not syncing
Cause: Mismatch between kernel and root filesystem.
Fix: Rebuild the image cleanly and re-flash the SD card.
wic.bz2 Image Not Found
Cause: IMAGE_FSTYPES doesn't include wic.
Fix: Add this to conf/local.conf:
IMAGE_FSTYPES = "wic.bz2 wic.bmap"
INCOMPATIBLE_LICENSE Error
ERROR: xxx has incompatible license
Cause: A package with commercial licensing requirements was included.
Fix: Explicitly accept the license in local.conf:
LICENSE_FLAGS_ACCEPTED = "commercial"
Wrapping Up
Here's what we covered:
- meta-raspberrypi provides all the Raspberry Pi board support
- MACHINE setting selects the exact target board
- wic format creates a ready-to-flash SD card image
- bmaptool is the fastest way to write images to SD cards
You now have a completely custom Linux running on Raspberry Pi — no Raspbian, no pre-installed bloat, just exactly what you put in the image. The same Yocto workflow scales from prototype to production.
- Raspberry Pi 5 dedicated guide — U-Boot fixes and Wi-Fi workarounds
- Writing recipes — package your own applications into images
- Getting started guide — revisit the fundamentals
These are also recommended.