Introduction

SciCompiler’s advanced architecture allows hierarchical designs in multichannel application. This powerful feature enables designers to create complex systems by encapsulating functionality into discrete modules or blocks, which can then be nested within higher-level systems. The hierarchical design has several advantages: Modularity: By breaking down a complex system into manageable parts, it simplifies the design process. Each module can be developed and tested independently, increasing efficiency and reducing errors.

Reusability: Once a module is created, it can be reused in different parts of the system or even in entirely new projects. This not only saves time but also ensures consistency across different designs.

Maintainability: When changes or updates are needed, they can be made at the module level without affecting the entire system. This localized approach to system updates makes maintenance more straightforward and less risky.

Scalability: Hierarchical designs allow for easy expansion. New layers of functionality can be added as the need arises without overhauling the existing system structure.

Clarity: A hierarchical structure makes it easier to understand the overall design of the system. It allows designers and stakeholders to visualize the flow and interaction between different system components more clearly.

Collaboration: Different teams can work on separate modules concurrently, SciCompiler allows to export and import subdesigns, so the work can be done in parallel.

Experimental Setup
Experimental Setup

In order to follow this application note, you need to install SciCompiler 2024.3.11.1 or newer and SciSDK 1.2.54 or newer

Use memory mapped components inside subdesign

The SciCompiler is a tool to speed up the design of multichannel systems. The subdesign will implement a simple trigger and a counter with an oscilloscope to monitor the analog input and the trigger. The subdesign will be replicated two times to create a multi-channel system. We will use the DT1260 as the digitizer. In the sub-design we will have a register to set the trigger threshold and a register connected to the counter to read the number of events.

The leading edge trigger have the following input:

trigger symbol
trigger symbol

  • polarity: 0 to invert the signal, 1 to keep the signal as it is
  • threshold: the threshold of the trigger, we would like to have a different threshold for each channel
  • delta: the hysteresis of the trigger, we would like to have a single hysteresis for all the channels
  • inibit: define the trigger deadtime to avoid double trigger on the noise. We will set it to a constant value for all the channels

Let’s consider a trigger circuit with hysteresis used for a voltage comparator, which is designed to output a high signal when the input voltage exceeds a certain threshold, and a low signal otherwise.

Imagine the threshold voltage is set at 5V, and we introduce a hysteresis of 1V. In this case, the comparator will switch its output from low to high not right at 5V, but at a higher voltage, say 5.5V (this is the upper threshold). Once the output is high, it won’t switch back to low as soon as the input drops below 5.5V; instead, it will switch back only when the input voltage goes down to 4.5V (this is the lower threshold).

So, for the voltage to trigger the circuit from high to low, it has to drop to 4.5V or less. And to trigger from low to high, it has to rise to 5.5V or more. This 1V difference is the hysteresis window that prevents the output from toggling rapidly in case the input voltage hovers around the 5V threshold due to noise or small fluctuations. The hysteresis ensures that the voltage has to make a definitive change before the comparator responds, thus stabilizing the trigger behavior.

trigger symbol
trigger symbol

Create a multi-channel design

Create a new design for DT1260 in SciCompiler and add a new subdesign. Rename it as “channel_processing” and open it.

create subdesign
create subdesign

Place a new trigger

select LE trigger
select LE trigger

Enable the hysteresis in the trigger configuration

trigger configuration
trigger configuration

Now create the analog input as a subdesign port. The physical I/O can not be placed in sub-design and can be connected only in the top design. This is to avoid the creation of multiple instances of the same physical I/O.

create input port
create input port

We configure the input port as ARRAY of port. This will allow to create multiple instances of the this port for each channel in the top design. We have to set this port with size 16 bits and we name the port “ansignal”.

configure input port
configure input port

We can now connect the port to the trigger analog input

connect analog
connect analog

Now create a common port to share between all channels the hysteresis value. We will use a register at top level (external from sub-design) to set the hysteresis value for all the channels. In order to make it shared between all channel we need to set Multichannel Behaviour to COMMN

create hysteresis
create hysteresis

We can now create a register to set the trigger threshold. We place it in the subdesign because we want to have a single threshold for each channel. We now create a 16 bit wide READ MODE register and we name it “trg_th”.

create register
create register

connect threshold register
connect threshold register

Create now the counter, the counter readout trigger (32 bit WRITE MODE register) and the oscilloscope.

To create the oscilloscope select signal size to 16 bit, enable digital IO

create oscilloscope
create oscilloscope

This is the final diagram of the sub-design

final diagram sub-design
final diagram sub-design

Now save to synchronize the sub-design, the icon on the three will change as follow

Subdesign Icon after saving
Subdesign Icon after saving

Right click on the subdesign name and select “Open memory map”

Right click menu
Right click menu

The memory map will for the subdesign “channel_processing” will open in a new tab

Memory map Tab
Memory map Tab

Press refresh and than Auto Assign

Assigned address
Assigned address

Sci-Compiler detect that subdesign uses Memory Mapped Component and enable pages memory mapping and assign automatically a page memory area big enough to contains all mapped components

Now open top page desgin, right click on the diagram and select multichannel sub-design

Insert new multichannel sub-design
Insert new multichannel sub-design

Select the sub-design “channel_processing”, input 2 as repeat (in order to create a design with two channels) and assign a Designator name to the page like “digital_trigger”. SciCompiler will create a memory mapped endpoint in TOP page called “page_digital_trigger”. This name will be prepend to all MMC endpoint name inside sub-design

Import subdesign in top page
Import subdesign in top page

The imported top design will appear as a custom block like this:

Multichannel sub-design in TOP page
Multichannel sub-design in TOP page

We can now add the two analog input of the DT1260

Analog input
Analog input

and create the shared register for the hysteresis we will call hyst.

Final schematic of the top design
Final schematic of the top design

We can now open the Memory Map tab for the top page and press Auto Assign to allocate the memory for the register and the subpages.

Top page memory mapped
Top page memory mapped

Please note that, because the page_digital_trigger is replicated two times, the memory usage is not 2kbyte but 4kbyte

Readout data from multi-channel design

Now we can compile the firmware, load on the DT1260 and connect with the Resources Explorer.

Before we can have a look to the RegisterFile.json file in the folder library.

This is the content of library\RegisterFile.json

{
  "MMCComponents": [
    {
      "Name": "page_digital_trigger_0_Oscilloscope_0",
      "Type": "Oscilloscope",
      "Address": 0,
      "Version": "1.0.0.0",
      "Registers": [
        ...
      ],
      "nsamples": 1024,
      "Channels": 1,
      "WordSize": 16,
      "WordEnob": 16,
      "AnalogInputs": 1,
      "DigitalInputs": 4,
      "SamplingFrequency": 0,
      "TimeMultiplexing": 1,
      "DecimatorMax": 0,
      "DecimatorAveraging": false,
      "Path": "page_digital_trigger_0/Oscilloscope_0"
    },
    {
      "Name": "page_digital_trigger_1_Oscilloscope_0",
      "Type": "Oscilloscope",
      "Address": 2048,
      "Version": "1.0.0.0",
      "Registers": [
        {
          ...
      ],
      "nsamples": 1024,
      "Channels": 1,
      "WordSize": 16,
      "WordEnob": 16,
      "AnalogInputs": 1,
      "DigitalInputs": 4,
      "SamplingFrequency": 0,
      "TimeMultiplexing": 1,
      "DecimatorMax": 0,
      "DecimatorAveraging": false,
      "Path": "page_digital_trigger_1/Oscilloscope_0"
    }
  ],
  "Registers": [
    {
      "Name": "hyst",
      "Type": "Register",
      "Address": 4096,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "Undefined",
      "Path": "/hyst"
    },
    {
      "Name": "page_digital_trigger_0_trg_th",
      "Type": "Register",
      "Address": 1031,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "Undefined",
      "Path": "page_digital_trigger_0/trg_th"
    },
    {
      "Name": "page_digital_trigger_0_cnt",
      "Type": "Register",
      "Address": 1032,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "Undefined",
      "Path": "page_digital_trigger_0/cnt"
    },
    {
      "Name": "page_digital_trigger_1_trg_th",
      "Type": "Register",
      "Address": 3079,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "Undefined",
      "Path": "page_digital_trigger_1/trg_th"
    },
    {
      "Name": "page_digital_trigger_1_cnt",
      "Type": "Register",
      "Address": 3080,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "Undefined",
      "Path": "page_digital_trigger_1/cnt"
    },
    {
      "Name": "ANALOG_OFFSET",
      "Type": "Register",
      "Address": 4294967289,
      "Version": "1.0.0.0",
      "RegionSize": 1,
      "Description": "",
      "Category": "AnalogAFE",
      "Path": "/ANALOG_OFFSET"
    }
  ],
  "Device": "SCIDK",
  "Project": "multichannel",
  "Magic": "04819291",
  "Version": null,
  "FPGA": "XC7S25CSGA225-1",
  "BuildDate": "2024-03-11T07:40:13.0462728+01:00"
}

we can observe that the endpoint name of the elements inside the subdesign has been renamed with the page name and the subdesign name. This is to avoid name collision between the different subdesigns.

For the two oscilloscope we have the following endpoint name:

  • page_digital_trigger_0_Oscilloscope_0
  • page_digital_trigger_1_Oscilloscope_0

For the two trigger threshold we have the following endpoint name:

  • page_digital_trigger_0_trg_th
  • page_digital_trigger_1_trg_th

For the two counter we have the following endpoint name:

  • page_digital_trigger_0_cnt
  • page_digital_trigger_1_cnt

We can notice that the address of the endpoint is different for the two channels. This is because the subdesign is replicated two times and the memory area is different for the two channels. This version of RegisterFile.json is called flat because the tree structure of the project is lost and the name of the endpoint is unique. In the library folder you can notice that exist also a RegisterFileTree.json that keep the tree structure of the project and the endpoint name and the address are the same for the two channel, but they are child of two different page_digital_trigger. This is the future version of the RegisterFile.json and it will be used in the future version of the Resources Explorer and SciSDK. At the moment both Resource Explorer and SciSDK are compatible with the flat version of the RegisterFile.json

Open resources explorer and connect to the DT1260. We can now read the trigger threshold and the counter for the two channels.

Resource Explorer Project Tree
Resource Explorer Project Tree

We can see that remote explorer has created a tree with the two channels and the elements inside the subdesign as a flat tree.

Have a quick look to the oscilloscope of the two channels to decide the threshold. We can but the oscilloscope in free running, thant set the trigger threshold of the oscilloscope to a reasonable value and than set the trigger threshold of the trigger to the same value (or a better accurate one).

Use the oscilloscope to find the threshold
Use the oscilloscope to find the threshold

Now we can set the trigger threshold for the two channels writing the two register page_digital_trigger_*_trg_th and configure hysteresis to 10 writing the register hyst.

Configure trigger threshold and hysteresis
Configure trigger threshold and hysteresis

At the end have a look to the oscilloscope to see if the trigger is working properly. Read the counters register to see the number of events.

Signal and counters
Signal and counters

We can create a very simple script in Python, using the SciSDK, to configure the threshold for the two channels read the counter register and print the number of events for the two channels.

from scisdk.scisdk import SciSDK
import time
# initialize Sci-SDK library
sdk = SciSDK()
#DT1260
res = sdk.AddNewDevice("usb:10500","dt1260", "./RegisterFile.json","board0")
if res != 0:
    print ("Script exit due to connection error")
    exit()


for i in range(2):
    res = sdk.SetRegister("board0:/Registers/page_digital_trigger_" + str(i) + "_trg_th", 500)

#negative pulses
res = sdk.SetRegister("board0:/Registers/hyst", 10)

while True:
    counts = [0,0]
    for i in range(2):
        res, counts[i] = sdk.GetRegister("board0:/Registers/page_digital_trigger_" + str(i) + "_cnt")
    print(counts)
    time.sleep(0.1)

You may also be Interested in