32blogby StudioMitsu
yocto7 min read

Build Custom Linux for Raspberry Pi with Yocto

Build custom Linux for Raspberry Pi with Yocto Scarthgap. Covers meta-raspberrypi, SD card flashing, Wi-Fi, and GPIO.

yoctoembedded-linuxraspberry-piscarthgap
On this page

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

bash
# 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.

bash
# Initialize the build environment
cd ~/yocto/poky
source oe-init-build-env build-rpi

Adding Layers

bash
# 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:

text
# 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

MACHINETarget BoardArchitecture
raspberrypi5Raspberry Pi 564-bit (aarch64)
raspberrypi4-64Raspberry Pi 464-bit (aarch64)
raspberrypi4Raspberry Pi 432-bit (armhf)
raspberrypi3-64Raspberry Pi 364-bit (aarch64)
raspberrypi3Raspberry Pi 332-bit (armhf)
raspberrypi2Raspberry Pi 232-bit (armhf)
raspberrypi0-2w-64Raspberry Pi Zero 2 W64-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

bash
# 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

bash
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 uses the .bmap file to skip empty blocks during writing. It's significantly faster than dd for sparse images.

bash
# 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)

bash
bzcat core-image-minimal-raspberrypi4-64.wic.bz2 | sudo dd of=/dev/sdX bs=4M status=progress
sync

Booting on Raspberry Pi

  1. Insert the SD card into your Raspberry Pi
  2. Connect an HDMI monitor and keyboard
  3. Connect power and let it boot
  4. When the login prompt appears, log in as root (no password)
text
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:

text
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.

bash
# 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

text
# Add GPIO tools to local.conf
IMAGE_INSTALL:append = " libgpiod libgpiod-tools"

After rebuilding and reflashing:

bash
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:

text
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:

text
IMAGE_FSTYPES = "wic.bz2 wic.bmap"

INCOMPATIBLE_LICENSE Error

text
ERROR: xxx has incompatible license

Cause: A package with commercial licensing requirements was included.

Fix: Explicitly accept the license in local.conf:

text
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.

These are also recommended.

PRRaspberry Pi 5 8GBView on Amazon
PRMastering Embedded Linux Development 4th Ed (2024)View on Amazon
PREmbedded Linux Development Using Yocto Project 3rd Ed (2023)View on Amazon