Buildroot: Custom Image with SDL2 and SPI
Time estimate: ~90+ minutes (build time: 30--60 minutes) Prerequisites: Buildroot: Minimal Linux
Learning Objectives
By the end of this tutorial you will be able to:
- Extend a Buildroot configuration for a specific application
- Add SDL2 with KMSDRM backend support
- Enable SPI kernel support in Buildroot
- Measure the boot time impact of added packages
Understanding Buildroot Package Selection
Buildroot is a tool that cross-compiles a complete Linux system — kernel, libraries, and
applications — for an embedded target. Its menuconfig interface lets you select exactly which
packages to include in the final image. Each selected package is downloaded, cross-compiled for
the target architecture, and installed into the root filesystem. For example, enabling SDL2 with
the KMSDRM backend adds the SDL2 library and its DRM/KMS rendering support so that graphical
applications can run without a desktop environment. Because only the packages you select are
included, the resulting image stays small — typically tens to hundreds of megabytes instead of
the gigabytes required by a full desktop distribution.
For a deeper look at why you would build a custom Linux image and how Buildroot, Yocto, and other build systems compare, see the Building Custom Linux Reference.
1. Start from Existing Config
Navigate to your Buildroot directory from the previous tutorial and load your saved configuration:
cd ~/buildroot
make raspberrypi4_64_defconfig
# Or load your saved config from the previous tutorial:
# cp ../my_saved_defconfig .config
Open the configuration menu:
Tip
If you saved a defconfig in the previous tutorial with make savedefconfig, you can restore it by copying it to configs/ and running make <your_defconfig>. This ensures you start from a known working state.
2. Enable SPI Support
SPI kernel support is needed for communicating with hardware like the BMI160 accelerometer in later tutorials.
In make menuconfig, navigate to:
Select Use the architecture default configuration or if you are using a custom fragment, ensure the following options are enabled:
Then run the kernel configuration tool:
Navigate to:
Device Drivers → SPI support →
[*] BCM2835 SPI controller
[*] User mode SPI device driver support (spidev)
These two options do the following:
| Option | Purpose |
|---|---|
BCM2835 SPI controller |
Hardware SPI driver for the Raspberry Pi's Broadcom SoC |
User mode SPI device driver support |
Exposes SPI devices as /dev/spidevX.Y for userspace access |
Save and exit the kernel configuration.
Checkpoint
After saving the kernel config, verify your selections are stored. Run make linux-menuconfig again and confirm both SPI options show [*].
Stuck?
If you cannot find BCM2835 SPI controller, make sure you are building for the correct platform (raspberrypi4_64_defconfig). The BCM2835 driver also covers BCM2836/2837/2711 used in Pi 3 and Pi 4.
3. Add SDL2
SDL2 (Simple DirectMedia Layer) provides cross-platform graphics, audio, and input handling. For embedded Linux without a window manager, we use the DRM/KMS backend which renders directly to the display via the kernel's DRM/KMS subsystem.
In make menuconfig, navigate to:
After enabling SDL2, enter its submenu and configure:
This tells SDL2 to use the DRM/KMS interface instead of X11 or Wayland. On an embedded system without a desktop environment, this is the correct backend.
SDL2 will automatically pull in its dependencies:
| Dependency | Purpose |
|---|---|
libdrm |
Kernel DRM/KMS interface library |
mesa3d (optional) |
GPU acceleration (may not be selected by default) |
libgbm |
Generic buffer management for DRM |
Tip
Do not enable the X11 or Wayland video drivers unless you specifically need them. Each adds significant build time and image size.
SDL2's KMSDRM backend also requires the VC4 DRM driver in the kernel. Verify it is enabled in the kernel config:
Navigate to:
This is typically enabled by default in the Raspberry Pi defconfig, but verify it is present.
4. Add Python3 Packages
For prototyping and testing, add Python3 with SPI and numerical libraries:
In make menuconfig, navigate to:
Then add the additional Python packages:
Target packages → Interpreter languages and scripting → External python modules →
[*] python-spidev
[*] python-numpy
| Package | Purpose |
|---|---|
python3 |
Python interpreter for prototyping |
python-spidev |
Python bindings for /dev/spidevX.Y |
python-numpy |
Numerical arrays — used for sensor data processing |
Tip
python-numpy significantly increases build time (10--15 minutes). If you are short on time, you can skip it and add it later. python-spidev is small and builds quickly.
5. Enable Device Tree Overlay Support
Device tree overlays allow you to describe additional hardware (like SPI sensors) without modifying the base device tree. Ensure overlay support is included in the boot partition.
In make menuconfig, check:
If you have a custom overlay directory (e.g., board/raspberrypi4-64/rootfs-overlay/), ensure it includes the /boot/overlays/ directory structure.
Also verify in the kernel configuration (make linux-menuconfig):
Tip
On Raspberry Pi, overlays are loaded by the firmware before the kernel starts. The config.txt file on the boot partition controls which overlays are applied. Ensure your Buildroot post-build scripts copy config.txt to the boot partition.
6. Build
Save your configuration and start the build:
This will take 30--60 minutes depending on your host machine. What happens during the build:
| Phase | Duration | What Happens |
|---|---|---|
| Toolchain | 5--10 min | Cross-compiler is built (if not cached) |
| Kernel | 5--15 min | Linux kernel is compiled with your SPI options |
| SDL2 + deps | 5--10 min | SDL2 and its dependencies are compiled |
| Python3 + numpy | 10--15 min | Python interpreter and numerical library |
| Root filesystem | 1--2 min | All packages are assembled into a filesystem image |
| Image generation | <1 min | SD card image is created |
The final image will be at output/images/sdcard.img.
Checkpoint
The build should complete without errors. The image file should exist and be larger than your previous minimal image (typically 150--300 MB vs 50--80 MB for minimal).
Stuck?
Common build failures:
- Missing host dependencies: Run
sudo apt install build-essential libncurses-devand any packages Buildroot reports missing. - Network errors: Buildroot downloads source tarballs during build. Ensure internet access.
- Disk space: A full build can use 5--10 GB. Check with
df -h. - Partial rebuild: If a single package fails, fix the issue and run
makeagain. Buildroot will resume from where it stopped.
7. Flash and Boot
Write the image to an SD card (replace sdX with your SD card device):
# Identify your SD card
lsblk
# Write the image (WARNING: this erases the SD card)
sudo dd if=output/images/sdcard.img of=/dev/sdX bs=4M status=progress
sudo sync
Insert the SD card into the Raspberry Pi, boot, and connect via SSH or serial console.
Verify the new components:
Expected output:
Expected output:
# Check Python and spidev
python3 -c "import spidev; print('spidev OK')"
python3 -c "import numpy; print('numpy', numpy.__version__)"
Checkpoint
All three checks should pass:
/dev/spidev*devices existsdl2-config --versionprints a version number- Python can import
spidevandnumpywithout errors
Stuck?
SPI devices not appearing:
- Check that
dtparam=spi=onis in/boot/config.txt(or equivalent on your image) - Verify kernel config:
zcat /proc/config.gz | grep SPIshould showCONFIG_SPI_BCM2835=y
SDL2 missing KMSDRM backend:
- Run
sdl2-config --libsand check ifkmsdrmappears in the video drivers - If not, re-run
make menuconfigand verify the kmsdrm option is selected in SDL2's submenu
Python import errors:
- Ensure the packages were selected in Buildroot menuconfig
- Run
make python-spidev-rebuildandmaketo rebuild just that package
8. Measure Boot Time
Compare the boot time of this image to your previous minimal image.
If your image includes systemd:
If your image uses BusyBox init (no systemd), measure manually:
The first number from /proc/uptime is seconds since boot.
Fill in the comparison table:
| Metric | Minimal Image | SDL2 + SPI Image | Difference |
|---|---|---|---|
| Image size (MB) | |||
| Kernel boot (s) | |||
| Total boot to login (s) | |||
| Number of packages |
Check image size:
Count installed packages:
Tip
Each added package increases image size and potentially boot time. In production embedded systems, every package must justify its inclusion. This trade-off analysis is a core skill in embedded Linux engineering.
What Just Happened?
You extended a minimal Buildroot Linux image with specific application requirements:
- SPI kernel support — enabled at the kernel level so hardware SPI peripherals appear as
/dev/spidevX.Y - SDL2 with KMSDRM — a graphics library that renders directly to the display without a window manager
- Python prototyping tools —
spidevandnumpyfor rapid hardware testing - Device tree overlay support — so you can add hardware descriptions without rebuilding the kernel
This image will serve as the base for the BMI160 SPI driver tutorial and the display application tutorials. The key engineering decision was choosing the KMSDRM backend for SDL2, which avoids the overhead of X11/Wayland while still providing a standard graphics API.
Challenges
Challenge 1: Add OpenCV
Enable OpenCV in Buildroot (Target packages → Libraries → Graphics → opencv4). Measure the build time increase and final image size. How much larger is the image compared to SDL2 alone?
Challenge 2: Minimize Image Size
Starting from your current config, try to reduce the image size by removing unnecessary features (e.g., disable Python readline, remove unused SDL2 backends). Document each change and its size impact. What is the smallest image that still has working SDL2 + SPI + Python?
Challenge 3: Boot Time Budget
Create a boot time budget document that allocates time to each boot phase. If the requirement is "application ready in under 5 seconds," which components would you need to optimize or remove?
Deliverable
Submit the following:
| Item | Description |
|---|---|
| Buildroot defconfig | Your saved defconfig file (from make savedefconfig) |
| Verification screenshot | Terminal output showing SPI, SDL2, and Python checks from Step 7 |
| Boot time comparison table | Completed table from Step 8 comparing minimal vs. SDL2+SPI image |
| Image size comparison | File sizes of both images |