Building Embedded Debian for the DE10 Nano
The DE10 Nano is a low cost Intel / Altera Cyclone V SoC development board made by Terasic. The board combines a Cyclone V FPGA with a dual core ARM processor.
These instructions show how the build an SD card with the latest (as of Sept 2021) mainline Linux Kernel, U-Boot, and Debian root file system.
While these instructions are specific to the DE10 Nano, the process is very similar for any embedded system with an ARM processor.
1.0 Prerequisites
A Ubuntu 21.04 system was used for this build, but most Linux systems should work fine.
# For building U-Boot and the Linux kernel
sudo apt install libncurses-dev flex bison openssl \
libssl-dev dkms libelf-dev libudev-dev libpci-dev \
libiberty-dev autoconf bc libmpc-dev libgmp-dev
# For debian root filesystem
sudo apt install debootstrap qemu-user-static systemd-container
Create a directory to build everything in.
mkdir -p ~/de10
cd ~/de10
2.0 Get an ARM toolchain
Download the latest stable armebv7-eabihf / glibc toolchain from bootlin.
# cd to de10 directory
mkdir toolchain
cd toolchain
wget https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--glibc--stable-2020.08-1.tar.bz2
tar -xf armv7-eabihf--glibc--stable-2020.08-1.tar.bz2
rm armv7-eabihf--glibc--stable-2020.08-1.tar.bz2
# The CROSS_COMPILE variable must be set in any terminal used to build u-boot or the kernel
export CROSS_COMPILE=$PWD/armv7-eabihf--glibc--stable-2020.08-1/bin/arm-linux-
3.0 Build the u-boot bootloader
Make sure CROSS_COMPILE variable is still set in the environment.
# cd to de10 directory
git clone https://github.com/u-boot/u-boot.git
cd u-boot
# This is the latest version at time of writing
git checkout v2021.07
# Configure the the DE10 nano Intel FPGA SoC
make ARCH=arm socfpga_de10_nano_defconfig
# Optional: run make ARCH=arm menuconfig to have a play around
make ARCH=arm -j $(nproc)
# Desired output file is: u-boot/u-boot-with-spl.sfp
The defconfig for DE10-nano is in u-boot/configs/socfpga_de10_nano_defconfig
.
When this config is set, u-boot/arch/arm/mach-socfpga/Kconfig
sets the device to: u-boot/board/terasic/de10-nano/
.
In u-boot/board/terasic/de10-nano/qts
(qts = Quartus) there are 4 files that set ram timing, pin MUXing, and PLL settings.
The defaults will work for most applications, but if required they can be changed manually, or can be generated from the BSP handover files generated by the Intel Quartus software. See u-boot/docs/README.socfpga
for more info.
4.0 Build the Linux kernel
Make sure CROSS_COMPILE variable is still set in the environment.
# cd to de10 directory
git clone https://github.com/torvalds/linux.git
cd linux
# This is the latest version at time of writing
git checkout v5.14
# Configure kernel
make ARCH=arm socfpga_defconfig
make ARCH=arm menuconfig
Set the following kernel options:
- Under General setup and uncheck "Automatically append version information to the version string" (optional).
- Under File systems, enable "Overlay Filesystem Support" and all the options under it.
- Under File systems, Pseudo File Systems, Enable "Userspace-driven configuration filesystem".
Build the kernel:
# Compile kernel - This will take several minutes
make ARCH=arm LOCALVERSION=zImage -j $(nproc)
# Desired output file is: linux/arch/arm/boot/zImage
# Optionally save the config for future use
make savedefconfig
mv defconfig arch/arm/configs/socfpga_de10_defconfig
5.0 Make a Debian root filesystem
Generate a skeleton root filesystem
# cd to de10 directory
mkdir rootfs
sudo debootstrap --arch=armhf --foreign bullseye rootfs
# NB you can optionally specify a local mirror like this (might help if package downloads timeout):
# sudo debootstrap --arch=armhf --foreign bullseye rootfs http://ftp.uk.debian.org/debian
sudo systemd-nspawn -D ./rootfs/
This will create a container running the generated filesystem. From here the root filesystem can be customised as desired.
Finish setting up Debian
/debootstrap/debootstrap --second-stage
Enable UART TTY
# Add UART TTY out
systemctl enable serial-getty@ttyS0.service
# Set root password
passwd
Set up mount points
nano /etc/fstab
Add the following lines to the file:
tmpfs /tmp tmpfs rw,mode=1777 0 0
/dev/mmcblk0p2 / ext4 defaults 0 1
Set locale to en_GB.UTF-8
apt install locales
dpkg-reconfigure locales
Set hostname
This can be set to any value. E.g. de10-nano
.
nano /etc/hostname
Set up DHCP
nano /etc/network/interfaces
Add the following under line "source-directory /etc/network/interfaces.d"
auto lo eth0
allow-hotplug eth0
iface lo inet loopback
iface eth0 inet dhcp
Install SSH
apt install openssh-server
nano /etc/ssh/sshd_config
# Add: PermitRootLogin yes
Install other useful packages
apt install net-tools build-essential device-tree-compiler
apt install python3.7
apt install python3-pip
python3 -m pip install --upgrade pip
python3 -m pip install zmq
python3 -m pip install pyserial
Clean up
pip3 cache purge
apt clean
exit
Compress the root filesystem
# cd to de10 directory
cd rootfs
sudo tar -cjpf ../rootfs.tar.bz2 .
cd ..
sudo chown $USER:$USER rootfs.tar.bz2
6.0 Create the SD card image
Create a blank image file
Create at least a 1 GB image, and connect it as a loop device.
# cd to de10 directory
sudo dd if=/dev/zero of=de10_nano_sd.img bs=1G count=1
sudo losetup --show -f de10_nano_sd.img
# Make sure you note the name of the loop device that is used.
# Typically: /dev/loopX where X is a number.
Partition the image
sudo fdisk /dev/loopX
Make the U-Boot and SPL partition:
n <Enter>, p <Enter>, 3 <Enter>, <Enter>, +1M <Enter>, t <Enter>, a2 <Enter>
Make the kernel partition:
n <Enter>, p <Enter>, 1 <Enter>, <Enter>, +254M <Enter>, t <Enter>, 1 <Enter>, b <Enter>
Make the Root Filesystem partition:
n <Enter>, p <Enter>, 2 <Enter>, <Enter>, <Enter>
Check partitions:
p <enter>
Expected output:
Device Boot Start End Sectors Size Id Type
/dev/loop0p1 4096 524287 520192 254M b W95 FAT32
/dev/loop0p2 524288 2097151 1572864 768M 83 Linux
/dev/loop0p3 2048 4095 2048 1M a2 unknown
Write the partitions
w <Enter>
NB: The following command can instead be used to partition the disk in a scriptable (non-interactive) manner:
(
echo n; echo p; echo 3; echo; echo +1M; echo t; echo a2; # Make the U-Boot partition
echo n; echo p; echo 1; echo; echo +254M; echo t; echo 1; echo b; # Make kernel partition
echo n; echo p; echo 2; echo; echo; # Make the root file system partition
echo w; # Write the changes
) | sudo fdisk /dev/loopX
It is normal to get error "Re-reading the partition table failed.: Invalid argument".
Load the partitions:
sudo partprobe /dev/loopX
ls /dev/loopX*
should show:
/dev/loopX /dev/loopXp1 /dev/loopXp2 /dev/loopXp3
Create the filesystems
sudo mkfs -t vfat /dev/loopXp1
sudo mkfs -t ext4 /dev/loopXp2
Copy over U-BOOT
Remember to change /dev/loopX the the right value
# cd to de10 directory
sudo dd if=./u-boot/u-boot-with-spl.sfp of=/dev/loopXp3 bs=64k seek=0 oflag=sync
Copy Kernel and device tree
# cd to de10 directory
mkdir fat
sudo mount /dev/loopXp1 fat
sudo cp linux/arch/arm/boot/zImage fat
# Use DE0 DTB for now as no DE10 DTB and they are basically the same board
sudo cp linux/arch/arm/boot/dts/socfpga_cyclone5_de0_nano_soc.dtb fat
Generate extlinux file
# cd to de10 directory
echo "LABEL Linux Default" > extlinux.conf
echo " KERNEL ../zImage" >> extlinux.conf
echo " FDT ../socfpga_cyclone5_de0_nano_soc.dtb" >> extlinux.conf
echo " APPEND root=/dev/mmcblk0p2 rw rootwait earlyprintk console=ttyS0,115200n8" >> extlinux.conf
sudo mkdir -p fat/extlinux
sudo cp extlinux.conf fat/extlinux
sudo umount fat
rm extlinux.conf
Copy root filesystem
# cd to de10 directory
mkdir ext4
sudo mount /dev/loopXp2 ext4
cd ext4
sudo tar -xf ../rootfs.tar.bz2
cd ..
sudo umount ext4
Remove loopback
sudo losetup -d /dev/loopX
7.0 Write the image to an SD card
Remember to change /dev/sdX to the right value for your SD card!
# cd to de10 directory
sudo dd if=de10_nano_sd.img of=/dev/sdX bs=64K status=progress
sync
Pop the SD card into the DE10 nano, and it should boot up into Debian!