Open RF Prototyping

Red Pitaya Development Environment

Creating a Debian VM on MacOS

Configuring a preseed file for the installation

These instructions assume the use of the VirtualBox virtualization environment running on Mac OS. The build makes use of a Debian preseed file Debian Preseed. An example preseed config. file can be downloaded from: Stable preseed.cfg (for the latest stable Debian version). The mini.iso file used here can be downloaded from: Debian Bullseye mini.iso.

A quick way to make the seed script available on your local host is to copy it into a directory (say ~/software/temp) and running Python as follows:

python -m http.server 8080

For Python 2 use:

cd ~/software/temp
python -m SimpleHTTPServer 8080

The seed script is would then be available at the following URL: http://localhost:8080/bullseye.seed.

Configuring the seed script

Having downloaded the seed file it should be configured. At a minimum this involves the following: (See https://wiki.debian.org/DebianInstaller/Preseed for information on configuring and using preseed files.)

  • Set a suitable mirror:

    d-i mirror/http/hostname string ftp.iinet.net.au
    d-i mirror/http/directory string /pub/debian
  • Set details for the root account and the first regular account. For some reason the password hashes are generated using a ruby version of mkpasswd. This can be installed using:

    sudo gem install mkpasswd
    

    And the password hash is generated as follows:

    mkpasswd -m md5
    

    In this case the password is set to changeme with the hash being:

    $1$yUCwGuIB$siG3RFUyLS9lxYh.RM9n60

    The relevant lines in the preseed file are then:

    d-i passwd/root-login boolean true
    d-i passwd/root-password-crypted password $1$yUCwGuIB$siG3RFUyLS9lxYh.RM9n60
    
    d-i passwd/user-fullname string Dyadic
    d-i passwd/username string dyadic
    d-i passwd/user-password-crypted password $1$yUCwGuIB$siG3RFUyLS9lxYh.RM9n60
  • Set the hostname. Note that we should configure any other essential packages required here as well.

    d-i preseed/late_command string \
      in-target /bin/bash -c 'echo openems-dev > /etc/hostname'; \
      in-target apt-get --yes --no-install-recommends install \
      network-manager openssh-server x11-session-utils x11-utils \
      autofs samba git curl ca-certificates xauth \
      build-essential less vim screen sudo psmisc \
      libxrender1 libxtst6 libxi6 lib32ncurses5-dev \
      crossbuild-essential-armhf python \
      bc u-boot-tools device-tree-compiler libncurses5-dev \
      libssl-dev qemu-user-static binfmt-support \
      dosfstools parted debootstrap

Create the Virtualbox VM

This is done using the instructions from here red-pitaya-notes:

  • Download the Debian mini.iso file.

  • Make the preseed file available:

    cd ~/software/temp
    python -m http.server 8080
    

    For Python 2 the command will be:

    python -m SimpleHTTPServer 8080
    
  • Start VirtualBox

  • Create at least one host-only interface:

    • From the File menu select Host Network Manager

    • Click the green Create icon

    • Click “Close”

  • Create a new virtual machine:

    • Click the blue New icon

    • Pick a name for the machine, then select Linux and Debian (64 bit)

    • Set the memory size to at least 4096 MB

    • Select Create a virtual hard disk now

    • Select VDI (VirtualBox Disk Image)

    • Select Dynamically allocated

    • Set the image size to at least 129 GB

    • Select the newly created virtual machine and click the yellow Settings icon

    • Select Network and enable Adapter 2 attached to Host-only Adapter

    • Set Adapter Type to Paravirtualized Network (virtio-net) for both Adapter 1 and Adapter 2

    • Select System and select only Optical in the Boot Order list

    • Select Storage and select Empty below the IDE Controller

    • Click the small CD/DVD icon next to the Optical Drive drop-down list and select the location of the mini.iso image

    • Click OK

  • Select the newly created virtual machine and click the green Start icon

  • Press TAB when the Installer boot menu appears

  • Edit the boot parameters at the bottom of the boot screen to make them look like the following:

    linux initrd=initrd.gz url=http://192.168.0.163:8080/bullseye.seed auto=true priority=critical interface=auto
    
  • Press ENTER to start the automatic installation

  • After installation is done, stop the virtual machine

  • Select the newly created virtual machine and click the yellow Settings icon

  • Select System and select only Hard Disk in the Boot Order list

  • Click OK

  • The virtual machine is ready to use (the default password for the root and red-pitaya accounts is changeme)

Configure the VM

  • Set the network device for the new VM to be a bridged adapter by selecting: Settings > Network > Adapter 1 and then selecting Bridged Adapter from the Attached to: drop down list. in the Parallels menu for the new VM.

  • Setup sudo root for user timm on the VM. Using visudo, add the following user privilege specification after the one for root:

    dyadic    ALL=(ALL) NOPASSWD:ALL
  • Setup SSH trust on the VM for the dyadic user. First generate an SSH key on the VM:

    ssh-keygen
    

    Now add the RSA public key for dyadic from the VM host machine to the ~dyadic/.ssh/authorized_keys file on any other client hosts which need to trust the new VM.. Likewise, add the RSA public key for dyadic on <VM host> to the ~dyadic/.ssh/authorized_keys file on the new VM.

  • Add the dyadic user to the dialout group:

    usermod -a -G dialout dyadic
    

Install Virtualbox guest additions

  • Ensure that no optical drives are currently mounted. Do this by first selecting the guest VM window and then going to Devices -> Optical Drives and unselecting any selected drives/images.

  • From the virtual machine menu, select Devices -> Insert Guest Additions CD Image

  • In a guest VM terminal execute:

    sudo mkdir -p /mnt/cdrom
    sudo mount /dev/cdrom /mnt/cdrom
    
  • Execute the VBoxLinuxAdditions.run script to install the Guest Additions:

    cd /mnt/cdrom
    sudo sh ./VBoxLinuxAdditions.run --nox11
    
  • Reboot the guest VM for the changes to take effecct.

Install pyenv

curl https://pyenv.run | bash

Note the following and make the appropriate changes to .profile and .bashrc:

# (The below instructions are intended for common
# shell setups. See the README for more guidance
# if they don't apply and/or don't work for you.)

# Add pyenv executable to PATH and
# enable shims by adding the following
# to ~/.profile:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

# If your ~/.profile sources ~/.bashrc,
# the lines need to be inserted before the part
# that does that. See the README for another option.

# If you have ~/.bash_profile, make sure that it
# also executes the above lines -- e.g. by
# copying them there or by sourcing ~/.profile

# Load pyenv into the shell by adding
# the following to ~/.bashrc:

eval "$(pyenv init -)"

# Make sure to restart your entire logon session
# for changes to profile files to take effect.

# Load pyenv-virtualenv automatically by adding
# the following to ~/.bashrc:

eval "$(pyenv virtualenv-init -)"

Now restart the shell either by logging out and logging back in again or by doing the following:

exec "$SHELL"

Set up the rfblocks virtual environment

Install Python 3:

sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
  libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \
  libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl
pyenv install -v 3.8.5

Create and activate the virtual environment:

pyenv virtualenv 3.8.5 rfblocks
pyenv activate rfblocks
pip install --upgrade pip

Now install the rfblocks requirements:

pip install pyserial
pip install rpyc
pip install qasync
pip install PyQt5
pip install pyqtgraph
pip install scipy

Installing the Xilinx Vitis Core Development Kit

  • Download “AMD Unified Installer for FPGAs & Adaptive SoCs 2023.1 SFD” from the Xilinx download page (the file name is Xilinx_Unified_2023.1_0507_1903.tar.gz)

  • Create the /opt/Xilinx directory, unpack the installer and run it.

    mkdir /opt/Xilinx
    cd /opt/Xilinx
    (ssh maxwell "cd ~/Downloads; gzip -dc Xilinx_Unified_2023.1_0507_1903.tar.gz") | tar tvf -
    cd Xilinx_Unified_2023.1_0507_1903/
    
  • Ensure the right packages are installed:

    sudo apt-get --no-install-recommends install bc binfmt-support bison build-essential ca-certificates curl debootstrap device-tree-compiler dosfstools flex fontconfig git libgtk-3-0 libncurses-dev libssl-dev libtinfo5 parted qemu-user-static squashfs-tools sudo u-boot-tools x11-utils xvfb zerofree zip
    
  • The installation is run in batch mode. This entails executing a couple of commands before running the install. The following command creates an authentication token and will prompt for a Xilinx account user name (e-mail address) and password:

    ./xsetup -b AuthTokenGen
    

    The next command will create a configuration file to guide the installation and will prompt for the product to install - this should be Vitis:

    ./xsetup -b ConfigGen
    

    Take note of where the configuration file is created.

    Finally, run the install:

    export LD_LIBRARY_PATH=/lib/x86_64-linux-gnu:/opt/Xilinx/Vivado/2023.1/lib/lnx64.o:/opt/Xilinx/Vitis/2023.1/lib/lnx64.o
    ./xsetup --batch Install --agree XilinxEULA,3rdPartyEULA --location /opt/Xilinx --config /home/timm/.Xilinx/install_config.txt
    

    Note that (at least for Debian Bullseye) the LD_LIBRARY_PATH needs to be explicitly set otherwise the installer will hang towards the end of the installation process. Also note that the --location should be set to the location of the generated configuration file as reported by the previous ConfigGen command.

Red Pitaya Netboot

The following procedure should be followed in order to setup the infrastructure to allow Red Pitaya boards to be booted over the network.

  • TFTP installation on the Red Pitaya development host:

    sudo apt-get install tftpd-hpa
    mkdir /var/lib/tftp
    chown -R dyadic:dyadic /var/lib/tftp
    
  • The TFTP server is run as a daemon (the alternative is to run it as an inetd service). The default configuration file (/etc/default/tftpd-hpa) just needs some tweaks:

    TFTP_USERNAME="tftp"
    TFTP_DIRECTORY="/var/lib/tftp"
    TFTP_ADDRESS="0.0.0.0:69"
    TFTP_OPTIONS="--secure --ipv4"
    

    ipv6 is turned off in /etc/sysctl.conf:

    net.ipv6.conf.all.disable_ipv6 = 1
    net.ipv6.conf.default.disable_ipv6 = 1
    net.ipv6.conf.lo.disable_ipv6 = 1
    

    and then running::

    $ sudo sysctl -p
    

    The TFTP server is (re)started::

    sudo service tftpd-hpa start
    ...
    sudo service tftpd-hpa status
      tftpd-hpa.service - LSB: HPA's tftp server
         Loaded: loaded (/etc/init.d/tftpd-hpa)
       ...
       CGroup: /system.slice/tftpd-hpa.service
               +-1082 /usr/sbin/in.tftpd --listen --user tftp --address 0.0.0.0:69 --secure --ipv4 /var/lib/tftp
    

    The server must serve up the kernel image and device tree, which are put in the TFTP_DIRECTORY defined in the config file above:

    cd /var/lib/tftp
    cp $HOME/Source/red-pitaya-notes/uImage .
    cp $HOME/Source/red-pitaya-notes/devicetree.dtb .
    

Building a RedPitaya SD Card Image

The assumption is that Pavel Demin's Red Pitaya build tools and associated Zynq cores and projects have been cloned onto the Red Pitaya development VM:

git clone https://github.com/pavel-demin/red-pitaya-notes.git

Before building the SD cardimage the Linux kernel to be run on the Red Pitaya board must have been built.

Building the kernel and modules

This is carried out on the RedPitaya development host. (See the previous section for details on building this.)

This is a straightforward task using Pavel Demin's build tools:

cd ~/Source/red-pitaya-notes
make NAME=led_blinker

(In this case the led_blinker project is used but it can be any of the projects under the red-pitaya-notes/projects directory.) As part of the build the Linux kernel source will be downloaded, configured and built with the products: uImage, boot.bin, and devicetree.dtb placed in the red-pitaya-notes directory.

For the Red Pitaya SDR card use the following:

cd ~/Source/red-pitaya-notes
make NAME=adc_dac_dma_122_88 PART=xc7z020clg400-1

After completing the initial build process, the Xilinx Linux kernel source and U-Boot source will have been downloaded and built under the red-pitaya-notes/tmp/linux-6.1 and red-pitaya-notes/tmp/u-boot-2021.04 directories respectively.

The kernel binary will be available as red-pitaya-notes/uImage, the device tree binary as red-pitaya-notes/devicetree.dtb, the uBoot bootloader as red-pitaya-notes=/boot.bin and the FPGA bitstream will be available as red-pitaya-notes/tmp/adc_dac_dma_122_88.bit.

Building the SD card image

The SD card image is now built as follows:

cd ~/Source/red-pitaya-notes
sudo sh scripts/image.sh scripts/debian.sh debian_101123

The build will take some time.

After completion of the build the new image is written to the SD card using:

scp rp-dev2:~/Source/red-pitaya-notes/debian_150821 ~/Downloads
diskutil list
...
diskutil unmountDisk /dev/disk2
sudo dd bs=4m if=./debian_150821 of=/dev/disk2

(Note that the above commands are for MacOS.)

fdisk -l
  ...
  Disk /dev/sdb: 7.42 GiB, 7969177600 bytes, 15564800 sectors
  Disk model: STORAGE DEVICE
  Units: sectors of 1 * 512 = 512 bytes
  Sector size (logical/physical): 512 bytes / 512 bytes
  I/O size (minimum/optimal): 512 bytes / 512 bytes
  Disklabel type: dos
  Disk identifier: 0x68e8e856

  Device     Boot Start      End  Sectors Size Id Type
  /dev/sdb1        8192    32767    24576  12M  e W95 FAT16 (LBA)
  /dev/sdb2       32768 14680063 14647296   7G 83 Linux

umount /dev/sdb2
umount /dev/sdb1

dd bs=4096 if=./debian_101123 of=/dev/sdb status=progress

(Note that the above commands are for Linux (Debian))

Remount the SD card on the development host. Copy the FPGA bitstream file to the /boot partition:

cp red-pitaya-notes/tmp/adc_dac_dma_122_88.bit <boot-partition-mount-point>

The uEnv.txt settings must also be updated as follows:

bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk cma=132M uio_pdrv_genirq.of_id=generic-uio rootwait
kernel_addr=0x2080000
devicetree_addr=0x2000000
bitstream_addr=0x4000000
kernel_image=uImage
devicetree_image=devicetree.dtb
bitstream_image=fpga.bit
bootcmd=fatload mmc 0 ${bitstream_addr} ${bitstream_image}; fpga loadb 0 ${bitstream_addr} ${filesize}; fatload mmc 0 ${kernel_addr} ${kernel_image}; fatload mmc 0 ${devicetree_addr} ${devicetree_image}; bootm ${kernel_addr} - ${devicetree_addr}

The contents of the /boot partition are as follows:

ls /boot
boot.bin    devicetree.dtb  fpga.bit        uEnv.txt        uImage

The SD card can now be inserted into the Red Pitaya board and the board powered up. The boot sequence should start with something resembling the following:

U-Boot 2021.04 (Nov 12 2023 - 14:09:09 +1100)

CPU:   Zynq 7z020
Silicon: v3.1
Model: Red Pitaya Board
DRAM:  ECC disabled 512 MiB
MMC:   mmc@e0100000: 0
Loading Environment from EEPROM... OK
In:    serial@e0000000
Out:   serial@e0000000
Err:   serial@e0000000
Net:
ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 1, interface rgmii-id
eth0: ethernet@e000b000
Hit any key to stop autoboot:  0
Importing environment from SD...
Device: mmc@e0100000
Manufacturer ID: ad
OEM: 4c53
Name: USD00
Bus Speed: 25000000
Mode: MMC legacy
Rd Block Len: 512
SD version 1.0
High Capacity: Yes
Capacity: 14.7 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
593 bytes read in 9 ms (63.5 KiB/s)
2710528 bytes read in 240 ms (10.8 MiB/s)
  design filename = "system_wrapper;COMPRESS=TRUE;UserID=0XFFFFFFFF;Version=2023.1"
  part number = "7z020clg400"
  date = "2023/11/11"
  time = "19:27:01"
  bytes in bitstream = 2710404
zynq_align_dma_buffer: Align buffer at 400007c to 4000040(swap 1)
INFO:post config was not run, please run manually if needed
5617104 bytes read in 482 ms (11.1 MiB/s)
15461 bytes read in 15 ms (1005.9 KiB/s)
## Booting kernel from Legacy Image at 02080000 ...
   Image Name:   Linux-6.1.55-xilinx
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    5617040 Bytes = 5.4 MiB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 02000000
   Booting using the fdt blob at 0x2000000
   Loading Kernel Image
   Loading Device Tree to 1eb73000, end 1eb79c64 ... OK

Starting kernel ...

Booting Linux on physical CPU 0x0
Linux version 6.1.55-xilinx (timm@turing) (arm-xilinx-linux-gnueabi-gcc.real (GCC) 12.2.0, GNU ld (GNU Binutils) 2.39.0.20220819) #1 SMP PREEMPT Wed Nov  1 14:12:49 AEDT 2023
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
OF: fdt: Machine model: xlnx,zynq-7000
Memory policy: Data cache writealloc
cma: Reserved 36 MiB at 0x1c400000
...

Initmem setup node 0 [mem 0x0000000000000000-0x000000001fffffff]
percpu: Embedded 12 pages/cpu s19028 r8192 d21932 u49152
Built 1 zonelists, mobility grouping on.  Total pages: 130048
Kernel command line: console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk uio_pdrv_genirq.of_id=generic-uio rootwait cma=36M
...

Configuring the RedPitaya Board Environment

Log into the Red Pitaya as root either using the serial console (115200, 8 bits, No parity, 1 stop bit) or via either of the network interfaces. The default root password is changeme.

Add required packages

apt install git sudo

Disable services which aren't required

Only the ethernet network interface is used. In addition, we don't require the dhcp daemon to run.

systemctl stop wpa_supplicant.service
systemctl disable wpa_supplicant.service
systemctl stop hostapd.service
systemctl disable hostapd.service
systemctl stop isc-dhcp-server.service
systemctl disable isc-dhcp-server.service

Create a normal user account

adduser dyadic
...
usermod -aG sudo dyadic

Optionally, allow the dyadic user to sudo commands without requiring a password. This is done by adding the following line to the sudoers file using visudo:

dyadic  ALL=(ALL) NOPASSWD:ALL

Set up SSH trusts with any other hosts which may be used to access the board. At a minimum this should probably include the RedPitaya development host. This is a good time to copy over any keys required in order to access git repos.

su - dyadic
ssh-keygen
...
echo <SSH RSA public key> >~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

As root, add the dyadic user to the dialout group:

usermod -a -G dialout dyadic

Install pyenv

curl https://pyenv.run | bash

Note the following and make the appropriate changes to .profile and .bashrc:

# (The below instructions are intended for common
# shell setups. See the README for more guidance
# if they don't apply and/or don't work for you.)

# Add pyenv executable to PATH and
# enable shims by adding the following
# to ~/.profile:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"

# If your ~/.profile sources ~/.bashrc,
# the lines need to be inserted before the part
# that does that. See the README for another option.

# If you have ~/.bash_profile, make sure that it
# also executes the above lines -- e.g. by
# copying them there or by sourcing ~/.profile

# Load pyenv into the shell by adding
# the following to ~/.bashrc:

eval "$(pyenv init -)"

# Make sure to restart your entire logon session
# for changes to profile files to take effect.

# Load pyenv-virtualenv automatically by adding
# the following to ~/.bashrc:

eval "$(pyenv virtualenv-init -)"

Now restart the shell either by logging out and logging back in again or by doing the following:

exec "$SHELL"

Set up the rpboard virtual environment

Install Python 3:

sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
  libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \
  libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python3-openssl \
  libopenblas-dev
pyenv install -v 3.9.7

Create and activate the virtual environment:

pyenv virtualenv 3.9.7 rpboard
pyenv activate rpboard
pip install --upgrade pip

Include https://www.piwheels.org/ in the pip configuration:

sudo cat >/etc/pip.conf <<EOF
[global]
extra-index-url=https://www.piwheels.org/simple
EOF

Install required libraries for scipy:

sudo apt-get install libatlas-base-dev

Now install the rpboard requirements:

cat >requirements.txt <<EOF
aioserial==1.3.1
cffi==1.16.0
Cython==3.0.10
numpy==1.26.4
plumbum==1.8.2
pycparser==2.22
PyQt5-sip==12.13.0
pyserial==3.5
python-periphery==2.4.1
qasync==0.27.1
rpyc==5.3.1
scipy==1.13.0
> EOF
pip install -r requirements.txt

Install PyQt5 globally.

sudo apt-get install python3-sip-dev
sudo apt-get install python3-pyqt5

Copy PyQt5 python packages to the rpboard virtual environment:

cp -r /usr/lib/python3/dist-packages/PyQt5/* ~/.pyenv/versions/rpboard/lib/python3.9/site-packages/PyQt5

On the Red Pitaya board host clone the DualDacAdc reference design files and copy the required service scripts into place.

sudo chown dyadic:dyadic /opt
mkdir -p ~/Downloads
cd ~/Downloads
git clone https://gitlab.com/dyadic-groups/rfblocks-reference-designs/dualdacadc.git
cd dualdacadc/rpboard/root
cp -r opt/* /opt
sudo cp etc/systemd/system/*.service /etc/systemd/system

Copy the USB udev rule into place:

cd ~/Downloads/cd dualdacadc/rpboard/root
sudo cp etc/udev/rules.d/010_local.rules /etc/udev/rules.d

Create the directory for the AXI DMA kernel module:

mkdir -p /opt/modules/6.1.55-xilinx

On the development host, build the AXI DMA kernel driver. Copy the resulting kernel module into place on the Red Pitaya board host:

cd xilinx-axidma/outputs
scp axidma.ko dyadic@red-pitaya2:/opt/modules/6.1.55-xilinx

Clone the Xilinx axidma repo and build the Python _axidma module.

mkdir ~/Source
cd ~/Source
git clone https://gitlab.com/dyadic/xilinx-axidma.git
pyenv activate rpboard
cd xilinx-axidma/python
python axidma_extension_build.py
cp _axidma.cpython-39-arm-linux-gnueabihf.so ~/.pyenv/versions/rpboard/lib/python3.9/site-packages

Note that it may be necessary to build cffi from source because of libffi version issues. This can be done using the following:

pip uninstall cffi
pip install --no-binary cffi cffi

Configure systemd with the new services:

sudo systemctl daemon-reload

The serial bridge bridge_start and adcdma_start scripts should be edited to use the IP address of the board host. The services are then enabled:

sudo systemctl enable rp_dev_init.service
sudo systemctl enable rp_bridge.service
sudo systemctl enable rpyc_registry.service
sudo systemctl enable rp_adcdma.service

Now ensure that the correct versions of the kernel, device tree and fpga bit stream are in place using the directions documented in Updating the SD Card with kernel image, devicetree and/or FPGA bitstream and reboot the board.

Set up Netboot for the Xilinx 2020.1 U-Boot

The SD card has a U-boot environment settings file in the boot partition (uEnv.txt) which, by default, contains the following:

kernel_image=uImage
devicetree_image=devicetree.dtb
kernel_load_address=0x2080000
devicetree_load_address=0x2000000
bootcmd=fatload mmc 0 ${kernel_load_address} ${kernel_image} && fatload mmc 0 ${devicetree_load_address} ${devicetree_image} && bootm ${kernel_load_address} - ${devicetree_load_address}
bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk rootwait

This guides U-boot to load the Linux kernel and device tree from the SD card and then passes bootargs as the kernel boot parameters.

Logically, U-Boot needs to know 2 things to boot: what files to download over TFTP, and where in memory to put them. In order to successfully boot we'll need the kernel image and the device tree image. These should be loaded at the addresses 0x2080000 and 0x2000000 respectively. (These addresses are derived from the 'uEnv.txt' file used in the original SD card boot image.) The following code stanza shows the U-boot commands required in order to load kernel image, device tree, and bitstream from the TFTP server and boot the board using these:

setenv ipaddr 192.168.0.56
setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk rootwait
setenv serverip 192.168.0.87
setenv kernel_addr 0x2080000
setenv devicetree_addr 0x2000000
setenv bitstream_addr 0x4000000
setenv bitstream_image led_blinker.bit
tftpboot ${kernel_addr} uImage
tftpboot ${devicetree_addr} devicetree.dtb
tftpboot ${bitstream_addr} ${bitstream_image}
fpga loadb 0 ${bitstream_addr} ${filesize}
bootm ${kernel_addr} - ${devicetree_addr}

The above are formalized in a U-boot boot script by first creating a text file (boot-rp.txt) with the required commands:

setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk uio_pdrv_genirq.of_id=generic-uio rootwait
setenv serverip 192.168.0.87
setenv kernel_addr 0x2080000
setenv devicetree_addr 0x2000000
setenv bitstream_addr 0x4000000
setenv bitstream_image fpga.bit
setenv kernel_tftp 'tftpboot ${kernel_addr} uImage'
setenv devicetree_tftp 'tftpboot ${devicetree_addr} devicetree.dtb'
setenv bitstream_tftp 'tftpboot ${bitstream_addr} ${bitstream_image}'
setenv bitstream_load 'fpga loadb 0 ${bitstream_addr} ${filesize}'
setenv boot_now 'bootm ${kernel_addr} - ${devicetree_addr}'
run bitstream_tftp bitstream_load kernel_tftp devicetree_tftp boot_now

For the rp-dev3/red-pitaya2 combination the boot script commands will be:

setenv bootargs console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk uio_pdrv_genirq.of_id=generic-uio rootwait
setenv serverip 192.168.0.39
setenv kernel_addr 0x2080000
setenv devicetree_addr 0x2000000
setenv bitstream_addr 0x4000000
setenv bitstream_image fpga.bit
setenv kernel_tftp 'tftpboot ${kernel_addr} uImage'
setenv devicetree_tftp 'tftpboot ${devicetree_addr} devicetree.dtb'
setenv bitstream_tftp 'tftpboot ${bitstream_addr} ${bitstream_image}'
setenv bitstream_load 'fpga loadb 0 ${bitstream_addr} ${filesize}'
setenv boot_now 'bootm ${kernel_addr} - ${devicetree_addr}'
run bitstream_tftp bitstream_load kernel_tftp devicetree_tftp boot_now

Note that the uio_pdrv_genirq.of_id=generic-uio is required in bootargs to enable the generic-uio driver as explained in this Github posting. By default the kernel will configure 16MB of CMA at 0x1f000000. If more is required then the appropriate addition must be made to the bootargs (for example: cma=32M to increase the CMA size to 32MB).

The text file is then converted to a U-boot boot script image using the following command:

sudo mkimage -A arm -O u-boot -T script -C none -a 0 -e 0 -n "RP Boot Script" -d boot-rp.txt /var/lib/tftp/boot-rp.scr

Note that the boot script image is written directly to the TFTP server directory.

Now, whenever the red pitaya board is reboot, the U-boot prompt must be accessed (by interrupting the boot process via the serial console) and the following U-boot commands entered:

# For rp-dev2/red-pitaya:
setenv ipaddr 192.168.0.56
setenv serverip 192.168.0.87
setenv bootscr_addr 0x100000
setenv bootscr_boot 'tftpboot ${bootscr_addr} boot-rp.scr ; source ${bootscr_addr}'
setenv sdboot 'run bootscr_boot'
saveenv
boot

For the rp-dev2/red-pitaya2 use the following commands:

# For rp-dev2/red-pitaya2:
setenv ipaddr 192.168.0.155
setenv serverip 192.168.0.87
setenv bootscr_addr 0x100000
setenv bootscr_boot 'tftpboot ${bootscr_addr} boot-rp.scr ; source ${bootscr_addr}'
setenv sdboot 'run bootscr_boot'
saveenv
boot

This has the effect of downloading the U-boot script from the TFTP server and executing it's contents.

The setup described above now allows changes to kernel, kernel device tree and FPGA bitstream to be loaded onto the Red Pitaya board with a minimum of manual intervention. This saves wear and tear on the SD card slot and also the serial console and power connectors on the board.

Updating kernel image, devicetree and/or FPGA bitstream

With the above infrastructure in place updates to any of the kernel image, devicetree or FPGA bitstream is done by copying the updated files into place in the TFTP server file staging area (/var/lib/tftp) and making any required changes to symlinks in that directory.

For example, suppose that the current contents of the TFTP staging area is as follows:

timm@rp-dev2:/var/lib/tftp$ ls -l
total 5032
-rw-r--r-- 1 root root     713 Aug 17 07:16 boot-rp.scr
lrwxrwxrwx 1 timm timm      13 Aug 22 00:57 devicetree.dtb -> dma_test4.dtb
-rw-r--r-- 1 timm timm 4357760 Aug 17 10:12 dma_test4
-rw-r--r-- 1 timm timm  773364 Aug 17 11:55 dma_test4.bit
-rw-r--r-- 1 timm timm   13114 Aug 17 07:12 dma_test4.dtb
lrwxrwxrwx 1 timm timm      13 Aug 17 07:14 fpga.bit -> dma_test4.bit
lrwxrwxrwx 1 timm timm       9 Aug 22 00:58 uImage -> dma_test4

Kernel image, devicetree and FPGA bitstream files for another design are copied over to the TFTP staging area:

rp-dev2:/var/lib/tftp$ cp ~/Source/red-pitaya-notes/uImage sts_test
rp-dev2:/var/lib/tftp$ cp ~/Source/red-pitaya-notes/devicetree.dtb sts_test.dtb
rp-dev2:/var/lib/tftp$ cp ~/Source/red-pitaya-notes/tmp/sts_test.bit .

and the symlinks are updated to point to the new files:

rp-dev2:/var/lib/tftp$ rm devicetree.dtb
rp-dev2:/var/lib/tftp$ ln -s sts_test.dtb devicetree.dtb
rp-dev2:/var/lib/tftp$ rm fpga.bit
rp-dev2:/var/lib/tftp$ ln -s sts_test.bit fpga.bit
rp-dev2:/var/lib/tftp$ rm uImage
rp-dev2:/var/lib/tftp$ ln -s sts_test uImage
rp-dev2:/var/lib/tftp$ ls -l
total 9924
-rw-r--r-- 1 root root     713 Aug 17 07:16 boot-rp.scr
lrwxrwxrwx 1 timm timm      12 Aug 22 01:07 devicetree.dtb -> sts_test.dtb
-rw-r--r-- 1 timm timm 4357760 Aug 17 10:12 dma_test4
-rw-r--r-- 1 timm timm  773364 Aug 17 11:55 dma_test4.bit
-rw-r--r-- 1 timm timm   13114 Aug 17 07:12 dma_test4.dtb
lrwxrwxrwx 1 timm timm      12 Aug 22 01:07 fpga.bit -> sts_test.bit
-rw-r--r-- 1 timm timm 4367352 Aug 22 01:04 sts_test
-rw-r--r-- 1 timm timm  622528 Aug 22 01:04 sts_test.bit
-rw-r--r-- 1 timm timm   12597 Aug 22 01:04 sts_test.dtb
lrwxrwxrwx 1 timm timm       8 Aug 22 01:07 uImage -> sts_test

The board may now to booted to the U-boot prompt and the commands listed above in the tftp-boot script executed in order to run the new design.

Updating the SD Card with kernel image, devicetree and/or FPGA bitstream

It is usually worthwhile to update the SD card with recent versions of the kernel, devicetree and FPGA bitstream at significant milestones during development. This is easily done by making use of the uEnv.txt settings shown below and ensuring that the required image file versions are copied into place in the /boot partition of the SD card.

bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 ro rootfstype=ext4 earlyprintk cma=132M uio_pdrv_genirq.of_id=generic-uio rootwait
kernel_addr=0x2080000
devicetree_addr=0x2000000
bitstream_addr=0x4000000
kernel_image=uImage
devicetree_image=devicetree.dtb
bitstream_image=fpga.bit
bootcmd=fatload mmc 0 ${bitstream_addr} ${bitstream_image}; fpga loadb 0 ${bitstream_addr} ${filesize}; fatload mmc 0 ${kernel_addr} ${kernel_image}; fatload mmc 0 ${devicetree_addr} ${devicetree_image}; bootm ${kernel_addr} - ${devicetree_addr}

The contents of the /boot partition are as follows:

ls /boot
boot.bin    devicetree.dtb  fpga.bit        uEnv.txt        uImage

Scripts