Introduction

This application note explain how to design a firmware that can work with all Sci-Compiler FPGA compatible models that allows to use the board as a Multievent latching scaler housing up to both analog and digital channels. Each channel has a 32 bit counting depth. The maximum counting frequency depends on the target board. In the example we will use a DT1260 with a discriminator but is possible to use for example the DT2495 replacing the analog input + discriminator with an edge detector directly connected to V2495 pin. Each counter is incremented at the leading edge of the input signal. As a trigger arrives, all counters are latched simultaneously and independently from the counting operations; the counting operation is indeed reset. After the latched counter values have been made available for readout, the FPGA writes them into a FIFO memory. Events written in the FIFO can be readout via USB (or ethernet). Once an event has been written, the Scaler can accept another trigger even if the previous event has not been readout yet, provided that the FIFO memory has enough space left for other data.

Experimental setup

We used the following setup to test the counter reading a list. We use Cobalt60 as signal source and a Photomultiplier tube (PMT), to detect the gamma rays.

Experimental Setup
Experimental Setup

The PMT is connected to the SCI DK DT1260 board and the HV Power Supply Module.

It is connected to the digitizer DT1260 to channel 1 with a LEMO cable . It is connected to the HV Module, the DT5533E, to channel 1 with a BNC cable.

Both the modules are also connected to the computer. The digitizer is connected with a micro USB cable. The HV Module is connected with a USB type B cable.

List component

Sci-Compiler List Component
Sci-Compiler List Component

The block represent a list of data that could be buffered in a FIFO and could be downloaded with the specific List Module tool in the Resource Explorer or using the Sci-SDK library. The user can specify during the block creation the data size and the number of data that has to be buffered. The data can be provided with the IN input and can be written in memory giving a HIGH signal in the WR input. The CLK input signal represents the clock signal, while the RESET input signal clears the buffer. The BUSY output signal is HIGH during the data downloading and the FULL output signal is HIGH to indicate that the memory is full of data.

A FIFO (First-In, First-Out) memory, also known as a queue, is a type of memory structure that operates based on the principle of preserving the order in which data elements are stored and retrieved. It follows a First-In, First-Out data access policy, meaning that the data item that enters the memory first will be the first to be read out.

In a FIFO memory, data elements are written or “enqueued” at one end of the memory, called the “write” or “input” end, and they are read or “dequeued” from the other end, known as the “read” or “output” end. The data elements are stored in the memory in the same sequence they were received, forming a queue-like structure.

In order to prevent overflow of the FIFO, the d-well time must be big enough to allow the readout to be faster than the writing speed.

Scaler Block Diagram in Sci-Compiler

At first, we put an Analog Input box and select A0 as the analog signal input.

Before connecting the input signal to the oscilloscope, we put a Polarity Inverter box. The signal has a negative polarity so we invert it, because it is easier to work with positive signals. We also add a Register Read box (pol) to set the inversion.

The output signal of the polarity inverter is connected to the Oscilloscope box, to the analog entrance (A0).

Block Diagram of the Scaler
Block Diagram of the Scaler

After the polarity inverter, we put a Trigger LE box. The input signal is given in the In entrance. This box generates an output signal when the input signal amplitude exceeds a threshold. The threshold is specified with a Register Read box (trgthrs). The output signal TOT (Time Over Threshold) gives the triggered signal and it is connected to the Oscilloscope to a digital input (D1_0).

The Trigger output generates a signal every time a input signal exceeds the threshold. This output is connected to the Oscilloscope to a digital input (D0_0) and to the Start input to give an external trigger to the Oscilloscope.

The Trigger output is also connected to a Couter box, to the In entrance. The block counts the input pulses occurring during a certain period of time. The output signal is connected to a List box, to the In entrance.

The List block represent a list of data that could be buffered and downloaded with the specific List Module tool in the Resource Explorer.

To reset the Counter and the writing input of the List box, we put a Pulse Generator box. This box generates a periodic pulse. The pulse period and the width can be programmed. We put a Register Read box (PulsePeriod) to set the period, the width is in default set.

The output signal of the Pulse Generator is connected directly to the WE input of the List. In this way, every time there is a pulse, it enables the data writing.

The output signal of the Pulse Generator is also connected to the Reset input of the Counter, but first it passes through a D-Latch Rising box.

A D-Latch has a data input signal (D) and a control entry (Clock). When the Clock is HIGH (1), the input data is reported to the output and memorized in the circuit. When the Clock is LOW (0), the output is not changed and keeps the previous value, independently from the input signal changes.

In this case, the input signal is the pulse, the Clock is set to Default value: CLK_ACQ for DT5550 (80 MHz) and CLK_50 for V2495 (50 MHz), and the output goes to the Reset of the Counter.

Readout list data using Resource Explorer

Opening Resource Explorer, it is possible to view the oscilloscope, to set the parameters of the registers and to download the data from the List.

Resource Explorer Oscilloscope used to monitor the trigger
Resource Explorer Oscilloscope used to monitor the trigger

We set the polarity (pol) as 1, to invert the signal. We set the threshold of the trigger (trgthrs) al 2000, to see an effect on the signal. We set the period of the pulse generator (PulsePeriod) as 6250000. CLock of the board is 62.5 MHz, so the period is 6250000/62.5e6 = 100 ms. In the end, we set the trigger sources of the oscilloscope to External, so we get the same trigger signal as the one used by the Trigger LE.

To get the data from the List, we click on the Download button and the following window will be shown.

List download window
List download window

In this tool, it is possible to select the Format in which the data will be downloaded (decimal or binary). The fields File Name and File Folder allow to specify the name and the path of the file downloaded.

The number of data in words is specified in the Target Size field. It is possible to set the unit from the menu on its right side (word, kW, MW). In the Packet Size field it is possible to set the number of words.

The download process can be started and stopped with, respectively, the Start and Stop buttons.

In the chosen directory, a file “.txt” will be created with the data.

Readout waveform using Sci-SDK

Sci-SDK is a hardware-agnostic library that interfaces with CAEN Open hardware boards developed with SciCompiler. It offers flexibility and scalability for data acquisition, readout, and analysis, with a user-friendly interface and comprehensive documentation. The Sci-SDK library offers a hierarchical and hardware-agnostic approach, providing a common interface to manage various elements and seamlessly interface with different hardware boards. It ensures a unified and flexible experience for data acquisition and analysis, regardless of the specific hardware being used.

The Sci-SDK library is available for most common programming languages, including C/C++, Python, and LabVIEW. The library is open-source and available on GitHub. Sci-SDK Information

The following code snippet shows how to use the Sci-SDK library to read the list after configuring the trigger register. The script set the THRS register to 2350 (trigger level) and than monitor the analog signal and digital signal with the oscilloscope. The data are stored in an array and the time difference between events is indeed calculated and plotted with an histogram. It is possible to so the Poisson distribution of the events.

The code snippet is written in python and uses the Sci-SDK python library.

First of all the Sci-SDK library must be installed system wide. Use the Installer in windows or with package manager in Linux. Please be sure to install the Sci-SDK library binary files. The pip package is only a wrapper to the binary files and does not include the libraries files.

Read more about List Driver on GitHub Docs

  1. Install the Sci-SDK library and matplotlib

    pip install matplotlib
    pip install scisdk
    
  2. Create a new python file and import the Sci-SDK library

    Replace the usb:10500 with the PID of your board or : if you are using a network connection. Replace the model with the model of your board you are targeting the code to.

    
    from scisdk.scisdk import SciSDK
    import matplotlib.pyplot as plt
    from struct import unpack
    import csv
    
    # initialize Sci-SDK library
    sdk = SciSDK()
    #DT1260
    res = sdk.AddNewDevice("usb:28686","dt1260", "./library/RegisterFile.json","board0")
    if res != 0:
        print ("Script exit due to connection error")
        exit()
    
    res = sdk.SetRegister("board0:/Registers/trgthrs", 2350)
    
    #negative pulses
    res = sdk.SetRegister("board0:/Registers/pol", 1)
    
    #1s w-dell time
    err = sdk.SetRegister("board0:/Registers/PulsePeriod", 6250000)
    
    if res != 0:
        print ("Configuration error")
        exit()
    
    
    res = sdk.SetParameterString("board0:/MMCComponents/List_1.thread", "true")
    res = sdk.SetParameterInteger("board0:/MMCComponents/List_1.timeout", 500)
    res = sdk.SetParameterString("board0:/MMCComponents/List_1.acq_mode", "blocking")
    # allocate buffer raw, size 100
    res, buf = sdk.AllocateBuffer("board0:/MMCComponents/List_1", 100)
    res = sdk.ExecuteCommand("board0:/MMCComponents/List_1.stop", "")
    res = sdk.ExecuteCommand("board0:/MMCComponents/List_1.start", "")
    array_counts = []
    while True:
        res, buf = sdk.ReadData("board0:/MMCComponents/List_1", buf)
        if res == 0:
            for i in range(0, int(buf.info.valid_samples/4)):
                T = unpack('<L', buf.data[i*4:i*4+4])[0]
                array_counts.append(T)
        print(len(array_counts))
        if len(array_counts) > 100000:
            break
    
    # write the array to file
    
    # Specify the file path of the CSV file you want to write the array to
    file_path = 'file_path.csv'
    
    # Open the file in write mode
    with open(file_path, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(['Counts'])  # Write the column header
    
        # Write each element of the array as a row in the CSV file
        for count in array_counts:
            writer.writerow([count])
    

You may also be Interested in