
If like me, you’re a newbie to FPGAs, and SoC FPGAs from Xilinx, the complexity of running an application talking to your IP from Linux can be quite daunting. I started by using petalinux from Xilinx to try and use an IP that I made using Vivado HLS (C to HDL). I sort of got it working, but the iteration cycle was too long and I was not making much progress, and I was spending time on issues I didn’t really want to deal with. Petalinux is a little bit opaque, and it also uses Yocto behind the scenes. It is the right choice for many cases, but it may be too complex when you’re just starting off on a project. This blog post is an attempt to consolidate information that is spread across many web pages, and make the whole process easy to understand in a single sitting.
Note: this post assumes basic familiarity with Vivado, and Vivado SDK usage.
Step 1 – Create your Vivado project
Create or open your existing Vivado project, with whatever IP(s) you want in the block diagram. There are a few prerequisites that you do need to follow, to be able to run Linux: you will probably want serial console, so enable one uart on the correct pins, enable at least one TTC (triple timer counter). The board I’m using is MYIR Zturn-lite with the Zynq 7z007s chip. Here is what my block diagram looks like:

Generate your bitstream, and export your hardware description file “.hdf“.
Step 2 – generate device tree for your project
You need to do the following step only once, for this and for the next few steps. We need to clone these three repos:
$ cd /opt/Xilinx/xil-sources $ git clone https://github.com/Xilinx/u-boot-xlnx.git $ git clone https://github.com/Xilinx/linux-xlnx.git $ git clone https://github.com/Xilinx/device-tree-xlnx
For all three repositories, cd into the directory, and do ‘git checkout xilinx-v2018.3‘ revision, that’s the version of Vivado I’m using.
Next, launch Vivado SDK from your Vivado window, in the menu bar, go to Window -> Preferences -> Repositories, and add a local repository. Use the path for the ‘device-tree-xlnx’ directory.

Generating the .dtb file
Go to SDK window’s menu, File -> New -> Board support project. It will open a window for “New Board Support Package”. Earlier, it used to have two options for OS, freertos10_xilinx, and standalone, now it will have a device_tree option also, that’s the one we need right now.

Once you finish creating that, SDK will have created the required device tree files.

Now, the file “system-top.dts” is our main file, but it needs to be passed through a C preprocessor, to include the “.dtsi” dependencies, and then we’ll use dtc, the device-tree compiler to compile our device-tree blob file (.dtb). Make sure you have sourced the SDK’s settings64.sh file so that you have dtc in your path.
$ cd /mnt/shared/video_linux/video_linux.sdk/device_tree_bsp_0 $ cpp -nostdinc -I include -I arch -undef -x assembler-with-cpp system-top.dts system-top.dts.preprocessed $ dtc -I dts -O dtb -i . -o devicetree.dtb system-top.dts.preprocessed
The above command generates the devicetree.dtb file, which will be used later with the Linux kernel.
Step 3 – Compile U-boot
$ cd /opt/Xilinx/xil-sources/u-boot-xlnx $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zynq_zc702_defconfig or $ export ARCH=arm $ export CROSS_COMPILE=arm-linux-gnueabihf- $ make
You can customize u-boot as needed with “make menuconfig,” once you are done, a file named u-boot will be created in the directory, which is an ELF file. We’ll use this to create our BOOT.BIN file (along with FSBL – first stage bootloader).
Step 4 – Compile FSBL – first stage bootloader
We’ll use SDK to create this from Xilinx’s template code. Petalinux also generates this for you automatically.
Using the SDK, create a new Application project, and use “Zynq FSBL template“.


For the above screenshot, I had to go back and in my (already generated) “Standalone” BSP for the project, and enable the “xilffs“, i.e. the FAT file system driver, which is required by the FSBL template. Compiling this project will give you a “.elf” file, “fslbl.elf” for me. This also will be used in the next step to create the “BOOT.BIN” file.
Step 5 – Generate BOOT.BIN
From SDK window’s menu, Xilinx -> Create Boot Image. This will open a window like following image, and we will add our two “.elf” files to it. First the FSBL file, which we’ll mark as the bootloader, and then the u-boot file. FOr clarity, I renamed the “u-boot” file to “u-boot.elf“.

The tool creates a boot.bif file, which is description of partitions in the BOOT.BIN file; and then it generated the BOOT.BIN. If you see the output in the console, you will see:
bootgen -image boot.bif -arch zynq -o \ /home/tavish/vivado/video_linux/video_linux.sdk/BOOT.bin -w on
And here the contents of boot.bif, which we can use to bypass the SDK tool the next time:
//arch = zynq; split = false; format = BIN the_ROM_image: { [bootloader]/home/tavish/vivado/video_linux/video_linux.sdk/fsbl/Debug/fsbl.elf /opt/Xilinx/xil-sources/u-boot-xlnx/u-boot.elf }
If you run the bootgen command from above, it generates the BOOT.BIN file, and we’ll use this from now on instead of the SDK window.
NOTE: in the above example we did not include the bitstream. We can include that also, and if you read the source of the FSBL project, you will see that if the bitstream is present in any partition in the BOOT.BIN file, then it takes care of loading the bitstream into the FPGA.
Tweaking the FSBL
We built the FSBL from the Xilinx template, but it doesn’t print anything right now, and we want to make sure, that it is doing what we think it is doing. To do that, go to the FSBL project properties in the SDK, and add “FSBL_DEBUG_INFO” to the C preprocessor defines section. Now if you regenerate the BOOT.BIN as before, and try to boot, you should see the output from FSBL.
To boot from microsd card, make sure the board is set to boot from SD card, and your SD card has the first partition formatted as FAT (you can make two partitions, the second one larger and formatted ext4, for the filesystem).
Now copy BOOT.BIN to the microsd card, and boot. Here is my console output:
Xilinx First Stage Boot Loader Release 2018.3 Sep 12 2019-14:57:57 Devcfg driver initialized Silicon Version 3.1 Boot mode is SD SD: rc= 0 SD Init Done Flash Base Address: 0xE0100000 Reboot status register: 0x60680000 Multiboot Register: 0x0000C000 Image Start Address: 0x00000000 Partition Header Offset:0x00000C80 Partition Count: 2 Partition Number: 1 Header Dump Image Word Len: 0x0001748A Data Word Len: 0x0001748A Partition Word Len:0x0001748A Load Addr: 0x04000000 Exec Addr: 0x04000000 Partition Start: 0x000065D0 Partition Attr: 0x00000010 Partition Checksum Offset: 0x00000000 Section Count: 0x00000001 Checksum: 0xF7FB3A30 Application Handoff Address: 0x04000000 In FsblHookBeforeHandoff function SUCCESSFUL_HANDOFF FSBL Status = 0x1 U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702 Model: Zynq ZC702 Development Board Board: Xilinx Zynq Silicon: v3.1 I2C: ready DRAM: ECC disabled 1 GiB MMC: sdhci@e0100000: 0 (SD) reading uEnv.txt ... ...
As I mentioned before, if the BOOT.BIN contains a partition with the PL bitstream, it automatically loads it. If we have debug prints turned on, it should show some messages about that also. This time we’ll directly edit the boot.bif file, and run bootgen. Add the path to the bitstream for your project to the boot.bif file, so that it looks like this:
//arch = zynq; split = false; format = BIN the_ROM_image: { [bootloader]/home/tavish/vivado/video_linux/video_linux.sdk/fsbl/Debug/fsbl.elf /home/tavish/vivado/video_linux/video_linux.sdk/top_wrapper_hw_platform_0/top_wrapper.bit /opt/Xilinx/xil-sources/u-boot-xlnx/u-boot.elf }
Again, as before, run the bootgen command to generate the BOOT.BIN file:
bootgen -image boot.bif -arch zynq -o \ /home/tavish/vivado/video_linux/video_linux.sdk/BOOT.bin -w on
If you copy over this file, the boot logs should look like:
Xilinx First Stage Boot Loader Release 2018.3 Sep 12 2019-14:57:57 Devcfg driver initialized Silicon Version 3.1 Boot mode is SD SD: rc= 0 SD Init Done Flash Base Address: 0xE0100000 Reboot status register: 0x60680000 Multiboot Register: 0x0000C000 Image Start Address: 0x00000000 Partition Header Offset:0x00000C80 Partition Count: 3 Partition Number: 1 Header Dump Image Word Len: 0x0007F2E8 Data Word Len: 0x0007F2E8 Partition Word Len:0x0007F2E8 Load Addr: 0x00000000 Exec Addr: 0x00000000 Partition Start: 0x000065D0 Partition Attr: 0x00000020 Partition Checksum Offset: 0x00000000 Section Count: 0x00000001 Checksum: 0xFFE7BF06 Bitstream In FsblHookBeforeBitstreamDload function PCAP:StatusReg = 0x40000A30 PCAP:device ready PCAP:Clear done Level Shifter Value = 0xA Devcfg Status register = 0x40000A30 PCAP:Fabric is Initialized done PCAP register dump: PCAP CTRL 0xF8007000: 0x4C00E07F PCAP LOCK 0xF8007004: 0x0000001A PCAP CONFIG 0xF8007008: 0x00000508 PCAP ISR 0xF800700C: 0x0802000B PCAP IMR 0xF8007010: 0xFFFFFFFF PCAP STATUS 0xF8007014: 0x50000F30 PCAP DMA SRC ADDR 0xF8007018: 0x00100001 PCAP DMA DEST ADDR 0xF800701C: 0xFFFFFFFF PCAP DMA SRC LEN 0xF8007020: 0x0007F2E8 PCAP DMA DEST LEN 0xF8007024: 0x0007F2E8 PCAP ROM SHADOW CTRL 0xF8007028: 0xFFFFFFFF PCAP MBOOT 0xF800702C: 0x0000C000 PCAP SW ID 0xF8007030: 0x00000000 PCAP UNLOCK 0xF8007034: 0x757BDF0D PCAP MCTRL 0xF8007080: 0x30800100 DMA Done ! FPGA Done ! In FsblHookAfterBitstreamDload function Partition Number: 2 Header Dump Image Word Len: 0x0001748A Data Word Len: 0x0001748A Partition Word Len:0x0001748A Load Addr: 0x04000000 Exec Addr: 0x04000000 Partition Start: 0x000858C0 Partition Attr: 0x00000010 Partition Checksum Offset: 0x00000000 Section Count: 0x00000001 Checksum: 0xF7F34730 Application Handoff Address: 0x04000000 In FsblHookBeforeHandoff function SUCCESSFUL_HANDOFF FSBL Status = 0x1 U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702 ...
You can see that the bitstream was loaded this time! I think u-boot and Linux also can load the bitstream, but this is the easiest way that just-works, so we’ll use this.
Step 6 – Build the Linux kernel
cd into the linux-xlnx directory that you cloned earlier. Make sure you have the SDK’s environment file sourced (. settings64.sh). We have the kernel, but we should look for a sane starting config for our board, which is usually a defconfig file.
$ find . -name *defconfig | grep zynq ./arch/arm/configs/xilinx_zynq_defconfig ./arch/arm64/configs/xilinx_zynqmp_defconfig
Now we’ll run:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xilinx_zynq_defconfig # # configuration written to .config #
You can now customize the kernel’s configuration if you want using “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig“.

To compile the kernel, run “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4“. U-boot will expect kernel as a uImage file, which it will load into memory at a particular address and boot it. That address will be 0x8000. If you generate uImage now using “make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage“, it will give you an error that says “Specify LOADADDR on the commandline to build an uImage”. To fix this, run:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- UIMAGE_LOADADDR=0x8000 uImage ... ... Kernel: arch/arm/boot/Image is ready Kernel: arch/arm/boot/zImage is ready UIMAGE arch/arm/boot/uImage Image Name: Linux-4.14.0-xilinx Created: Thu Sep 12 15:51:37 2019 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 3965568 Bytes = 3872.62 KiB = 3.78 MiB Load Address: 00008000 Entry Point: 00008000 Kernel: arch/arm/boot/uImage is ready
Let’s try to boot the kernel this time, copy the uImage file to the boot partition in the microsd card, also copy the devicetree.dtb file. Also, we did not create it earlier, but we will also need a “uEnv.txt” file for u-boot, to tell it how to load the kernel and the devicetree file and what parameters to pass to it.
Note: the filenames uEnv.txt, and devicetree.dtb might be different for you, I may have changed this in the u-boot config using menuconfig.
Create uEnv.txt file in the boot partition with the contents:
bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait load_image=fatload mmc 0 ${kernel_load_address} ${kernel_image} && fatload mmc 0 ${devicetree_load_address} ${devicetree_image} uenvcmd=echo Copying Linux from SD to RAM... && mmcinfo && run load_image && bootm ${kernel_load_address} - ${devicetree_load_address}
Once that is done, let’s try booting our kernel:
U-Boot 2018.01 (Sep 11 2019 - 14:37:48 +0530) Xilinx Zynq ZC702 Model: Zynq ZC702 Development Board Board: Xilinx Zynq Silicon: v3.1 I2C: ready DRAM: ECC disabled 1 GiB MMC: sdhci@e0100000: 0 (SD) reading uEnv.txt ... ... reading uImage 3965632 bytes read in 254 ms (14.9 MiB/s) reading devicetree.dtb 9226 bytes read in 17 ms (529.3 KiB/s) ## Booting kernel from Legacy Image at 02080000 ... Image Name: Linux-4.14.0-xilinx Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 3965568 Bytes = 3.8 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 ... OK Loading Device Tree to 1fffa000, end 1ffff409 ... OK Starting kernel ... Booting Linux on physical CPU 0x0 Linux version 4.14.0-xilinx (tavish@resurgam) (gcc version 7.3.1 20180314 (Linaro GCC 7.3-2018.04-rc3)) #1 SMP PREEMPT Wed Sep 11 15:01:56 IST 2019 CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d Waiting for root device /dev/mmcblk0p2... mmc0: new high speed SDHC card at address 1388 mmcblk0: mmc0:1388 USD00 7.32 GiB mmcblk0: p1 p2 EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) VFS: Mounted root (ext4 filesystem) on device 179:2. Freeing unused kernel memory: 1024K init_stage2: hwclock main process (731) terminated with status 1 Ubuntu 12.04 LTS localhost.localdomain ttyPS0 localhost login: root (automatic login) Last login: Thu Jan 1 00:00:06 UTC 1970 on ttyPS0 Welcome to the Xillinux distribution for Zynq-7000 EPP. You may communicate data with standard FPGA FIFOs in the logic fabric by writing to or reading from the /dev/xillybus_* device files. Additional pipe files of that sort can be set up by configuring and downloading a custom IP core from Xillybus' web site (at the IP Core Factory). For more information: http://www.xillybus.com. To start a graphical X-Windows session, type "startx" at shell prompt. root@localhost:~#
It boots! It booted into Ubuntu for me, which will not happen in your case (because I had content from the demo CD which came with my board in the microsd card). More on the Linux root file system in the next section (rootfs). Here are my microsd card’s contents:
--- Partition 1 - FAT32 formatted boot partition $ ll /media/tavish/boot/ total 6400 drwxr-xr-x 4 tavish tavish 1536 Jan 1 1970 ./ drwxr-x---+ 4 root root 4096 Sep 12 16:07 ../ -rw-r--r-- 1 tavish tavish 2569512 Sep 12 15:35 BOOT.BIN -rw-r--r-- 1 tavish tavish 9226 Sep 12 15:57 devicetree.dtb -rw-r--r-- 1 tavish tavish 372 Sep 11 14:47 uEnv.txt -rw-r--r-- 1 tavish tavish 3965632 Sep 12 15:56 uImage --- Parition 2 - ext4 formatted - contains the rootfs - from demo image of Zturn lite $ l /media/tavish/rootfs/ bin/ boot/ dev/ etc/ home/ lib/ lost+found/ media/ mnt/ opt/ proc/ root/ run/ sbin/ selinux/ srv/ sys/ tmp/ usr/ var/
How Linux was able to boot and run Ubuntu, was because of the ‘kernel cmdline/bootargs’ that we passed to it, through u-boot. It told the kernel to mount the root filesystem from first SD card’s second partition: This is from the uEnv.txt file:
bootargs=console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=0
Note: if your kernel has loadable modules, those need to be packed in the rootfs also, for that you need to do “make modules” and “make INSTALL_MOD_PATH=/media/tavish/rootfs modules_install” for example.
Note: uImage is necessary for u-boot bootm command, which we are using right now. uImage is a kernel image with a u-boot wrapper, created with mkimage utility. Newer u-boot (ours too) supports booting kernel zImage (which was also generated when we built our kernel) directly also.
Step 7 – Rootfs – Linux root filesystem
You have multiple options for how to obtain or create a root filesystem, for Linux. You can use a distribution like Debian, or Ubuntu if you can find a “armhf” port of it. Generally for Debian for example, you can use debootstrap or netinstall image with qemu or chroot to generate a filesystem image. Petalinux uses Yocto, which can also be used separately, or with petalinux. Right now we will use Buildroot, to generate a very minimal and basic rootfs, which is sufficient for our needs at the moment.
Buildroot
Here’s a XIlinx article about this – https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842369/Build+Linux+for+Zynq-7000+AP+SoC+using+Buildroot
- Download Buildroot – “wget https://buildroot.org/downloads/buildroot-2019.02.5.tar.gz“
- Run “make menuconfig“, the settings you need to put for the correct architecture are:
- Target options:
Architecture: ARM (little endian)
Architecture variant: cortex-A9
[*] Enable NEON SIMD
[*] Enable VFP extensions
Target ABI – EABIhf - Go to “System configuration > Run a getty (login prompt) after boot > TTY port” and set to “ttyPS0“
- Target options:
- Run make
Once it is done building, the rootfs will be available in output/images/rootfs.tar. To copy to the microsd card, you can do: cd /media/tavish/rootfs/ (second partition on the card, ext4 formatted), then tar xvf /opt/Xilinx/buildroot/buildroot-2019.02.5/output/images/rootfs.tar. If you have kernel modules that need to be installed do that also as explained above with modules_install from the kernel directory.
This is the output from the serial now:
Waiting for root device /dev/mmcblk0p2... mmc0: new high speed SDHC card at address 1388 mmcblk0: mmc0:1388 USD00 7.32 GiB mmcblk0: p1 p2 EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) VFS: Mounted root (ext4 filesystem) on device 179:2. devtmpfs: mounted Freeing unused kernel memory: 1024K EXT4-fs (mmcblk0p2): re-mounted. Opts: data=ordered Starting syslogd: OK Starting klogd: OK Initializing random number generator... done. Starting network: OK Welcome to Buildroot buildroot login: root #
Using UIO driver for your IP on Xilinx Zynq
UIO – (userspace I/O) is a Linux kernel feature which allows you to write driver for a memory mapped device. Candidates for UIO are devices that do not really need other kernel services, and which are not handled better by some other kernel driver. This includes many kinds of FPGA IPs.
Xilinx article on device tree and UIO – https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842482/Device+Tree+Tips#DeviceTreeTips-8UsingUIO
UIO howto from the kernel docs – https://www.kernel.org/doc/html/v4.17/driver-api/uio-howto.html
In the example that I am building, I have my custom IP (which I generated using Vivado HLS), attached to the AXI Bus. The goal of all of this was to access this IP from my Linux application. In the device tree project’s folder, SDK generated the file pl.dtsi, which contains this for me:
/ { amba_pl: amba_pl { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; ranges ; fir_filter_0: fir_filter@43c00000 { /* This is a place holder node for a custom IP, user may need to update the entries */ clock-names = "ap_clk"; clocks = <&clkc 15>; compatible = "xlnx,fir-filter-0.0"; reg = <0x43c00000 0x10000>; xlnx,s-axi-axilites-addr-width = <0xa>; xlnx,s-axi-axilites-data-width = <0x20>; }; }; };
Although it is an auto-generated file, we will modify it for now (couldn’t find a way to not modify it, there is no system-user.dtsi for me as it is present for some people in forums). We’ll modify compatible = “xlnx,fir-filter-0.0”; to compatible = “generic-uio”; – this is so that we are able to use generic UIO driver to talk to this peripheral/IP. We’ll also pass uio_pdrv_genirq.of_id=generic-uio to kernel bootargs in uEnv.txt.
After making these two changes, i.e. – 1. edit uEnv.txt 2. edit pl.dtsi and re-generate devicetree.dtb, we will see if we can see our uio peripherals:
# ls /sys/class/uio/ uio0 # ls /dev/uio* /dev/uio0
Using Buildroot SDK to cross-compile an application
See https://buildroot.org/downloads/manual/manual.html#_advanced_usage
We simply need to add the Buildroot toolchain to out path, and simply use it. You can do the following:
export PATH=/opt/Xilinx/buildroot/buildroot-2019.02.5/output/host/bin:$PATH export CC=arm-buildroot-linux-uclibcgnueabihf-gcc export CXX=arm-buildroot-linux-uclibcgnueabihf-g++ export LD=arm-buildroot-linux-uclibcgnueabihf-ld export AR=arm-buildroot-linux-uclibcgnueabihf-ar export OBJCOPY=arm-buildroot-linux-uclibcgnueabihf-objcopy export SIZE=arm-buildroot-linux-uclibcgnueabihf-size
For the IP that I am testing (named fir_filter generated using HLS, but it does not matter if it is from an AXI memory mapped IP made with verilog/VHDL), there is driver code in the SDK project list’s BSP project, which I had created. Code is for both baremetal, and for Linux. For me it is located in “/home/tavish/vivado/video_linux/video_linux.sdk/standalone_bsp_0/ps7_cortexa9_0/libsrc/fir_filter_v0_0/src”. My project name was “video_linux”.
The application that I want to run is the following file (which doesn’t do much) – test.c:
#include "xfir_filter.h" int main() { XFir_filter fir0; int rc; if ((rc = XFir_filter_Initialize(&fir0, "fir_filter")) != XST_SUCCESS) { fprintf(stderr, "Initialization failed. Return code: %d\n", rc); exit(EXIT_FAILURE); } if ((rc = XFir_filter_Release(&fir0)) != XST_SUCCESS) { fprintf(stderr, "Release failed. Return code: %d\n", rc); exit(EXIT_FAILURE); } return 0; }
There is also a Makefile in the directory, which I modified slightly for my needs:
# ============================================================== # File generated on Thu Aug 22 19:21:04 IST 2019 # Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2018.3 (64-bit) # SW Build 2405991 on Thu Dec 6 23:36:41 MST 2018 # IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 # Copyright 1986-2018 Xilinx, Inc. All Rights Reserved. # ============================================================== COMPILER=$(CC) ARCHIVER=$(AR) CP=cp COMPILER_FLAGS= EXTRA_COMPILER_FLAGS= LIB=libxil.a RELEASEDIR=../../../lib INCLUDEDIR=../../../include INCLUDES=-I./. -I${INCLUDEDIR} INCLUDEFILES=*.h LIBSOURCES=*.c OUTS = *.o app: $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) test_app/test.c -o test_fir libs: echo "Compiling fir_filter" $(COMPILER) -c $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) $(ARCHIVER) -rv ${RELEASEDIR}/${LIB} $(OUTS) make clean include: ${CP} $(INCLUDEFILES) $(INCLUDEDIR) clean: rm -rf ${OUTS}
Run make app, to build the file test_fir. This application doesn’t do anything, but it doesn’t give an error, which means initialization and release work. To test this, copy this file to the rootfs, say the /root folder.
When you run it you should see:
buildroot login: root # ./test_fir #
No output! Which means our application was able to initialize and release the uio driver without any issue.
Conclusion
In this article, we were able to see the complete workflow of utilizing an IP in the FPGA, by building u-boot, FSBL, kernel, device tree, rootfs, and application. Writing this helped me remember all the parts involved in the whole process.