Skip to content
heliaPROFILER
Getting started
HELIA

Install

Get hpx and the tools it drives onto your machine. When this page is done, hpx doctor reports every required row as found. Nothing here needs a board attached.

Python 3.11 or newer on the host (requires-python in pyproject.toml), a package manager (uv or pip), and either an internet connection for the downloads below or the Nix flake, which pins everything. Windows users need long-path support before the first build; the command is in step 1.

Terminal window
uv tool install helia-profiler

uv tool install keeps hpx in its own environment, so the example model shipped inside the package is not importable from your shell; use a source checkout’s examples/quickstart/kws_model.tflite or your own model on the First profile page.

On Windows, enable long paths before the first build. Some NSX module checkouts exceed the 260-character MAX_PATH limit; git needs its setting so checkouts can create the files, and the OS policy so Python can traverse and clean them:

Terminal window
git config --global core.longpaths true
# In an elevated (Administrator) PowerShell; new processes pick it up
# immediately, no reboot needed:
Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem `
-Name LongPathsEnabled -Value 1

Optional extras use the same installer as the base package. To add both compiler and model-analysis support to a uv tool environment:

Terminal window
uv tool install --force 'helia-profiler[aot,analysis]'

For an active Python environment:

Terminal window
pip install 'helia-profiler[aot]' # heliaAOT compiler support
pip install 'helia-profiler[analysis]' # model compute and parameter analysis, no hardware

The aot extra installs the supported helia-aot>=0.33.0,<2.0.0 range. Power capture support (pyjoulescope_driver) is a core dependency and needs no extra.

arm-none-eabi-gcc is the default cross-compiler. armclang and ATfE are alternatives; see Toolchains.

Terminal window
sudo apt install gcc-arm-none-eabi

For a newer compiler than your distribution packages, download the Arm GNU Toolchain tarball and put its bin/ directory on PATH:

Terminal window
export PATH="$HOME/arm-gnu-toolchain-14.3.rel1/bin:$PATH"
Terminal window
sudo apt install cmake ninja-build

hpx drives the probe through SEGGER Commander (JLinkExe on Linux and macOS, JLink.exe on Windows) for flashing, and through pylink-square, installed with hpx, for RTT and SWO capture. Discovery checks JLINK_PATH first, then both executable names on PATH, then the common SEGGER install locations; set JLINK_PATH to the full executable path for a non-standard install.

Install the .deb or .tgz from segger.com/downloads/jlink. The SEGGER installer sets up the udev rules for non-root access to the probe; replug the probe afterwards if hpx probes list does not see it.

hpx resolves SEGGER RTT through the pinned nsx-segger-rtt NSX module. No separate RTT checkout is needed. To test a different module, use the existing module override contract:

build:
nsx_modules:
nsx-segger-rtt:
path: /path/to/nsx-segger-rtt

The path must contain nsx-module.yaml, not just a raw SEGGER source tree. Use ref instead of path for a remote override, for example ref: v0.1.3. The RTT module does not support the version selector; use a released tag or commit through ref. Overrides are recorded as development-overrides and refused by pinned fixture builds.

Breaking migration: target.segger_rtt_path was removed, including from the Python TargetConfig constructor. Nonempty SEGGER_RTT_PATH is rejected for RTT runs; unset it and migrate to the module override above. Doctor no longer accepts raw RTT source arguments or checks target sources. Existing frozen runs and compiled records remain readable; rebuilding a plan from the previous baseline requires re-freezing with this HPX or using the original HPX version.

Installing tools does not grant access to attached hardware. J-Link and Joulescope are raw USB devices; uart and usb_cdc transports also need the serial device (/dev/ttyACM0, /dev/ttyUSB0). Run hpx as your normal user after granting access.

On a desktop Linux host, from a source checkout:

Terminal window
nix run .#install-udev-rules -- --dry-run
nix run .#install-udev-rules

Without Nix, run bash nix/scripts/install-udev-rules.sh. The installer writes 70-segger-jlink.rules and 70-joulescope.rules under /etc/udev/rules.d/, reloads the rules and refreshes USB devices; unplug and reconnect the instruments afterwards. The rules grant the active local desktop session access through uaccess, not every user.

On NixOS, declare the rules in the system configuration instead:

services.udev.packages = [
(pkgs.writeTextDir "lib/udev/rules.d/70-hpx.rules" ''
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", MODE="0660", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0e88|0e87|10ba|10b9|135a", MODE="0660", TAG+="uaccess"
'')
];

Use services.udev.packages, not services.udev.extraRules, which NixOS writes after the active-session access handler.

For SSH sessions and CI runners, which have no local desktop session, give a dedicated group access:

Terminal window
sudo groupadd -f hpx
sudo usermod -aG hpx "$USER"
sudo tee /etc/udev/rules.d/70-hpx-group.rules >/dev/null <<'RULES'
SUBSYSTEM=="usb", ATTR{idVendor}=="1366", GROUP="hpx", MODE="0660", ENV{ID_MM_DEVICE_IGNORE}="1"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0e88|0e87|10ba|10b9|135a", GROUP="hpx", MODE="0660"
RULES
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=usb

For serial ports, check the device’s owning group with ls -l /dev/ttyACM0 and add yourself to it (dialout on Ubuntu and Debian); the raw-USB rules do not cover /dev/tty*.

hpx doctor prints one row per tool. The tool table was captured on macOS 26.6 on 2026-09-21. The environment diagnostic below is illustrative; your Python path and driver version will differ:

Check host tools
$ hpx doctor Toolchain Check ╭────┬───────────────────────────────────────┬─────────────────────────────────────────────────────╮ │ │ Tool │ Path │ ├────┼───────────────────────────────────────┼─────────────────────────────────────────────────────┤ │ ✓ │ CMake (>= 3.24) │ /opt/homebrew/bin/cmake │ │ ✓ │ Ninja build system │ /opt/homebrew/bin/ninja │ │ ✓ │ SEGGER J-Link commander │ /usr/local/bin/JLinkExe │ │ ✓ │ neuralspotx Python package │ installed │ │ ✓ │ ARM GCC toolchain │ /Applications/ArmGNUToolchain/15.2.rel1/arm-none-e… │ │ ✓ │ pylink Python package (RTT transport) │ installed │ ╰────┴───────────────────────────────────────┴─────────────────────────────────────────────────────╯ Unknown: Joulescope environment: Python 3.12; /path/to/python; driver 2.3.4; unknown Device or driver metadata is unknown; JS320 compatibility was not determined. All required tools found.

A dash in the first column marks an optional tool that was not found (heliaAOT, armclang); those rows only matter if you use that engine or toolchain. The tool table checks presence; minimum versions are on Hardware prerequisites. The environment diagnostic uses host metadata. Unknown means doctor has not inspected attached instruments; it does not mean a required host tool is missing.

Hardware prerequisites lists what to plug in. If the board is already on the bench, go straight to Validate your setup.