Bootloader-equipped instruments have two firmware environments: RUNTIME for acquisition and measurement, and BOOTLOADER for flash slot management and updates. Original Zynq instruments without a bootloader have runtime only. The same native API discovers the attachment, resolves its profile and owns the required startup/handoff sequence; a GUI, C program or Python script is a client of that lifecycle.
If a bootloader-equipped device is running an application image, request service entry before a field update. This normally does not require a power cycle. A device known to have no bootloader returns NEXATOM_ERROR_NOT_SUPPORTED without sending the service-entry control.
/* Request entry; check the result, then confirm service through status. */
nexatom_error_code_t rc = nexatom_tt_request_field_upgrade_service_entry(device);
/* Use nexatom_tt_refresh_field_update_status() to obtain confirmed service
status/slots before an update. See the field-update reference for buffers. */
device.request_field_upgrade_service_entry()
status, slots = device.refresh_field_update_status()
# A returned service status/slot table is the evidence for the next operation.
The native request quiets normal runtime traffic, transfers transport ownership to the service path and sends the appropriate runtime handoff command. Request success alone does not prove that firmware reset or entered service. Confirm service using the response/status API before proceeding. Zynq PS and Kintex MicroBlaze implement the hardware transition differently; clients do not need separate handoff protocols or a USB disconnect/re-enumeration loop.
If aborting a pending request, use clear_field_upgrade_service_entry_request() (nexatom_tt_clear_field_upgrade_service_entry_request in C). Do not call it immediately after every entry request: it is a cancellation/recovery operation. When service is already confirmed, clearing the request is a native host-state no-op and does not send runtime commands to the bootloader.
Because an instrument may power on in runtime or service, the native connect_runtime() operation performs the common measurement startup. It leaves an already usable runtime in its current acquisition/output mode, or boots an existing valid image when needed, and returns success only after decoded runtime identity and control authorization are established. It never loads firmware or changes the stored default slot.
/* device is the handle created from the selected discovery result. */
nexatom_error_code_t rc = nexatom_tt_connect_runtime(device, 20000);
if (rc != NEXATOM_SUCCESS) {
/* Report the actual error; do not blindly resend a boot command. */
}
/* Only configure acquisition after success. */
In Python, call device.connect_runtime(timeout_ms=20000) on an existing device, or use open_runtime_device() from nexatomtt.runtime_boot to manage handle lifetime as well:
from nexatomtt.runtime_boot import RuntimeBootOptions, open_runtime_device
# library and device_info come from discovery of the selected instrument.
with open_runtime_device(library, device_info,
RuntimeBootOptions(timeout_ms=20000)) as device:
profile = device.get_device_profile()
# Configure channels, register callbacks/open savers, then acquire.
# Stop output and close savers before leaving the context.
RuntimeBootOptions)from nexatomtt.runtime_boot import RuntimeBootOptions
options = RuntimeBootOptions(
timeout_ms=20000, # Native connection + boot/readiness budget
mode_timeout_sec=20.0, # Used only for explicit preferred-slot inspection
poll_sec=0.25, # Used only for that explicit mode-inspection loop
preferred_slot=None # Normal measurement: native chooses existing image
)
select_runtime_slot())Normal runtime entry chooses the valid stored default slot, otherwise the lowest-indexed valid slot. An optional explicit preferred_slot is available for a field-update/verification workflow and is checked by the helper’s select_runtime_slot() function:
RuntimeBootOptions.preferred_slot, provided its state is VALID.is_default in the bootloader’s flash table, provided its state is VALID.VALID.A requested slot must be VALID; a missing/invalid preferred slot is rejected. Normal native runtime entry returns NEXATOM_ERROR_NOT_SUPPORTED if no valid slot is available (surfaced as NexatomError in Python). The helper’s explicit-slot selection can raise RuntimeBootError. Neither failure authorizes silently loading an image or changing which persistent slot is default.
The explicit nexatom_tt_boot_field_update_slot() / device.boot_field_update_slot() operation is synchronous with native runtime startup: success requires usable decoded runtime identity and controls. Retain the same handle and registered callbacks. Do not recreate it, issue another peripheral reset or repeat startup register writes after success.
The FTDI bridge may remain enumerated throughout the firmware transition. The following identity information remains useful to applications, but the normal startup path does not require a Python-owned USB reconnect loop:
| Field | Description |
|---|---|
connection_id |
The board’s identity: usb: plus the USB port path. It stays the same through a boot or service transition while the board stays in the same port |
serial_number |
FT601 USB serial, for service information only; it never selects a board |
product_model_id |
Native profile’s model identity and associated contract |
application_image_id |
Running image identity; changing firmware does not change the USB serial or the connection_id |
A boot ACK is not runtime readiness. If an explicit boot times out after transmission, preserve the error/status evidence and inspect the device; do not automatically send a second boot request. Run blocking boot/service operations off an application’s UI thread. Each handle owns one board, and both C and Python delegate these lifecycle decisions to the same native library.