Pattern generator

This chapter focuses on the functions and notions related to the creation of logic signals with your SP1000G series device.

In the previous part, dedicated to SQ series, signals generation worked with a Signal Builder. It means that :

  • The script was executed as soon as you added it to the Signal Builder section of Scanastudio,
  • Then the signals were immediately displayed on your screen,
  • And they were finally sent to the SQ device after clicking on Start.

For SP1000G series, signals generation works with a Pattern Generator as follows :

  • You add your script in Pattern Generator section,
  • Then, you have to click on Start Generate and Capture,
  • ScanaStudio executes the script and sends it to the SP1000G, which acquires while generating.

Entry point functions

If you want to make a script which is able to build and generate a signal with your SP1000G series device, you have to write these three entry point functions.

Warning : You must write function on_draw_gui_pattern_generator() and function on_pattern_generate(), even if you don’t use it (in this case, you won’t write anything between the braces) :

function on_draw_gui_pattern_generator()
{
  // Function called when ScanaStudio needs to display the GUI
}

function on_eval_gui_pattern_generator()
{
  //  Function to evaluate (and validate) the choices set by the user in the GUI
}

function on_pattern_generate()
{
  // Function to build the signals you want to generate
}

Function on_draw_gui_pattern_generator()

Description : This entry point function is launched when you add the script in Pattern Generator section. It will display a GUI, an interface which can be used (for example) :

  • to configure parameters you want to take into account for the signals generation,
  • to show information to user,

This entry point function is optional ; you don’t have to write between the braces if you don’t need it.

Example :

You want to know on which channel the user wants to display a signal.

Context : Pattern generator

Function on_eval_gui_pattern_generator()

Description : This entry point function is used to evaluate if the GUI configuration (the choices made by the user in the GUI) is valid. The approach is often based on :

  • The retrieve of a value entered by the user in the GUI,
  • A test on this value,
  • Then a display of an error message if this value doesn’t correspond to criteria you defined.

This entry point function is optional.

Example :

Following the previous example, the user wants to display a signal on channel 2, but you want to keep this channel for a clock signal you built in on_pattern_generate() entry point function. So if the user selects channel 2, you display an error message.

Context : Pattern generator

Entry point function on_pattern_generate()

Description : This entry point function is focused on signal creation and generation. It can use parameters :

  • Defined on ScanaStudio, like the sample rate,
  • Entered in the GUI, like the frequency you want to make a modulation,
  • Directly created in the function itself, like retrieving the available memory in your device.

Example :

Following the previous example, the user wants to display a sine signal on the channel selected by the user, and use a frequency defined in the GUI.

Context : Pattern generator

Electrical setting of channels

For each channel you want to use, you have to set three parameters :

ScanaStudio.builder_set_out_voltage(channel_index, voltage_in_mV) ; //Voltage of the output
ScanaStudio.builder_set_idle_state(channel_index, idle_state) ; //Idle state of the output
ScanaStudio.builder_set_io(channel_index, output_type) ; //Type of the output

ScanaStudio.builder_set_out_voltage(channel_index, voltage_in_mV)

Description : This function allows you to set the voltage of the output for a channel.

Parameters :

  • channel_index : Index of the channel (0 Based, that is the first channel’s index in 0).
  • voltage_in_mV : Voltage of the output, which depends on your use, and is expressed in milliVolts (mV).

Example :

If you want to initialize the first channel to 3300 mV, you can write :

ScanaStudio.builder_set_out_voltage(0, 3300) ;

You can also get these values from the GUI, i.e. ask the user to enter a channel and a voltage value, thanks to the function on_draw_gui_pattern_generator() :

var ch = ScanaStudio.gui_get_value("channel") ; //if you stocked the user's channel choice in "channel"
var volt = ScanaStudio.gui_get_value("voltage") ; //if you stocked the user's voltage choice in "voltage"
ScanaStudio.builder_set_out_voltage(ch, volt) ;

Context : Pattern generator

ScanaStudio.builder_set_idle_state(channel_index, idle_state)

Description : Your device is described as idle when it’s not being used by any program. Thus, you have to set the value it takes during this “waiting time”. Therefore, this function allows you to set the idle state for a channel.

Parameters :

  • channel_index : Index of the channel (0 Based, that is the first channel’s index in 0).
  • idle_state : This value depends on your use, and is either 0 or 1.

Example :

If you want to initialize the idle state of the first channel to 1, you can write :

ScanaStudio.builder_set_idle_state(0, 1) ;

You can also get these values from the GUI, i.e. ask the user to enter a channel and an idle state, thanks to the entry point function on_draw_gui_pattern_generator() :

var ch = ScanaStudio.gui_get_value("channel") ; //if you stocked the user's channel choice in "channel"
var idle = ScanaStudio.gui_get_value("idle_state") ; //if you stocked the user's idle state choice in "idle_state"
ScanaStudio.builder_set_out_voltage(ch, idle) ;

Context : Pattern generator

ScanaStudio.builder_set_io(channel_index, output_type)

Description : This function allows you to set the output type for a channel.

Parameters :

  • channel_index : Index of the channel (0 Based, that is the first channel’s index in 0).
  • output_type : Depending on your use, the output type could be :
 ScanaStudio.io_type.push_pull; //a transistor connected to high and a transistor connected to low (only one is operated at a time)
 ScanaStudio.io_type.open_drain_no_pull; //a transistor connected to low and nothing else
 ScanaStudio.io_type.open_drain_pull_up; //a transistor connected to low, and a resistor connected to high

If you don’t know what to set, keep in mind that :

  • Push-pull output is best suited for communication interfaces that have single direction lines (e.g SPI, UART etc…).
  • Open drain is commonly used for bidirectional single line communication interfaces, where more than two devices are connected on the same line(e.g I2C, One-Wire etc.).

Example :

If you want to initialize the output type of the first channel to push-pull, you can write :

ScanaStudio.builder_set_io(0,  ScanaStudio.io_type.push_pull) ;

You can also get these values from the GUI, i.e. ask the user to enter a channel and a voltage value, thanks to the entry point function on_draw_gui_pattern_generator() :

var ch = ScanaStudio.gui_get_value("channel") ; //if you stocked the user's channel choice in "channel"
var io = ScanaStudio.gui_get_value("IO_type") ; //if you stocked the user's output type choice in "IO_type"
ScanaStudio.builder_set_io(ch, io) ;

Context : Pattern generator

Chunk

A SP1000G series device uses both live stream (therefore in direct emission, unlike the SQ series) and embedded memory. Thus, signal emission is different from the SQ series devices (with the Signal Builder) ; it’s done by sending “chunks”. If you want to send the whole of a signal composed of a large amount of samples, you must “cut” your signal into several chunks (if your signal size is bigger than a chunk size).

ScanaStudio.builder_start_chunk()

Description : This function sends a chunk to your device’s memory.

Context : Pattern generator

ScanaStudio.builder_get_max_chunk_size()

Description : A chunk contains all or part of your signal, that it will bring to embedded memory. It depends on the size of :

  • Your signal, i.e. the number of samples you want to build,
  • A chunk, i.e. the number of samples that a chunk is able to “carry” to embedded memory.

The size of a chunk can be obtained by the use of this function.

Context : Pattern generator

ScanaStudio.builder_wait_done(time)

Description : Once the chunk is sent, your SP1000G series device will return true or false, depending on whether or not it has finished getting the chunk into memory. It’s important to wait for the device to return true before sending another chunk.

Note : However, if you want to optimize your script, it’s recommended not to wait for your device to return true as soon as you send your chunk. It’s better to execute your instructions until your next chunk is ready to be sent. At this time, you can check if the previous chunk has been entered in your device memory, therefore if it returns true.

Parameters :

  • time : This function waits during a maximum duration “time” your device, and stops waiting when it receives a true, so when the device is ready to receive another chunk. You can set it to 500 for instance.

Context : Pattern generator

Structure of on_pattern_generate()

  • First, you have to parameter your outputs. For example, you want to use all your channel and initialize them with :
    • A 3300 mV voltage,
    • An idle state set to 0,
    • A push-pull output.
      function on_pattern_generate()
      {
      for (var ch = 0 ; ch < ScanaStudio.get_device_channels_count() ; ch++)
      {
          ScanaStudio.builder_set_out_voltage(ch, 3300) ;
          ScanaStudio.builder_set_idle_state(ch, 0) ;
          ScanaStudio.builder_set_io(ch, ScanaStudio.io_type.push_pull) ;
      }
      }
      
  • Then, you have to declare the variables you will use to send a chunk :
    • sample_acc : this variable (initialized to 0) will be incremented as soon as you add a sample, until it’s close to the maximum size of a chunk,
    • counter : this variable (initialized to 0) will be incremented when you send a chunk, so it’s used to know how many chunks you have sent,
    • first chunk : this boolean (initialized to true) will become false when the first chunk is sent.
      function on_pattern_generate()
      {
      //...
      var samples_acc = 0 ;
      var counter = 0 ;
      var first_chunk = true ;
      }
      
  • You write the way you want to build your signal, and each time you add a sample, you increment samples_acc, until you are close to the maximum size of a chunk. In this example, this script aims to add 1000 times a 1 then 0 on each channels :
    function on_pattern_generate()
    {
      //...
      var number_of_cycles = 1000 ;
      while (samples_acc < number_of_cycles)
      {
          for (var ch=0 ; ch<ScanaStudio.get_device_channels_count() ; ch++)
          {
              ScanaStudio.builder_add_samples(ch, 1, 100) ;
              ScanaStudio.builder_add_samples(ch, 0, 100) ;
          }
          samples_acc += 1 ; //increments samples_acc when you add samples
      }
    }
    
  • But it’s possible that samples_acc becomes greater than the maximum size of a chunk. This situation means that the first chunk must be sent to your SP1000G series device memory.

    Consequently, the variable first_chunk becomes false. In this example, we’ll take a margin of 5%.

    Furthermore, the variable samples_acc is both used to build the signal and the chunk. Therefore, after sending a chunk, samples_acc is subtracted to number_of_cycles, then reseting (set to 0).

    function on_pattern_generate()
    {
      //...
      while (samples_acc < number_of_cycles)
      {
          //...
          if (samples_acc >= ScanaStudio.builder_get_max_chunk_size() * 0,95) //builds normally a signal until samples_acc is greater than 95% of the chunk size
          {
              first_chunk = false ;
              counter += 1 ;
    
              ScanaStudio.builder_start_chunk() ;  //send the chunk to memory
              ScanaStudio.console_info_msg("Chunk number " + counter + " sent to SP100G series device.") ;
              ScanaStudio.builder_wait_done(500) ; //wait until memory returns true
    
              number_of_cycles = number_of_cycles - samples_acc ;
              samples_acc = 0 ;
          }
      }
    }
    
  • As it was said in the previous Note, call ScanaStudio.builder_wait_done(500) directly after sending a chunk is a waste of time. Indeed, it would be better to start building the next chunk before waiting the true sending by your SP1000G series device. Thus, to optimize this script, we will use the boolean first_chunk :
function on_pattern_generate()
{
    //...
    while (samples_acc < number_of_cycles)
    {
        //...
        if (samples_acc >= ScanaStudio.builder_get_max_chunk_size() * 0,95)
        {
            if (first_chunk == true)
            {
                first_chunk = false ;
            }

            else
            {
                ScanaStudio.builder_wait_done(500) ; //wait until memory returns true, so if your device gets the chunk into memory
            }

            counter += 1 ;

            ScanaStudio.builder_start_chunk() ;
            ScanaStudio.console_info_msg("Chunk number " + counter + " sent to SP100G series device.") ;

            number_of_cycles = number_of_cycles - samples_acc ;
            samples_acc = 0 ;
        }
    }
}
  • Finally, you have finished to add all the samples you wanted to build your signal. But considering what is written before, the last chunk won’t be sent. Indeed, the size of this last chunk won’t necessarily be equal to 95% of the maximum size of a chunk. Thus, when the last chunk is finished (so when script is out of the while loop), you have to send the last chunk.
function on_pattern_generate()
{
    //...

    while (samples_acc < number_of_cycles)
    {
        //...
    }

    if (first_chunk == true)
    {
    }

    else
    {
        ScanaStudio.builder_wait_done(500) ;
    }

    ScanaStudio.builder_set_repeat_count(1) ; //how many times you want to send the signal (here, once)
    ScanaStudio.builder_start_chunk() ;
    ScanaStudio.console_info_msg("Last chunk sent to SP100G series device.") ;

    return ;
}
  • Now, we will add on_draw_gui_pattern_generator() and on_eval_gui_pattern_generator() entry point functions to show when they are displayed on your screen. To resume, the script of this example will be :
function on_draw_gui_pattern_generator()
{
    ScanaStudio.console_info_msg("Hello world, this is a test script !");
}

function on_eval_gui_pattern_generator()
{
    ScanaStudio.console_info_msg("No problem with GUI configuration !");
    return "" ;
}

function on_pattern_generate()
{
    /*ELECTRICAL SETTINGS*/

    for (var ch = 0; ch < ScanaStudio.get_device_channels_count(); ch++)
    {
        ScanaStudio.builder_set_out_voltage(ch, 3300) ;
        ScanaStudio.builder_set_idle_state(ch, 0) ;
        ScanaStudio.builder_set_io(ch, ScanaStudio.io_type.push_pull) ;
    }

    /*VARIABLES DECLARATION*/

    var samples_acc = 0 ;
    var counter = 0 ;
    var first_chunk = true ;
    var number_of_cycles = 1000 ;

    /*SIGNALS BUILDING*/

    while (samples_acc < number_of_cycles)
    {

        /*Add samples to channels*/
        for(var ch=0; ch<ScanaStudio.get_device_channels_count(); ch++)
        {
            ScanaStudio.builder_add_samples(ch, 1, 100) ;
            ScanaStudio.builder_add_samples(ch, 0, 100) ;
        }

        samples_acc+=1 ;

        /*Send chunks*/
        if (samples_acc >= ScanaStudio.builder_get_max_chunk_size() * 0,95)
        {
            if (first_chunk == true)
            {
                first_chunk = false ;
            }

            else
            {
                ScanaStudio.builder_wait_done(500) ; //wait until memory returns true, so if your device getting the chunk into memory
            }

            counter += 1 ;

            ScanaStudio.builder_start_chunk() ;  //send the chunk to memory
            ScanaStudio.msg("Chunk number " + counter + " sent to SP100G series device.") ;

            number_of_cycles = number_of_cycles - samples_acc ;
            samples_acc = 0 ;
        }
      }

      /*SEND THE LAST CHUNK*/

      if (first_chunk == true)
      {
      }

      else
      {
          ScanaStudio.builder_wait_done(500) ;
      }

      ScanaStudio.builder_set_repeat_count(1) ;
      ScanaStudio.builder_start_chunk() ;  
      ScanaStudio.console_info_msg("Last chunk sent to SP100G series device.") ;

      return ;
}

How to execute this script on ScanaStudio

Now, we will execute this script (named “Test for website”) on ScanaStudio.

  1. First, you have to launch ScanaStudio and create a WorkSpace with your device. On top right corner, there is a button for the settings. You can click on Show log to see the console : SP100G Series create workspace
  2. Then, you have to click on Pattern generator and Add script : SP100G Series open pattern generator then add
  3. Now, you select your script (here it’s “Test for website”). When you click on Next, function on_draw_gui_pattern_generator() is executed, so the message “Hello world, this is a test script !” is displayed : SP100G Series click on your script, here test for website, hello world
  4. When you click on Finish, the script checks if, according to what you wrote in function on_draw_gui_pattern_generator(), there is a problem. In this example, we just want to display “No problem with GUI configuration !”. You can change capture periode (here, 800ms) : SP100G Series all is ok eval, now click on start gen with capture periode 800ms
  5. So now, you just have to click on Start generate and capture. As you can see, there are big spaces between some part of the signal ; it represents the time between two chunks : SP100G Series what you see : big space between two chunks
  6. If you zoom on one of the “vertical lines”, you can see a “1-0” signal : SP100G Series if you zoom on one "1-0"