OS Build Instructions
Note: this page is the detailed/manual reference and was carried over from the original standalone
seedsigner-luckfox-picorepo, so some paths (e.g. a top-levelbuildroot/directory) reflect that older layout. For the current build/dev process in this merged repo — the./build.sh --luckfoxdispatcher, the reusable CI workflow, the package set, and reboot-to-flash (Loader) commands — see Luckfox Pico — build & development.
Build with GitHub Actions (Easiest Method)
For most users, building with GitHub Actions is the easiest and most reliable method. This approach builds directly on GitHub’s infrastructure without using Docker:
Using GitHub Actions
- Fork this repository to your GitHub account
- Go to the “Actions” tab in your fork
- Select the “Build SeedSigner OS” workflow
- The workflow runs automatically on every push to
main,develop, ormasterbranches - Wait for the build to complete (60-120 minutes)
- Download the artifacts from the completed workflow run
The workflow automatically:
- Installs all required build dependencies on Ubuntu 22.04
- Clones all required repositories:
luckfox-picoSDK (customized fork with SeedSigner modifications)seedsignercode (dev branch)seedsigner-ospackages
- Configures buildroot with SeedSigner-specific packages
- Builds for both hardware targets:
- LuckFox Pico Mini (RV1103)
- LuckFox Pico Pro Max (RV1106)
- Creates flashable SD card images and NAND flash bundles (for SD_CARD and SPI_NAND boot media)
- Provides detailed instructions for flashing both SD card images and NAND flash bundles
Note: The GitHub Actions workflow does NOT use Docker - it builds directly on the runner, following the same approach as the stock LuckFox Pico SDK.
Build Locally with Docker (Simple Method)
The Docker build is fully self-contained and handles all repository cloning and setup automatically. This is the easiest local build option.
Quick Start with build.sh
From the buildroot/ directory, simply run:
./build.sh build --microsd
Build artifacts will be automatically available in buildroot/build-output/ when the build completes.
Common Build Commands:
# Build SD card images for both Mini and Max
./build.sh build --microsd
# Build NAND flash bundles
./build.sh build --nand
# Build both SD and NAND artifacts
./build.sh build --microsd --nand
# Build only Mini hardware
./build.sh build --microsd --model mini
# Build only Max hardware
./build.sh build --microsd --model max
# Use 8 parallel jobs for faster builds
./build.sh build --microsd --jobs 8
# Interactive mode for debugging
./build.sh interactive
# Check build system status
./build.sh status
Key Features:
- Automatically builds Docker image if needed
- Uses persistent Docker volume for repository caching (faster subsequent builds)
- First build: 30-90 minutes (clones repos)
- Later builds: 15-45 minutes (reuses cached repos)
- Artifacts automatically exported to
build-output/directory
Output Location:
- Default:
buildroot/build-output/ - Custom:
./build.sh build --microsd --output /path/to/output
Alternative: Direct Docker Commands
If you prefer to use Docker commands directly (note: uses different output directory than build.sh):
# Build the Docker image
docker build -t foxbuilder:latest .
# Run the automated build (creates SD card images for both Mini and Max)
# Note: Artifacts will be in buildroot/output/ (not build-output/)
docker run --rm -v $(pwd)/output:/build/output foxbuilder:latest auto
# Or with NAND flash bundles included
docker run --rm -v $(pwd)/output:/build/output foxbuilder:latest auto-nand
Customize with environment variables:
# Build only Mini hardware
docker run --rm -v $(pwd)/output:/build/output -e BUILD_MODEL=mini foxbuilder:latest auto
# Build only Max hardware
docker run --rm -v $(pwd)/output:/build/output -e BUILD_MODEL=max foxbuilder:latest auto
# Adjust Mini CMA memory size
docker run --rm -v $(pwd)/output:/build/output -e MINI_CMA_SIZE=2M foxbuilder:latest auto
Build Locally Without Docker (Advanced/Development Users)
This method builds directly on your host system, mirroring the GitHub Actions workflow. Tested with Ubuntu 22.04.
Quick Start with build-local.sh
For the easiest non-Docker build experience, use the automated build script:
cd buildroot/
# Install dependencies (first time only)
./build-local.sh --check-deps
# Build for Mini with SD card (default)
./build-local.sh
# Build for Max with SD card
./build-local.sh --hardware max --boot sd
# Build for Mini with NAND
./build-local.sh --hardware mini --boot nand
# Just clone repositories
./build-local.sh --clone-only
# Clean build artifacts
./build-local.sh --clean
The script automates all the manual steps below and produces flashable images in luckfox-pico/output/image/.
Build time: 60-120 minutes for first build, 30-60 minutes for subsequent builds.
Manual Build Process (Step-by-Step)
If you prefer to run each step manually or need more control, follow these detailed instructions:
Prerequisites
Install required dependencies:
sudo apt-get update
sudo apt-get install -y \
git ssh make gcc gcc-multilib g++-multilib \
module-assistant expect g++ gawk texinfo \
libssl-dev bison flex fakeroot cmake unzip \
gperf autoconf device-tree-compiler \
libncurses5-dev pkg-config bc python-is-python3 \
passwd openssl openssh-server openssh-client \
vim file cpio rsync
Clone Required Repositories
Clone all required repositories into your working directory:
# Clone the LuckFox Pico SDK (customized fork with SeedSigner modifications)
git clone https://github.com/3rdIteration/luckfox-pico.git --depth=1 --single-branch
# Clone SeedSigner OS packages (buildroot package definitions)
git clone https://github.com/3rdIteration/seedsigner-os.git --depth=1 --single-branch
# Clone SeedSigner application code
git clone https://github.com/3rdIteration/seedsigner.git --depth=1 -b dev --single-branch --recurse-submodules
# Clone this repository (if not already)
git clone https://github.com/3rdIteration/seedsigner-luckfox-pico.git --depth=1 --single-branch
Set Up Build Environment
cd luckfox-pico
# Source the toolchain environment
cd tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf
source env_install_toolchain.sh
cd ../../../..
# Verify toolchain is accessible
which arm-rockchip830-linux-uclibcgnueabihf-gcc
Configure Board
Choose your hardware type and boot medium:
# For LuckFox Pico Mini with SD Card:
# Hardware index: 1 (RV1103_Luckfox_Pico_Mini)
# Boot index: 0 (SD_CARD)
# System index: 0 (Buildroot)
printf "1\n0\n0\n" | ./build.sh lunch
# For LuckFox Pico Pro Max with SD Card:
# Hardware index: 4 (RV1106_Luckfox_Pico_Pro_Max)
# Boot index: 0 (SD_CARD)
# System index: 0 (Buildroot)
printf "4\n0\n0\n" | ./build.sh lunch
# For SPI NAND boot, use boot index 1 instead of 0
Apply CMA Memory Configuration (Mini Only)
If building for Mini hardware, apply CMA memory configuration:
# Find the board config file
BOARD_CONFIG=$(find project/cfg/BoardConfig_IPC -name "BoardConfig-*-Buildroot-RV1103_Luckfox_Pico_Mini-IPC.mk" | head -n 1)
# Set CMA size to 1M (recommended for Mini)
if grep -q '^export RK_BOOTARGS_CMA_SIZE=' "$BOARD_CONFIG"; then
sed -i 's|^export RK_BOOTARGS_CMA_SIZE=.*|export RK_BOOTARGS_CMA_SIZE="1M"|' "$BOARD_CONFIG"
else
echo 'export RK_BOOTARGS_CMA_SIZE="1M"' >> "$BOARD_CONFIG"
fi
Prepare Buildroot Source Tree
make buildroot_create -C sysdrv
Install SeedSigner Packages
# Auto-detect buildroot directory
BUILDROOT_DIR=$(find sysdrv/source/buildroot -maxdepth 1 -type d -name 'buildroot-*' | sort | tail -n 1)
PACKAGE_DIR="${BUILDROOT_DIR}/package"
# Copy SeedSigner packages from seedsigner-os
cp -rv ../seedsigner-os/opt/external-packages/* "$PACKAGE_DIR/"
# Add SeedSigner menu to buildroot Config.in
CONFIG_IN="${PACKAGE_DIR}/Config.in"
if ! grep -q '^menu "SeedSigner"$' "$CONFIG_IN"; then
cat >> "$CONFIG_IN" << 'EOF'
menu "SeedSigner"
source "package/python-urtypes/Config.in"
source "package/python-pyzbar/Config.in"
source "package/python-mock/Config.in"
source "package/python-embit/Config.in"
source "package/python-pillow/Config.in"
source "package/zbar/Config.in"
source "package/jpeg-turbo/Config.in.options"
source "package/jpeg/Config.in"
source "package/python-qrcode/Config.in"
source "package/python-pyqrcode/Config.in"
endmenu
EOF
fi
Apply SeedSigner Buildroot Configuration
# Copy SeedSigner defconfig
cp -v ../seedsigner-os/opt/luckfox/configs/luckfox_pico_defconfig "$BUILDROOT_DIR/configs/luckfox_pico_defconfig"
cp -v ../seedsigner-os/opt/luckfox/configs/luckfox_pico_defconfig "$BUILDROOT_DIR/.config"
# Update pyzbar patch with Python version
PYZBAR_PATCH="${PACKAGE_DIR}/python-pyzbar/0001-PATH-fixed-by-hand.patch"
if [ -f "$PYZBAR_PATCH" ] && [ -f "$BUILDROOT_DIR/.config" ]; then
PYTHON_VER=$(grep -oP 'BR2_PACKAGE_PYTHON3_VERSION="\K[^"]+' "$BUILDROOT_DIR/.config" 2>/dev/null || echo "3.11")
sed -i "s|path = \".*/site-packages/zbar.so\"|path = \"/usr/lib/python${PYTHON_VER}/site-packages/zbar.so\"|" "$PYZBAR_PATCH"
echo "Updated pyzbar patch for Python ${PYTHON_VER}"
fi
Build System
./build.sh uboot
./build.sh kernel
./build.sh rootfs
./build.sh media
./build.sh app
Install SeedSigner Application
# Find rootfs directory
ROOTFS_DIR=$(find output/out -maxdepth 1 -type d -name "rootfs_uclibc_*" | head -n 1)
# Copy SeedSigner code
cp -rv ../seedsigner/src/ "$ROOTFS_DIR/seedsigner"
# Patch settings.json for Mini hardware (if applicable)
# For Mini, change FOX_40 to FOX_22
SETTINGS_JSON="$ROOTFS_DIR/seedsigner/settings.json"
if [ -f "$SETTINGS_JSON" ]; then
# Uncomment the following line if building for Mini:
# sed -i 's/"hardware_config":[[:space:]]*"FOX_40"/"hardware_config": "FOX_22"/g' "$SETTINGS_JSON"
echo "Settings.json ready"
fi
# Fix pyzbar library path
PYTHON_VERSION=$(ls "$ROOTFS_DIR/usr/lib/" | grep -E '^python3\.[0-9]+$' | head -n 1)
if [ -n "$PYTHON_VERSION" ]; then
SITE_PACKAGES="$ROOTFS_DIR/usr/lib/$PYTHON_VERSION/site-packages"
if [ -f "$SITE_PACKAGES/zbar.so" ]; then
ln -sf "$PYTHON_VERSION/site-packages/zbar.so" "$ROOTFS_DIR/usr/lib/zbar.so"
echo "Created zbar.so symlink for pyzbar"
fi
fi
# Copy configuration files
cp -v ../seedsigner-os/opt/luckfox/files/luckfox.cfg "$ROOTFS_DIR/etc/luckfox.cfg"
cp -v ../seedsigner-os/opt/luckfox/files/nv12_converter "$ROOTFS_DIR/"
cp -v ../seedsigner-os/opt/luckfox/files/start-seedsigner.sh "$ROOTFS_DIR/"
cp -v ../seedsigner-os/opt/luckfox/files/S99seedsigner "$ROOTFS_DIR/etc/init.d/"
Package Firmware
./build.sh firmware
Create Flashable SD Image
For SD card boot configurations:
cd output/image
# Determine board label (mini or max based on your build)
BOARD_LABEL="mini" # or "max"
# Artifact name tag: <appref>-os<develop|production>-<unsigned|signed[-devkey|-realkey]|burnable[-devkey|-realkey]>
# (match build-local.sh's artifact_tag so manual and scripted builds compare by name)
TAG="dev-os-production-unsigned"
IMAGE_NAME="seedsigner-luckfox-pico-${BOARD_LABEL}-sd-${TAG}.img"
# Use blkenvflash to create the SD image
../../seedsigner-os/opt/luckfox/blkenvflash "$IMAGE_NAME"
echo "SD card image created: $IMAGE_NAME"
Create NAND Flash Bundle (Optional)
For SPI NAND boot configurations.
First, repoint the SDK’s U-Boot flashing scripts at a staging address the rootfs actually fits below. build.sh and build-local.sh do this for you; a manual build must run it explicitly, before packaging:
# from the luckfox-pico directory, after ./build.sh firmware
bash ../seedsigner-os/opt/luckfox/patch-sd-update-scripts.sh .
Why: the SDK generates
sd_update.txt/tftp_update.txtso that every step stages the whole partition image in DRAM at${ramdisk_addr_r}(0x00E00000) beforemtd write. On a Pico Mini (RV1103, 64 MiB DRAM) U-Boot relocates itself to the top of RAM and its stack/heap/fdt start at about0x02DF0000, so only ~31 MiB is usable above0x00E00000. SeedSigner’srootfs.imgis ~38.6 MiB, somw.bruns straight over the loader that is executing the script: the microSD auto-flash hangs on the rootfs step with no console output at all. Restaging at0x00100000widens the window to ~44 MiB. The script also hard-fails the build if any image outgrows that.This only affects the microSD auto-flash path. Flashing
update.imgover USB (SocToolKit /rkdeveloptool, MASKROM mode) streams to flash and never stages a partition in DRAM, so it is unaffected and remains the recommended route.
Then package:
cd output/image
BOARD_LABEL="mini" # or "max"
# Same artifact name tag as the SD image above (see artifact_tag in build-local.sh)
TAG="dev-os-production-unsigned"
NAND_BUNDLE_DIR="seedsigner-luckfox-pico-${BOARD_LABEL}-nand-files-${TAG}"
mkdir -p "$NAND_BUNDLE_DIR"
# Copy required NAND flashing files
cp update.img download.bin env.img idblock.img uboot.img boot.img \
userdata.img rootfs.img sd_update.txt tftp_update.txt \
"$NAND_BUNDLE_DIR/"
# Create tar.gz archive
tar -czf "seedsigner-luckfox-pico-${BOARD_LABEL}-nand-bundle-${TAG}.tar.gz" "$NAND_BUNDLE_DIR"
echo "NAND bundle created: seedsigner-luckfox-pico-${BOARD_LABEL}-nand-bundle-${TAG}.tar.gz"
Advanced Docker Build (Legacy Method)
For advanced users who want more control over the Docker build process, follow these instructions: Run these commands from buildroot directory.
Build the builder image:
cd buildroot/
docker build -t foxbuilder:latest .
IMPORTANT We need all of these directories to be setup, and cloned in our $HOME directory:
ls ~
luckfox-pico seedsigner seedsigner-luckfox-pico seedsigner-os
The seedsigner-luckfox-pico directory is this repo we are already in!
Clone the Luckfox SDK repo:
git clone https://github.com/3rdIteration/luckfox-pico.git \
--depth=1 --single-branch
Clone the Seedsigner OS repo:
git clone https://github.com/3rdIteration/seedsigner-os.git \
--depth=1 --single-branch
Clone the Seedsigner repo:
git clone https://github.com/3rdIteration/seedsigner.git \
--depth=1 -b dev --single-branch --recurse-submodules
Run OS Build
Run these commands from buildroot/ directory. This is the directory/repo we cloned above.
LUCKFOX_SDK_DIR=$HOME/luckfox-pico
SEEDSIGNER_CODE_DIR=$HOME/seedsigner
LUCKFOX_BOARD_CFG_DIR=$HOME/seedsigner-luckfox-pico
SEEDSIGNER_OS_DIR=$HOME/seedsigner-os
# TODO check all these above paths exist
docker run -d --name luckfox-builder \
-v $LUCKFOX_SDK_DIR:/mnt/host \
-v $SEEDSIGNER_CODE_DIR:/mnt/ss \
-v $LUCKFOX_BOARD_CFG_DIR:/mnt/cfg \
-v $SEEDSIGNER_OS_DIR:/mnt/ssos \
foxbuilder:latest
These below commands are run INSIDE of the docker image.
Enter the container:
docker exec -it luckfox-builder bash
Start the build:
/mnt/cfg/buildroot/add_package_buildroot.sh
This commands sets the build targets: Select, Pico Pro Max, buildroot, and SPI.
# set build configuration
./build.sh lunch
This command allows us to choose what packages to install into our OS image.
# configure packages to install in buildroot
./build.sh buildrootconfig


After selecting all the above packages, SAVE the configuration. The configuration is saved at: sysdrv/source/buildroot/buildroot-2023.02.6/.config
You can sanity check your configuration to ensure the selected packages have been enabled like so:
cat sysdrv/source/buildroot/buildroot-2023.02.6/.config | grep "ZBAR"
cat sysdrv/source/buildroot/buildroot-2023.02.6/.config | grep "LIBJPEG"
...
A final sanity check, this shows all enabled packages… This might be useful as we try and remove any unnecessary packages from the build:
cat sysdrv/source/buildroot/buildroot-2023.02.6/.config | grep -v "^#"
Adding Custom Packages
If you need to add custom packages to the buildroot configuration, you can use the add_package_buildroot.sh script. This script:
- Adds SeedSigner-specific packages to the buildroot configuration
- Copies necessary package files from the seedsigner-os repository
- Updates Python paths and configurations
- Adds required dependencies like python-pyzbar, python-embit, and camera-related packages
To use the script:
# From the buildroot directory
./add_package_buildroot.sh
This command will use one of the saved configurations for the build:
# Use config from repo
cp ../configs/config_20241218184332.config sysdrv/source/buildroot/buildroot-2023.02.6/.config
# Sanity check the configuration was loaded properly
# Selected packages like ZBAR should be listed as enabled here
./build.sh buildrootconfig
Start the image compilation process:
./build.sh uboot
./build.sh kernel
./build.sh rootfs
# needed for camera libs
./build.sh media
Verify all of the .img files are there:
$ ls /mnt/host/output/out/
S20linkmount media_out rootfs_uclibc_rv1106 sysdrv_out
$ ls /mnt/host/output/image/
boot.img download.bin idblock.img uboot.img
Copy over app code and pin configs
# Pin configs
cp /mnt/cfg/config/luckfox.cfg /mnt/host/output/out/rootfs_uclibc_rv1106/etc/luckfox.cfg
# Seedsigner code
cp -r /mnt/ss/src/ /mnt/host/output/out/rootfs_uclibc_rv1106/seedsigner
Package:
# Package up the pieces
./build.sh firmware
Double check the output, now all of the expected .img files are there:
$ ls /mnt/host/output/image/
boot.img download.bin env.img idblock.img rootfs.img sd_update.txt tftp_update.txt uboot.img update.img userdata.img
Final Piece of Sanity Checking:
dbg='yes' ./tools/linux/Linux_Upgrade_Tool/rkdownload.sh -d output/image/
Package into single flashable ISO image:
cd /mnt/host/output/image
/mnt/cfg/buildroot/blkenvflash seedsigner-luckfox-pico.img
Send back to dev machine (if building on a remote X86 machine):
scp ubuntu@11.22.33.44:/home/ubuntu/seedsigner-os/opt/luckfox/luckfox-pico/output/image/seedsigner-luckfox-pico.img ~/Downloads
Flash to MicroSD Card:
sudo dd bs=4M \
status=progress \
if=/Users/lightningspore/Downloads/seedsigner-luckfox-pico.img \
of=/dev/disk8
Put MicroSD Card into Luckfox Pico Device.
adb shell
TODO: Link to next steup in the install/setup process
Official resources
Luckfox Pico Official Flashing Guide - Official documentation for flashing images to the Luckfox Pico device on Linux and macOS systems
Hardware Device Overlay Config
cat luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts/rv1103g-luckfox-pico.dts
cat luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts/rv1103.dtsi
cat luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts/rv1103-luckfox-pico-ipc.dtsi
cat luckfox-pico/sysdrv/source/kernel/arch/arm/boot/dts/rv1106-evb.dtsi