How to …

Use peripherals


The TDK’s all have 1 or more general purpose LEDs. They are registered (via the devicetree) to the Linux OS as LED devices. Device files for them are created at /sys/devices/platform/<group-label>/leds/<label> For example to turn on a LED run the following command (replace the labels with the actual values):

echo 1 > /sys/class/leds/<label>/brightness


The TDK’s all have a I2C EEPROM memory device that can (partly) be used by the user. The first part of this memory is used by TOPIC for production data as serial numbers and MAC address

To find the EEPROM device run the following ‘search’ command on target:

find /sys/bus/nvmem -name nvmem

The search result is the path to the EEPROM device

To view its content:

hexdump -C <path_to_eeprom_device>

To write something to it:

echo "Hello World" > <path_to_eeprom_device>

RTC (Real Time Clock)

To configure the RTC, first sync time with internet once using ntpd

echo "server" >> /etc/ntp.conf
echo "server" >> /etc/ntp.conf
ntpd -d -n -q

The output should be something like:

ntpd: '' is
ntpd: '' is
ntpd: sending query to
ntpd: sending query to
ntpd: reply from offset:+54013.704436 delay:0.007460 status:0x24 strat:2 refid:0xca4f43c1 rootdelay:0.001831 reach:0x01
ntpd: reply from offset:+54013.700510 delay:0.151523 status:0x24 strat:3 refid:0x4c4037ce rootdelay:0.089906 reach:0x01
ntpd: sending query to
ntpd: reply from offset:+54013.704544 delay:0.008119 status:0x24 strat:2 refid:0xca4f43c1 rootdelay:0.001831 reach:0x03
ntpd: setting time to 2021-03-30 09:08:45.282092 (offset +54013.704544s)

To sync the HW clock with the system clock run the following:

hwclock -w

After executing the above commands, the system clock should stay intact after a reboot.


Wired ethernet is supported on the TDKZ(U) and TDPZU boards. This interface is registered as the eth0 interface. This can be displayed/configured using the ifconfig command:

ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:12:78:AB:95:12
          inet addr:  Bcast:  Mask:
          RX packets:1311 errors:0 dropped:0 overruns:0 frame:0
          TX packets:593 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:127745 (124.7 KiB)  TX bytes:627085 (612.3 KiB)

A command like ping can be used to test the connection:

ping -c 1


On most of the TDKs a display interface is present as a HDMI output. This display is present as a linux framebuffer device in /dev/fbX where X is a sequential number starting at 0.

When running the desktop-image, the framebuffer device is used by that desktop. When running with the minimal-image, the framebuffer can be ‘tested’ by running:

cat /dev/urandom > /dev/fbX


WiFi is supported on the XDPZU board. To check/configure it run:

ifconfig wlan0
wlan0   Link encap:Ethernet  HWaddr C0:EE:40:61:9F:58
        inet6 addr: fe80::c2ee:40ff:fe61:9f58/64 Scope:Link
        RX packets:54 errors:0 dropped:0 overruns:0 frame:0
        TX packets:17 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:6164 (6.0 KiB)  TX bytes:3501 (3.4 KiB)

When running the desktop-image the GUI can configure the WiFi network.

When running with the minimal-image a connection to a WiFi network can be made using a wpa supplicant file. This file is located (or should be created) at /etc/wpa_supplicant.conf and can be ‘filled’ by using the following command:

wpa_passkey MY-SSID MY-PASSWORD >> /etc/wpa_supplicant.conf

Change the contents of the file to look like the following:


Replacing SSID-of-network and Password-of-network with the SSID and password of the network you are connecting to.


Bluetooth is supported on the XDPZU board.

Scan for bluetooth devices using bluetoothctl. Running bluetoothctl will open a bluetooth console.

In that console, run the following commands:

power on
scan on
discoverable on

Now the device should show up, type devices in bluetooth console to show a list

Device 7D:51:A8:F6:3B:9A 7D-51-A8-F6-3B-9A
Device 0C:43:10:1D:B5:43 0C-43-10-1D-B5-43
Device 1D:46:AA:40:F6:DC 1D-46-AA-40-F6-DC
Device 47:A6:EB:66:2E:D3 47-A6-EB-66-2E-D3
Device 00:D1:EB:ED:86:CF 00-D1-EB-ED-86-CF

Use SWUpdate

SWUpdate is a software package for embedded Linux systems to update the contents of non-volatile memories holding the software components like a bootloader, kernel and rootfs.

The SWUpdate service can be reached in several ways but the most convenient way is via a network connection. The board runs a webserver hosting a webpage. Use a browser or program like curl to upload a software update package file (.swu) through this webpage. This .swu file contains the new software and also the location of where it should go and other meta-data.

There are several ways to update a board using SWUpdate:

  • SWUpdate webpage:
    Can be reached by typing its hostname/IP-address + a port number into a browser.

    The portnumber defaults to 8080. This requires a network connection (ethernet, USB or WiFi). Example URL:

  • USB (memory device):

    On the desktop images, an USB stick with a .swu file on it can be inserterd. This will then be automativally installed.

  • Command line:

    Execute the following command on the target device: swupdate -v -i <path_to_swu_file>. This is particularly useful to debug issues with an SWU file.

  • SWUpdate API:

    SWUpdate also comes with an API to control it.

For more information check the SWUpdate website.

Update scheme

Most setups use an A/B update scheme. There are two copies of the whole filesystem present, called A and B. When the system is running from A, the update process will write the new image to the B partition. On success, the system will mark B as bootable and reboot. This makes the upgrade almost atomic, a failure during the upgrade will have no effects on the running system.

By default, for SD/eMMC we use A/B scheme for all devices using 4 partitions:

  • boot Hold the FSBL/u-boot

  • x-rootfs-a and x-rootfs-b Where x is either sd or emmc

    These partitions are the ones being updated by SWUpdate. Either a or b is the ‘active’ partition.

  • data General data partition. Can be used to hold persistent data, SWUpdate will not touch this partition. By default it is empty.

The following will happen when providing a new SWUpdate package for eMMC.

  1. The non-active will be mounted (lets say B)

  2. SWUpdate writes the Update to non-active partition

  3. Copy peristent files from A to B (see Persistent files)

  4. SWUpdate moves the bootable flag from A to B

  5. SWUpdate triggers a reboot

  6. The boot loader will detect bootable flag is now on B, and will use that one to boot from.

When there is not enough space on the media for two copies, a single update scheme can be used. This allows an atomic update only by booting from another device, for example one can upgrade the QSPI while running from eMMC. When running from QSPI, it is still possible to upgrade the image in QSPI but failure during the upgrade will result in the system being unable to boot. In this case the user will have to manually repair this, for example by booting from an SD card instead.

The following configs use a single scheme instead:

  • XDP with QSPI

  • TDKZ with QSPI

Persistent files

Some files can be left untouched when updating the board’s software with SWUpdate, like for example the WiFi configuration.

See for full list:


After writing the new copy of the filesystem, the upgrade process will copy the files in this list (if they exist) to the newly installed copy. At the moment, this is not available on QSPI using ubifs.

Create your own Vitis app

Xilinx’ Vitis SDK can be used to create applications for the TOPIC boards. To create a platform project, import the .XSA file generated by Vivado. Check FPGA technical reference designs (TRDs) for more information about this .XSA file.

Standalone (bare-metal) application

For the steps on how to create a standalone application with the Vitis SDK we refer to the

Linux application

For the steps on how to create a Linux application with the Vitis SDK we refer to the

Create and use an SDK

In order to generate the SDK in the petalinux project folder run

petalinux-build --sdk

This command will create a script in the folder images/linux.

To create the SDK, run the petalinux-package command:

petalinux-package --sysroot -s images/linux/

This will create an sdk folder in images/linux which contains the SDK. This directory can also be changed by passing the -d or –dir flag to the petalinux-package command.

For more information on how to use the SDK, see the UG1144 Petalinx Reference Guide.

Use a custom FPGA image

By default the TLD will fetch a prebuild FPGA image from The following steps describe how to use a custom build FPGA image.

  1. Create your Vivado project (it is recommended to use the TRD as a starting point, see FPGA technical reference designs (TRDs).)


    The TLD 2020.2 release only supports the use of Vivado 2020.2.

  2. Build your FPGA image

  3. Export the build results: choose File -> Export -> Export hardware (Use default settings in wizard)

    This exports a .xsa file which is needed in the next step.

  4. Import the results into the petalinux project by running the following command in the petalinux workspace:

    petalinux-config --silentconfig --get-hw-description ${XSA_FILE}
  5. Generate new device tree based on new FPGA image (by default the TLD does not do this, as it is not reliable)
    Enable the devicetree generation by running the following command: petalinux-config
    In the menu change the following:
    • DTG Settings -> DEselect “Remove PL from devicetree”

    • Save the configuration -> default location

    • Exit the menu

  6. Rebuild the design

    Clean the project (sometimes old build results are not cleaned automaticaly) and then rebuild:

    rm -rf components/ build/
    petalinux-build -c device-tree -x do_compile

Now petalinux has generated a device tree based on the new FPGA image. Unfortunately this can not be used as is but it can be used as a starting point / reference.

  1. Create a new device tree file at project-spec/meta-user/recipes-bsp/device-tree/

    An example of the contents of this file is shown below:

    SUMMARY = "Devicetree overlay for FPGA image"
    require ../../../topic-platform/meta-topic/recipes-bsp/device-tree/
    BITSTREAM = "fpga-image-example-custom"
  2. Create a new folder to hold the new devicetree files:


  3. Copy the device tree from the reference design to
    Check Appendix A - Topic boards for the location of the reference device tree file of your board.
  4. Update the reference device tree with the new components.
    The auto generated version is located here:
    It is recommended to only copy/overwrite the changed parts into the new device tree
  5. Disable the device tree generation again by running the following command: petalinux-config
    In the menu do the following:
    • DTG Settings -> select “Remove PL from devicetree”

    • Save the configuration -> default location

    • Exit the menu

    The device tree part is done now.
    The next steps show how to generate a recipe for the new FPGA image. This to include the FPGA image into the build.
  6. Create a new folder project-spec/meta-user/recipes-bsp/fpga and create a new file in there:

    An example of the content is shown below. Change the ${FPGA_BITFILE} variable with the correct filename.

    SUMMARY = "FPGA image"
    require recipes-bsp/fpga/
    FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
    PV = "1"
    FPGA_BITFILE = "fpga-image-example-custom.bit"
    BOARD_DESIGN_NAME = "fpga-image-example-custom"
    PKGV = "${PV}"
    B = "${S}"
    # Nothing to build
    do_compile() {
            cp ${FPGA_BITFILE} fpga.bit
  7. Copy the .bit file to project-spec/meta-user/recipes-bsp/fpga/fpga-image-example-custom/

    Make sure to use the same filename as provided in the recipe ${FPGA_BITFILE}. The recipe created in the previous step will pick up the .bit file and copy it into the build.

  8. Update the project-spec/meta-user/recipes-core/images/ to include new FPGA image.

    Do this by adding the name of the new recipe to the IMAGE_INSTALL_append list and adding the original dtb recipe to the IMAGE_INSTALL_remove list. See example below:

    IMAGE_INSTALL_append = " \
       dtb-example-custom \
    IMAGE_INSTALL_remove = "dtb-miami-florida-gen-reference"
    # login by default
    inherit autologin
  9. Now we can build again and the new FPGA image will be built and included into the image: