Xilinx
Block Preview

Introduction

Principle of Operation

The Frame Transfer block transfers multi-channel event data from pixelated sensors or detector arrays to the PC. Each triggered event generates a frame containing:

  • 64-bit timestamp
  • 64-bit trigger counter
  • 64-bit frame counter
  • Channel trigger mask
  • Energy values for all channels

This is ideal for:

  • Imaging detectors (pixelated sensors, CCDs, SiPMs arrays)
  • Multi-channel spectroscopy (simultaneous energy readout)
  • Event-by-event analysis with timing correlation
  • 2D distributions reconstruction

The block can be visualized through Resource Explorer or read programmatically using SciSDK.

SciSDK Documentation: https://nuclearinstruments.github.io/SCISDK/

Pin Description

DATA_0 Input 16 bit BIT VECTOR
DV_0 Input 1 bit BIT
START Input 1 bit BIT
External Trigger – When trigger_mode = ext, a rising edge on this input triggers frame acquisition.
CLK Input 1 bit BIT
Clock – All operations are synchronous to this clock. Default: CLK_ACQ.
Default: Default Board Clock
SYNC_TRIG_IN Input 1 bit BIT
Sync Trigger Input – Trigger signal from master board in multi-board setup. Used when trigger_mode = sync and CONFIG_SYNC[0] = 1.
SYNC_RESET_IN Input 1 bit BIT
Sync Reset Input – Reset signal from master board. Clears counters and FIFO when asserted.
SYNC_CLK_IN Input 1 bit BIT
Sync Clock Input – Timestamp clock from master board. Ensures synchronized timestamps across boards.
BUSY Output 1 bit BIT
Busy – HIGH when frame is being transferred to FIFO or FIFO is full. Use to gate upstream trigger logic.
SYNC_TRIG_OUT Output 1 bit BIT
Sync Trigger Output – Trigger signal to daisy-chain to next board. Directly passes through or generates internal trigger.
SYNC_RESET_OUT Output 1 bit BIT
Sync Reset Output – Reset signal to daisy-chain to next board.
SYNC_CLK_OUT Output 1 bit BIT
Sync Clock Output – Timestamp clock to daisy-chain to next board.
DATA_n
Data Input – 16-bit energy/value input for channel N. Multiple channels supported (DATA_0, DATA_1, … DATA_n).
DV_n
Data Valid – When HIGH, indicates that DATA_n contains valid data. Used for AND/OR trigger logic. One per channel.
CE
Clock Enable – When HIGH, enables acquisition. Used to gate data capture. Default: 1 (always enabled).
Default: 1

Properties

Property window

Name EndpointName

Set the name of the endpoint

Logical endpoint name used in register map. Used in Resource Explorer and SciSDK. Default: ImageReadout_0

Default: ImageReadout_0

Number of inputs InputCount

Set the number of input to the virtual block

Number of input channels (pixels). Range: 1 to 32. Each channel has a DATA and DV input pair. Default: 1

Default: 1

Range: 1 – 32

Number of samples per channel Samples

Set the number of samples stored for each acquisition

FIFO buffer depth in frames. Available values: 128, 256, 512, 1024, 2048, 4096. Default: 1024

Default: 1024

Options: 128 256 512 1024 2048 4096

Analog Channel Word Size Wordsize

Set the analog channel word size in bits

Channel data word size in bits. Fixed at 16 bits. Default: 16

Default: 16

Range: 1 – 32

⚙️ Detailed Operation

Data Flow

  ┌──────────────────────────────────────────────────────────────────────────┐
│                      Frame Transfer Data Flow                            │
│                                                                          │
│   DATA_0 ──────►┌────────────────┐                                       │
│   DV_0 ────────►│                │                                       │
│   DATA_1 ──────►│     Frame      │     ┌─────────────┐                   │
│   DV_1 ────────►│    Builder     │────►│    FIFO     │────► PC           │
│   ...          │  State Machine │     │   Buffer    │                   │
│   DATA_n ──────►│                │     │             │                   │
│   DV_n ────────►│                │     └─────────────┘                   │
│                └────────────────┘                                       │
│                       ▲                                                  │
│   START ──────────────┤                                                  │
│   CE ─────────────────┤                                                  │
│                       │                                                  │
│                  ┌────┴────┐                                             │
│                  │  BUSY   │──► HIGH during frame transfer               │
│                  └─────────┘                                             │
└──────────────────────────────────────────────────────────────────────────┘
  

Frame Builder State Machine

The VHDL implements a state machine that builds frames on trigger events:

  ┌───────┐     trigger      ┌──────────┐     wait done    ┌──────────┐
│ IDLE  │─────────────────►│WAIT_RUN  │─────────────────►│ HEADER0  │
└───────┘                  └──────────┘                  └──────────┘
    ▲                                                         │
    │                                                         ▼
    │                   ┌──────────────┐                ┌──────────┐
    │                   │ SEND_ENERGY  │◄───────────────│ HEADER1  │
    │                   └──────────────┘                └──────────┘
    │                         │                              │
    │       all channels      │                              ▼
    └─────────────────────────┘                         ... HEADER8
  

Timing Diagram

Normal Frame Acquisition:

 

Trigger Modes:

 

Trigger Logic (from VHDL)

The trigger is generated based on CONFIG_TRIGGER_MODE:

Mode Value Logic Description
AND 000 AND(DV & MASK) All masked channels must be valid
OR 001 OR(DV & MASK) Any masked channel valid triggers
External 010 START input External trigger signal
Sync 100 SYNC_TRIG input Synchronized trigger from another board

Wait Time

The CONFIG_WAIT register adds delay cycles between trigger detection and energy capture. This allows late-arriving channels to settle before capture:

 

Frame Data Structure

Each frame consists of a fixed header followed by channel energy values:

Word Content Description
0 0xFFFFFFFF Header marker (sync word)
1 0x12345678 Frame identifier
2 TIMECODE[63:32] Timestamp high 32 bits
3 TIMECODE[31:0] Timestamp low 32 bits
4 COUNTER_IN[63:32] Trigger count high (total triggers)
5 COUNTER_IN[31:0] Trigger count low
6 COUNTER_OUT[63:32] Frame count high (acquired frames)
7 COUNTER_OUT[31:0] Frame count low
8 CHANNEL_TRIGGER Trigger mask (which channels triggered)
9..N ENERGY[0..n-1] Energy value for each channel

Total frame size: 9 + N_channels words (32-bit each)

Signal Logic (from VHDL)

Signal Logic Description
BUSY FIFO_FULL_IN OR (state != IDLE) HIGH when acquiring or FIFO full
FIFO_FLUSH RESET OR ARM[1] OR EXT_SYNC_RESET Clears FIFO
READ_STATUS[0] FIFO_EMPTY No data available
READ_STATUS[1] CONFIG_ARM[0] Acquisition enabled

Configuration Registers

CONFIG_ARM

Bit Function
0 Enable acquisition (1 = running)
1 Reset (clears FIFO and counters)

CONFIG_TRIGGER_MODE

Bits Value Mode
2:0 000 AND trigger (all masked channels)
2:0 001 OR trigger (any masked channel)
2:0 010 External trigger (START input)
2:0 100 Sync trigger (SYNC_TRIG input)

CONFIG_T0_MASK

Channel enable mask. Bit N enables channel N for trigger logic.

CONFIG_WAIT

Number of clock cycles to wait after trigger before capturing energy values.

CONFIG_SYNC

Bit Function
0 Enable external synchronization (use SYNC_* inputs)

READ_STATUS

Bits Function
0 FIFO empty (1 = no data)
1 Running (mirrors CONFIG_ARM[0])
31:8 Available words in FIFO

Multi-Board Synchronization

For systems with multiple boards, the SYNC signals provide distributed timing:

  ┌─────────┐   SYNC_CLK    ┌─────────┐   SYNC_CLK    ┌─────────┐
│ Board 0 │──────────────►│ Board 1 │──────────────►│ Board 2 │
│ (Master)│   SYNC_RESET  │ (Slave) │   SYNC_RESET  │ (Slave) │
│         │──────────────►│         │──────────────►│         │
│         │   SYNC_TRIG   │         │   SYNC_TRIG   │         │
│         │──────────────►│         │──────────────►│         │
└─────────┘               └─────────┘               └─────────┘
  

Set CONFIG_SYNC[0] = 1 on slave boards to use external clock and reset.

Software Integration with SciSDK

The Frame Transfer is fully supported by SciSDK. For complete documentation see: SciSDK Frame Guide

Available Parameters

Parameter Access Description Default
trigger_mode R/W and, or, ext, sync or
wait_time R/W Wait cycles after trigger 0
channel_mask R/W Enabled channels bitmask 0xFFFFFFFF
acq_mode R/W blocking or non-blocking blocking
timeout R/W Timeout in ms for blocking mode 1000

Available Commands

Command Description
start Reset and start acquisition
stop Stop acquisition

Buffer Structure

c
  typedef struct {
    uint32_t magic;              // Buffer identifier
    uint32_t *data;              // Raw frame data
    struct {
        uint32_t buffer_size;    // Total buffer size
        uint32_t valid_data;     // Valid data words
        uint32_t nchannels;      // Number of channels
    } info;
} SCISDK_FRAME_RAW_BUFFER;

typedef struct {
    uint32_t magic;
    struct {
        uint64_t timestamp;
        uint64_t trigger_count;
        uint64_t frame_count;
        uint32_t trigger_mask;
        uint32_t *energy;        // Array of energy[nchannels]
    } *frames;                   // Array of decoded frames
    uint32_t n_frames;           // Number of frames
    uint32_t nchannels;
} SCISDK_FRAME_DECODED_BUFFER;
  

C/C++ Example

c
  #include "SciSDK_DLL.h"

// Allocate decoded buffer
SCISDK_FRAME_DECODED_BUFFER *buffer;
SCISDK_AllocateBuffer("board0:/MMCComponents/ImageReadout_0",
                      T_BUFFER_TYPE_DECODED,
                      (void**)&buffer, _sdk);

// Configure: OR trigger on first 4 channels
SCISDK_SetParameterString("board0:/MMCComponents/ImageReadout_0.trigger_mode",
                          "or", _sdk);
SCISDK_SetParameterInteger("board0:/MMCComponents/ImageReadout_0.channel_mask",
                            0x0F, _sdk);  // Channels 0-3
SCISDK_SetParameterInteger("board0:/MMCComponents/ImageReadout_0.wait_time",
                            0, _sdk);

// Start acquisition
SCISDK_ExecuteCommand("board0:/MMCComponents/ImageReadout_0.start", "", _sdk);

// Read frames
SCISDK_SetParameterString("board0:/MMCComponents/ImageReadout_0.acq_mode",
                          "blocking", _sdk);

int ret = SCISDK_ReadData("board0:/MMCComponents/ImageReadout_0",
                           (void*)buffer, _sdk);
if (ret == NI_OK && buffer->n_frames > 0) {
    for (int f = 0; f < buffer->n_frames; f++) {
        printf("Frame %d: ts=%llu, triggers=%llu\n",
               f, buffer->frames[f].timestamp,
               buffer->frames[f].trigger_count);

        // Print energy for each channel
        for (int ch = 0; ch < buffer->nchannels; ch++) {
            printf("  CH%d: %u\n", ch, buffer->frames[f].energy[ch]);
        }
    }
}

// Stop and free
SCISDK_ExecuteCommand("board0:/MMCComponents/ImageReadout_0.stop", "", _sdk);
SCISDK_FreeBuffer("board0:/MMCComponents/ImageReadout_0",
                  T_BUFFER_TYPE_DECODED, (void**)&buffer, _sdk);
  

Python Example

python
  from scisdk.scisdk import SciSDK
import numpy as np
import matplotlib.pyplot as plt

sdk = SciSDK()
sdk.AddNewDevice("usb:10500", "dt5560", "board0", "RegisterFile.json")

# Allocate buffer
res, buf = sdk.AllocateBuffer("board0:/MMCComponents/ImageReadout_0",
                               sdk.T_BUFFER_TYPE_DECODED)

# Configure: OR trigger, 16 channels
sdk.SetParameter("board0:/MMCComponents/ImageReadout_0.trigger_mode", "or")
sdk.SetParameter("board0:/MMCComponents/ImageReadout_0.channel_mask", 0xFFFF)

# Start acquisition
sdk.ExecuteCommand("board0:/MMCComponents/ImageReadout_0.start", "")

# Read frames
sdk.SetParameter("board0:/MMCComponents/ImageReadout_0.acq_mode", "blocking")
sdk.SetParameter("board0:/MMCComponents/ImageReadout_0.timeout", 5000)

res, buf = sdk.ReadData("board0:/MMCComponents/ImageReadout_0", buf)
if res == 0 and buf.n_frames > 0:
    # Accumulate image (sum all frames)
    image = np.zeros(buf.nchannels)
    for f in range(buf.n_frames):
        for ch in range(buf.nchannels):
            image[ch] += buf.frames[f].energy[ch]

    # Reshape to 2D if square (e.g., 4x4 = 16 channels)
    side = int(np.sqrt(buf.nchannels))
    if side * side == buf.nchannels:
        image_2d = image.reshape(side, side)
        plt.imshow(image_2d, cmap='hot')
        plt.colorbar(label='Counts')
        plt.title('Accumulated Image')
        plt.show()
    else:
        plt.bar(range(buf.nchannels), image)
        plt.xlabel('Channel')
        plt.ylabel('Counts')
        plt.show()

sdk.ExecuteCommand("board0:/MMCComponents/ImageReadout_0.stop", "")
  

Resource Explorer

The Frame Transfer tool in Resource Explorer provides real-time visualization with 2D image display and event-by-event analysis.

Quick Reference

Item Description
Channels 1 to 32
Word size 16 bits (fixed)
Buffer depth 128 to 4096 frames
Trigger modes AND, OR, External, Sync
Frame size 9 + N_channels words
Best for Pixelated detectors, multi-channel readout

Resources & Timing

  • Latency: ~10 clock cycles from trigger to frame completion

  • Throughput: One frame per trigger (with wait time + N channels)

  • Uses BRAM for FIFO storage
  • Each frame contains timestamp, counters, mask, and all channel values
  • Supports multi-board synchronization via SYNC signals
  • Wait time allows late channels to settle before capture
  • FIFO full prevents new acquisitions (BUSY goes HIGH)
  • Maximum 32 channels per block