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.
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:
- 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.
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.
Place a new trigger
Enable the hysteresis in the 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.
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”.
We can now connect the port to the trigger analog input
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
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 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
This is the final diagram of the sub-design
Now save to synchronize the sub-design, the icon on the three will change as follow
Right click on the subdesign name and select “Open memory map”
The memory map will for the subdesign “channel_processing” will open in a new tab
Press refresh and than Auto Assign
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
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
The imported top design will appear as a custom block like this:
We can now add the two analog input of the DT1260
and create the shared register for the hysteresis we will call hyst.
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.
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.
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).
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.
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.
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)