Device Tree Generation

There are two paths available for device tree generation. The first path is to use the BoardModel API to generate device tree overlays directly from Python. The second path is to use the BoardModel API to generate device tree overlays from a Vivado .xsa file. If you are connecting an ADI device to a Raspberry Pi, BeagleBone, Intel FPGA, or any platform that does not use Vivado, you can generate device tree overlays directly from Python using the BoardModel API.

This guide walks through the simplest case — an ADIS16495 IMU on a Raspberry Pi — then shows how the same approach scales to more complex boards with clock chips, JESD204 links, and FPGA transceivers. It is recommened to follow the XSA workflow if you are using Vivado, but it is not required. See XSA to Device Tree for more information.

Example: ADIS16495 IMU on Raspberry Pi

The ADIS16495 is a 6-DOF inertial measurement unit connected via SPI. Its device tree node is simple: a compatible string, SPI mode flags, and an interrupt GPIO.

Step 1: Build a BoardModel

from adidt.model import BoardModel, components

model = BoardModel(
    name="rpi5_adis16495",
    platform="rpi5",
    components=[
        components.adis16495(
            spi_bus="spi0",
            cs=0,
            gpio_label="gpio",
            interrupt_gpio=25,
        ),
    ],
)

The components module provides pre-configured factories for each supported device — no need to specify template filenames or role strings.

That is the entire model. No JESD links, no FPGA config, no clock chip — just one SPI device.

Step 2: Render to DTS

from adidt.model.renderer import BoardModelRenderer

nodes = BoardModelRenderer().render(model)
overlay_content = nodes["converters"][0]
print(overlay_content)

Output:

&spi0 {
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;
    imu0: adis16495@0 {
        compatible = "adi,adis16495-1";
        reg = <0>;
        spi-max-frequency = <2000000>;
        spi-cpol;
        spi-cpha;
        interrupt-parent = <&gpio>;
        interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
    };
};

Step 3: Write to a file

Wrap the overlay in DTS headers and write it out:

with open("adis16495-rpi5.dts", "w") as f:
    f.write("/dts-v1/;\n/plugin/;\n\n")
    for node_list in nodes.values():
        for node in node_list:
            f.write(node + "\n")

Step 4: Compile and deploy

# Compile the overlay
dtc -@ -I dts -O dtb -o adis16495-rpi5.dtbo adis16495-rpi5.dts

# Copy to the RPi boot partition
sudo cp adis16495-rpi5.dtbo /boot/overlays/

# Enable in config.txt
echo "dtoverlay=adis16495-rpi5" | sudo tee -a /boot/config.txt

# Reboot
sudo reboot

After reboot, verify the device appears:

ls /sys/bus/iio/devices/
cat /sys/bus/iio/devices/iio:device0/name
# adis16495-1

Editing the model before rendering

The BoardModel is a plain Python dataclass. Change any field before rendering:

# Change interrupt GPIO pin
imu = model.components[0]
imu.config["interrupt_gpio"] = 17

# Change SPI chip select
imu.config["cs"] = 1
imu.spi_cs = 1

# Use a different ADIS variant
imu.config["compatible"] = "adi,adis16497-3"
imu.config["device"] = "adis16497"

# Re-render with changes
nodes = BoardModelRenderer().render(model)

Multiple devices on one board

Add more components to the same model. Devices on the same SPI bus are automatically grouped:

model = BoardModel(
    name="rpi5_multi",
    platform="rpi5",
    components=[
        components.adis16495(spi_bus="spi0", cs=0, interrupt_gpio=25),
        components.adis16495(
            spi_bus="spi0", cs=1, label="imu1", interrupt_gpio=24,
        ),
    ],
)

Both devices appear inside the same &spi0 { ... } block in the rendered output.

Scaling up: FPGA boards with JESD204

For boards with clock chips, high-speed converters, and JESD204 links, the same BoardModel structure scales by adding more components and JesdLinkModel entries. The existing board classes handle this complexity:

from adidt.boards.daq2 import daq2

board = daq2(platform="zcu102")
model = board.to_board_model(solver_config)
# model.components: AD9523-1 clock, AD9680 ADC, AD9144 DAC
# model.jesd_links: RX link, TX link

For simpler SOM boards like the ADRV9361-Z7035 (AD9361 SDR transceiver on a Zynq Z-7035), the model has no JESD links or FPGA config:

from adidt.boards.adrv9361_z7035 import adrv9361_z7035

board = adrv9361_z7035(platform="bob")  # or "fmc"
model = board.to_board_model({})
# model.components: AD9361 transceiver (SPI)
# model.jesd_links: [] (AD9361 uses LVDS, not JESD204)

See BoardModel: Unified Device Tree Generation for detailed examples with daq2, ad9081_fmc, adrv9009_fmc, ad9084_fmc, adrv9361_z7035, and adrv9009_zu11eg.

For the XSA pipeline workflow (Vivado-based), see XSA Flow Tutorials.

Available components

The adidt.model.components module provides factory functions for each supported device. Import and use directly — no template filenames needed:

from adidt.model import components

Simple SPI devices:

  • components.adis16495(spi_bus, cs, ...) — ADIS16495/16497 IMU

  • components.adxl345(spi_bus, cs, ...) — ADXL345 3-axis accelerometer

  • components.ad7124(spi_bus, cs, ...) — AD7124 24-bit precision ADC

Clock chips:

  • components.hmc7044(spi_bus, cs, ...) — HMC7044 clock distributor

  • components.ad9523_1(spi_bus, cs, ...) — AD9523-1 clock generator

  • components.ad9528(spi_bus, cs, ...) — AD9528 clock generator

ADCs / DACs:

  • components.ad9680(spi_bus, cs, ...) — AD9680 ADC

  • components.ad9144(spi_bus, cs, ...) — AD9144 DAC

  • components.ad9152(spi_bus, cs, ...) — AD9152 DAC

  • components.ad9172(spi_bus, cs, ...) — AD9172 RF DAC

Transceivers:

  • components.ad9081(spi_bus, cs, ...) — AD9081 MxFE

  • components.ad9084(spi_bus, cs, ...) — AD9084 RX transceiver

Each factory accepts device-specific keyword arguments (forwarded to the underlying context builder). See Board Model Module for the full API reference.

CLI shortcut

The gen-dts command provides a CLI equivalent to the Python workflow above — no script needed:

adidtc gen-dts -b daq2 -p zcu102 -c solver_config.json

# Generate and compile to DTB in one step
adidtc gen-dts -b ad9081_fmc -p vpk180 -c config.json --compile

This runs the board class’s to_board_model()BoardModelRenderer pipeline and writes the DTS (and optionally DTB) to disk. See Command Line Interface for all gen-dts options.