To build custom Linux for Raspberry Pi with Yocto, clone Poky and meta-raspberrypi on the scarthgap branch, set MACHINE = "raspberrypi4-64" in local.conf, and run bitbake core-image-minimal. Flash the resulting .wic.bz2 to an SD card and boot.
This guide walks you through the full process 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 (https://github.com/agherzan/meta-raspberrypi)
git clone -b scarthgap git://git.yoctoproject.org/meta-raspberrypi
# Download meta-openembedded (https://github.com/openembedded/meta-openembedded)
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 libgpiod tools to your image:
# 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"
FAQ
Why use Yocto instead of Raspberry Pi OS?
Raspberry Pi OS (formerly Raspbian) is great for desktop use. But for embedded products, you need full control over every package, no unnecessary services, reproducible builds, and a minimal attack surface. Yocto gives you exactly that — build only what you need, nothing more.
How long does the first build take?
On an 8-core machine with 32 GB RAM, expect 1.5–2 hours for core-image-minimal. Subsequent builds are much faster because BitBake caches intermediate results. See our build speed optimization guide for tips on cutting build times.
Can I add my own application to the image?
Yes. Write a Yocto recipe (.bb file) for your application and add it to IMAGE_INSTALL. Place custom recipes in your own layer, not in meta-raspberrypi or Poky.
Does meta-raspberrypi support camera and display modules?
Yes. Set RASPBERRYPI_CAMERA_V2 = "1" or RASPBERRYPI_CAMERA_V3 = "1" in local.conf for camera support. The official 7-inch display also works via DSI. Check the meta-raspberrypi README for available configuration variables.
Should I use U-Boot or direct kernel boot?
RPI_USE_U_BOOT = "1" (U-Boot) is recommended for production because it enables A/B partition schemes and OTA updates. Direct kernel boot is simpler but lacks these features. For prototype/hobby projects, either works.
How do I auto-start a service on boot?
Use systemd. Write a systemd unit file, package it in a recipe with inherit systemd, and set SYSTEMD_AUTO_ENABLE = "enable". Yocto Scarthgap uses systemd by default when you set INIT_MANAGER = "systemd" in local.conf.
Can I use the same image across Raspberry Pi 3 and 4?
No. The MACHINE setting determines the target board, and each model has different device trees, bootloader configurations, and kernel settings. You need separate builds for Pi 3 (raspberrypi3-64) and Pi 4 (raspberrypi4-64), though the recipes and layers are shared.
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.
Related articles: