Sending PL overlays from Ubuntu in the KR260
PetaLinux is probably the go-to OS when working with Zynq devices. It makes life easy because it is built for these chips and comes with plenty of pre-configured Yocto layers that take care of most of the setup for you. But here is the catch: AMD itself has said that PetaLinux is not meant to be a production OS — it is really designed for prototyping and testing.
Ubuntu is also available, though only for some development kits — including all the Kria boards. In this article we will take a look at how, even running Ubuntu, you can configure and control the PL on a KR260 kit in a pretty straightforward way.
Table of Contents
- Connecting to the KR260 via SSH
- Checking xmutil
- Installing fpga-manager
- Checking available UIO devices
- Generating the Device Tree overlay
- Sending the bitstream and DTS to the board
- Generating the Device Tree Overlay
- Loading the PL and applying the overlay
- Verifying the new UIO device
- Running the Python driver
- Conclusion
Connecting to the KR260 via SSH
First, we need to get ready the KR260 kit. We need to download the Ubuntu 24.04 image for Kria kits from the Ubuntu webpage. Then, using ‘dd’ if you are on Linux, or an application like Balena Etcher if you are running Linux or Windows, you will need to generate the SD card needed for the Ubuntu booting on Kria.
Once your Ubuntu distribution has booted, from your host you can check if the SSH connection is ready. This is important because we will need a way to send files to the KR260 kit, and the scp
command, based on SSH protocol, is the best way to do this.
ubuntu@host:~$ ssh [email protected]
When the communication is ready, we can start with some comprobations.
Checking xmutil
The Ubuntu image for KR260 already includes xmutil. You can confirm by running:
ubuntu@kria:~$ sudo xmutil --help
xmutil
makes it easy to install acceleration applications, since it works with .xclbin
files that contain both the FPGA bitstream and the device tree overlay.
By default, some example applications are already available:
ubuntu@kria:~$ sudo xmutil listapps
However, it is very focused on acceleration applications, like the ones we will generate using Vitis AI, or Vitis HLS. In this case, we have our .bin
file, and our driver, so there we are not going to follow the acceleration flow described by AMD, so fpga-manager
will be a better option in this case.
Installing fpga-manager
FPGA manager is not installed by default in the Ubuntu image, but it can be added easily from the official Ubuntu repository installing the package fpga-manager-xlnx. First, update the package index and then install:
ubuntu@kria:~$ sudo apt update
ubuntu@kria:~$ sudo apt install fpga-manager-xlnx
Now, we can check that the command fpgautil
is available.
ubuntu@kria:~$ fpgautil --help
Checking available UIO devices
Now, we are going to execute a sanity check. The peripheral we are going to add to the PL will be registered from Ubuntu as a peripheral without a driver, so the addresses of the peripheral will be accesed by the userspace. This will be very important because, in general, Ubuntu does not allow to access directly to memory addresses, so we need to add in the Device Tree a userspace I/O peripheral.
Initially, Ubuntu already have some UIO peripherals, and we can find them in the /dev
folder.
ubuntu@kria:~$ ls -l /dev/uio*
crw------- 1 root root 237, 0 Feb 21 21:18 /dev/uio0
crw------- 1 root root 237, 1 Feb 21 21:18 /dev/uio1
crw------- 1 root root 237, 2 Feb 21 21:18 /dev/uio2
crw------- 1 root root 237, 3 Feb 21 21:18 /dev/uio3
In this case we already have 4 UIO perpherals. When we add a new UIO peripheral, it must appear here.
Generating the Device Tree overlay
We already mentioned that our PL peripheral will be registered by Ubuntu as a Userspace I/O one. To make Ubuntu recognise that set of addresses as the ones that manage the peripheral, we need to add to the device tree a new node. In a Petalinux build, we will add it to the system-conf.dtsi
. However, here we already have a LInux distribtion built and running, so we can’t modify the device tree as usual. In this case we need to apply an overlay.
A Device Tree overlay is a fragment of the Device Tree that can be applied dinamically over the (original) Device Tree. It a way of “installing” new peripherals in the Linux distribution.
In this overlay, we need to especify the type of peripheral we are going to add, and according this type, we will need to add some other fields. For example, in out case we are going to add a generic-uio
peripheral, so we need to add also the address range in which it will be installed, and the initial status of the peripheral.
If your peripheral is not a generic-uio
, you can check the different bindings you can add, and the structure you need to follow to add your peripheral type.
Since the overlays have a very specific structure, with some key words at the beginninf, I just ask ChatGPT to generate a device tree overlay for a generic-uio device, with the corresponding address range.
/dts-v1/;
/plugin/;
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target-path = "/axi";
__overlay__ {
axi_pwm_wrapper: axi_pwm_wrapper_0@a0000000 {
compatible = "generic-uio";
reg = <0x0 0xA0000000 0x0 0x0001000>; // 64 KB
status = "okay";
};
};
};
};
At this point, we have the overlay, but it is not compiled yet,we just have the font code of the overlay.
Sending the bitstream and DTS to the board
Your Vivado design flow will generate a .bin
bitstream , and the .dts
file (device tree source) is the one generated before. Now, from the host machine, we transfer them to the KR260:
pablo@host:~$ cd your-bin-and-dts-folder
pablo@host:~$ scp ./* [email protected]:.
Also transfer the Python script that will control the IP:
pablo@host:~$ cd ../python
pablo@host:~$ scp ./* [email protected]:.
On the KR260, confirm the files are there:
ubuntu@kria:~$ ls
axi_pwm.dts axi_pwm_driver.py krind_lab02_bd_wrapper.bin
Generating the Device Tree Overlay
Now it’s time to compile the .dts
into a .dtbo
overlay. Ubuntu for Kria already include the dtc
application. This application will compile the dts
file, the source file of the device tree overlay, into a compiled device tree overlay (dtc
).
The structure of the dtc
command will be shown by executing the command without arguments. In general, the command with the corresponding arguments will be the one you can find here.
ubuntu@kria:~$ dtc -@ -I dts -O dtb -o axi_pwm.dtbo axi_pwm.dts
Now, we alread have the overlay ready to be installed into Ubuntu.
Loading the PL and applying the overlay
The next, is to load the design of the PL, and load the device tree overlay.
The fpgautil
application allows to load the PL and the device tree overlay in the same line, however I ran into several issues when I try to do it. My recommendation is to execute two different commands, the first one to load the PL, and another one to load the device tree overlay.
To load your bitstream, you can execute the next command.
ubuntu@kria:~$ sudo fpgautil -b ./krind_lab02_bd_wrapper.bin -f Full
When you load the PL of the KR260, the board’s fan will spin at maximum speed — this is expected, since the default Ubuntu design includes fan control logic.
Then, we can apply the overlay:
ubuntu@kria:~$ sudo fpgautil -o axi_pwm.dtbo
At this point, we have our peripheral and driver ready to be used.
Verifying the new UIO device
Since the peripheral is a generic-uio
type, it will be added to the UIO devices of Ubuntu. We can check it by listing again the UIO devices.
ubuntu@kria:~$ ls -l /dev/uio*
crw------- 1 root root 237, 0 Feb 21 21:18 /dev/uio0
crw------- 1 root root 237, 1 Feb 21 21:18 /dev/uio1
crw------- 1 root root 237, 2 Feb 21 21:18 /dev/uio2
crw------- 1 root root 237, 3 Feb 21 21:18 /dev/uio3
crw------- 1 root root 237, 4 Feb 21 21:18 /dev/uio4
We can see that a new /dev/uio4
has been added. We can check also whether it is our device or not by checking the address of this new UIO.
ubuntu@kria:~$ cat /sys/class/uio/uio4/maps/map0/addr
0x00000000a0000000
Now we can confirm that the new UIO added is located in the address of our device. Also we can check the size of the recerved memory by readint the size
of this new device.
ubuntu@kria:~$ cat /sys/class/uio/uio4/maps/map0/size
0x0000000000001000
Running the Python driver
Finally, you can interact with your custom IP from user space using your driver written either using Python or C.
ubuntu@kria:~$ sudo python3 ./axi_pwm_driver.py 10000 50
This will write to the memory-mapped registers of your IP through the UIO interface, controlling the peripheral directly from Linux.
Conclusion
From my perspective Ubuntu is not the best OS for a Kria SOM - it is too close. While reconfiguring the PL, fairly straighforward, if you want to lod the RPU using remoteproc, the thigs get a bit more complicated. The reason is that, by default, the RPU is not recognized by the kernel, so you would need to modify it in order to make the RPU accesible.
If you want to keep all the control over your Kria SOM, the best option is build your own Linux, either petalinux, or a custom distribution using Yocto. However, the example presented in this post shows how, even using a regular Linux distribution, we can integrate hardware accelerators in a very simple way.