FPGA meets DevOps - System, FPGA, and PetaLinux versioning
In the previous blog post we created a system that automatically builds the FPGA bitstream and Linux image.
Let’s imagine a bug has been found after a bitstream or Linux image has been released. The questions we need to answer to fix the problem are:
- What is the version with the bug?
- What is the source code that was used to build that particular version?
By the end of this blog post we will be able to answer those questions for FPGA bitstream and Linux image, but also to identify a particular board i.e. for RMA.
Video
You can find this blog post in video format on YouTube (embedded below).
FPGA versioning
Now that we have Gitlab building the FPGA bitstream, we can store the version and build number inside the FPGA as a register readable from a microprocessor. The version has format major.minor.buildnumber. Major and minor are assigned by the designer while the buildnumber is the git commit hash used to build the bitstream. When the Gitlab pipeline is running, the git hash is exported as environment variable.
I have created a simple system version IP core for Vivado where major and minor version numbers can be configured from the block design user interface and the build number is the git hash. The complete source code is available on github.
Clone the ip repository inside the FPGA directory
git clone https://www.github.com/starwaredesign/ip_repo.git
Once you have cloned the repo, add the directory to the IP repository for the project: Project Manager -> settings -> IP.
Add the system version IP core to the design used in the previous videos. Set the major and minor version.
The system version IP core has inputs for board type and revision.
For example the same bitstream can be used on different boards, but the software might expose different features based on the board type. Similarly the software might need to run on different board revisions. This way you can have a single FPGA bitstream or firmware that supports multiple products or product versions.
In this example we’re going to wire board type and revision to the Zedboard dip switches.
Let’s add a constraints file with the following content.
set_property -dict {PACKAGE_PIN F22 IOSTANDARD LVCMOS25} [get_ports { board_rev[0] }]
set_property -dict {PACKAGE_PIN G22 IOSTANDARD LVCMOS25} [get_ports { board_rev[1] }]
set_property -dict {PACKAGE_PIN H22 IOSTANDARD LVCMOS25} [get_ports { board_rev[2] }]
set_property -dict {PACKAGE_PIN F21 IOSTANDARD LVCMOS25} [get_ports { board_rev[3] }]
set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS25} [get_ports { board_type[0]}]
set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS25} [get_ports { board_type[1]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS25} [get_ports { board_type[2]}]
set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS25} [get_ports { board_type[3]}]
The build_bitstream.tcl script sets the build number in the system version IP core.
Let’s update the script to recreate the project. From the Vivado TCL shell:
pwd
rm scripts/recreate_prj.tcl
source scripts/create_project_tcl.tcl
Add the constraints to the repo
git add constraints
and add the IP repository as git submodule
git submodule add https://www.github.com/starwaredesign/ip_repo.git ip_repo
And commit the changes
git commit -am “Add system version to the FPGA design.”
Now to answer the question “what is the version affected”, we have added the system version IP core to the design and we’re going to provide a way to read the version from the system itself i.e. printing the version on the console when the system starts. Once the infrastructure is in place, the git hash will be stored inside the FPGA bitstream automatically.
The easiest way to access the system version IP is using a User I/O Linux driver. We can modify the device tree to use the user I/O driver for the system version IP.
Make sure to get the correct memory address from Vivado memory map.
Clone the meta-swd layer repo into the project-spec folder
git clone https://www.github.com/starwaredesign/meta-swd.git project-spec/meta-swd
Add the meta layer to your project with
petalinux-config
in the Yocto settings -> User layers add this
${PROOT}/project-spec/meta-swd
To add the application to the Petalinux project add CONFIG_system-version to user-rootfsconfig and then use:
petalinux-config -c rootfs
We also need to update the device tree with the system version IP configuration.
We’re going to bind the IP to the User I/O driver modifying system-user.dtsi. Replace the file with the following
#include
#include
/include/ "system-conf.dtsi"
/ {
chosen {
bootargs = "console=ttyPS0,115200 earlycon root=/dev/ram0 rw uio_pdrv_genirq.of_id=generic-uio";
stdout-path = "serial0:115200n8";
};
};
&amba_pl {
systemversion: systemversion0@43c00000 {
compatible = "generic-uio";
status = "okay";
reg = <0x43c00000 0x10000>;
};
};
PetaLinux versioning
What can we do for versioning the Petalinux image? Let’s add versioning to the root file system and Linux kernel.
For the root file system we can use the OS release package. Modify user-rootfsconfig (in project-spec/meta-user/conf/) adding
CONFIG_os-release
and add the package to the root filesystem with
petalinux-config -c rootfs
I have modified os release in meta-swd so the version stored in the root filesystem is composed of 4 variables: VERSION_PROJECT_NAME, VERSION_MINOR, VERSION_MAJOR and CI_COMMIT_SHORT_SHA. The first 3 can be set in petalinuxbsp.conf while the last is set automatically by Gitlab CI. The Gitlab CI environment variable has to be explicitly allowed from the external environment into Bitbake’s data store. This is done in the build_image.sh script with
export BB_ENV_PASSTHROUGH_ADDITIONS="$BB_ENV_PASSTHROUGH_ADDITIONS CI_COMMIT_SHORT_SHA"
Set the version variables in petalinuxbsp.conf adding
VERSION_MAJOR = "1"
VERSION_MINOR = "2"
Also add this line
SIGGEN_UNLOCKED_RECIPES += "os-release"
Otherwise the bbappend file in meta-swd will not be used. Make sure you have enabled the meta-swd layer as shown earlier in the video.
For the kernel I have modified the recipe to add VERSION_MAJOR, VERSION_MINOR and the Gitlab CI hash to the extraversion in the Makefile.
Board serial number
What if you need a serial number for your board? On most SoCs there is already a serial number or you can burn one in the SoC itself. Or you can add a silicon serial number to your PCB like this one from Analog devices DS2401.
You just need a single GPIO and the device drivers are available in the Linux kernel. The device is available in different packages. Once you have a serial number on each board, you can use it to track the history of the board i.e. for RMA.
I have designed a DS2401 PMOD module, but you could get the TO-92 version and solder it to a pin header.
Connector JE on the ZedBoard is wired to the MIOs. We need ground, data and a pull-up to 3.3V.
On the Petalinux side, we need to enable the driver for 1-wire core, the GPIO-based 1-wire controller, and the 1-wire memory device with
petalinux-config -c linux-xlnx
We need to add a 1-wire entry in the device tree to specify the GPIO to be used. In project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi add
onewire {
compatible = "w1-gpio";
gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>;
};
Testing
Let’s commit and push changes to the repo so Gitlab CI will build the bitstream and petalinux image. Don’t forget to commit the kernel configuration fragment.
git add project-spec/meta-user/recipes-kernel/linux/linux-xlnx/user_2024-11-15-18-52-00.cfg
And add the meta layer as submodule
git submodule add https://www.github.com/starwaredesign/meta-swd.git project-spec/meta-swd
git commit -am "Add support for 1-wire and system version IP."
git push
Download the artifacts from GitLab and copy them to the SD card.
unzip archive.zip
cp linux/devopsexample/images/linux/* /media/matteo/1D70-745B/
Replace /media/matteo/1D70-745B with the mount point of the SD card on your computer.
Put the sd card back and turn on the board.
Let’s run print-systemconfig and we can see the FPGA version. The major and minor version numbers are set in Vivado, the build number is the git commit hash.
sudo print-systemversion
Given the git hash, it is straightforward to get the source code used to build that particular bitstream or petalinux image.
git show hash
The board version and revision correspond to settings of the dip switches.
sudo print-systemversion
We can check the OS version
sudo cat /etc/os-version
And kernel version
uname -a
We can read the serial number of the silicon ID from sysfs
example1:~$ ls /sys/devices/w1_bus_master1/
01-00001db3c7aa w1_master_attempts w1_master_search
driver w1_master_max_slave_count w1_master_slave_count
power w1_master_name w1_master_slaves
subsystem w1_master_pointer w1_master_timeout
uevent w1_master_pullup w1_master_timeout_us
w1_master_add w1_master_remove
Conclusion
Together with the previous three blog posts, we have Vivado and Petalinux projects under version control, use docker and Gitlab to build automatically the bitstream and petalinux image plus we can track the version of the bitstream, Linux kernel and rootfs once the files are distributed.
Disclaimer
All trademarks, logos, and brand names shown on this video are the property of their respective owners. The use of these trademarks does not imply any affiliation with, or endorsement by, their owners. This video is intended for educational/entertainment/informational purposes only, and no copyright infringement is intended.