Skip to main content

Pattern generator

The pattern generator drives the device's outputs from a script, so the instrument stimulates the board as well as watching it. Reached through workspace.pattern.

Like a decoder, a generator is a JavaScript file in the server's script library, one implementing on_pattern_generate. See pattern generator scripts for writing one.

Only the SP1000G series can generate

Pattern generation is an SP1000G-series feature (SP1018G, SP1036G, SP1054G). The SE254, SP209 and SP259 families are logic analysers only: they capture, and have no outputs to drive.

The examples on this page use sp1018, the SP1018G demo device (hw:SP1018G-<serial> for the real thing). Its channels are group-prefixed (G1 PWM, G1 I2C SCL, G2 UART TX), one group per block of 18 channels.

preview() is the exception: it is interpreted by the server rather than sent to hardware, so it runs on any device. That makes it possible to write a generator without an SP1000G at hand, but it does not prove that the attached device could play it.

One generator per workspace

The device has a single pattern generator, so a workspace has one too. Adding a second replaces the first: there is no list and no instance id, just current.

options and add​

for option in workspace.pattern.options("pwm.js"):
print(option)

generator = workspace.pattern.add("pwm.js", {
"channel": workspace.channel("G1 PWM"),
"simple_freq_val": 1_000_000, # 1 MHz
"simple_pwm_val": 25, # 25 % duty
"nb_of_cycles": "100",
})
print(generator)

Example output. pwm.js on an SP1018G. Each option with its type, unit, tab and default:

channel: Target channel (ch_selector) = None
simple_freq_val [Fixed duty cycle]: Frequency (engineering_input) in Hz = nan
simple_pwm_val [Fixed duty cycle]: Duty cycle (engineering_input) in % = 50.0
mod_type [Modulated frequency]: Modulation type (combo) one of ['Sine', 'Triangle', 'SawTooth'] = 'Sine'
f_mod [Modulated frequency]: Modulation frequency (engineering_input) in Hz = nan
ph_mod [Modulated frequency]: Modulation phase (engineering_input) in DEG = 0.0
freq_carrier [Modulated frequency]: Carrier frequency (engineering_input) in Hz = nan
duty_min [Modulated frequency]: Carrier minimum (lower) duty cycle (engineering_input) in % = 10.0
duty_max [Modulated frequency]: Carrier maximum (upper) duty cycle (engineering_input) in % = 90.0
nb_of_cycles: Number of cycles (0 = infinite loop) (text_input) = '1000'

and the generator that add() returns:

instance_id=1 file_name='pwm.js' name='PWM Builder on CH 8' enabled=True pausable=False paused=False

A nan default means the script leaves it unset and expects you to supply it (simple_freq_val here). The bracketed name is the tab the option sits under in the ScanaStudio dialog.

Options work exactly as they do for decoders: discovered at runtime, keyed by id or caption, anything omitted keeps the script's default.

current​

The generator attached to this workspace, if any.

generator = workspace.pattern.current # PatternDesc, or None
generator.file_name
generator.name
generator.enabled
generator.pausable # the script can pause mid-generation
generator.paused

workspace.pattern.config # its current settings, which update() takes

preview​

Runs the generator script through an interpreter instead of the device. The result replaces the workspace data exactly as an acquisition would. The script runs unchanged, so the preview shows the real program. This is how you develop and verify a generator with no hardware attached.

workspace.pattern.preview(timeout=300.0)

# The preview lands in the workspace like a capture would:
for edge in workspace.data.transitions(channel=workspace.channel("G1 PWM")):
print(edge.sample, edge.level)
Preview overwrites the capture

The preview replaces whatever the workspace was displaying. Save anything you still need first.

resume​

A generator script can pause itself mid-program. resume lets it continue.

if workspace.pattern.current and workspace.pattern.current.paused:
workspace.pattern.resume()

set_enabled and set_generate_on_trigger​

set_enabled turns generation off without losing the configuration.

set_generate_on_trigger decides when the pattern plays: on the acquisition's trigger, or as soon as the acquisition starts.

workspace.pattern.set_enabled(True)
workspace.pattern.set_generate_on_trigger(True)
workspace.pattern.generate_on_trigger # read it back

update and remove​

workspace.pattern.update({"baud": 9600})
workspace.pattern.remove()

Generating while capturing​

On real hardware the generator runs alongside the acquisition, and a script can produce its pattern in chunks as the capture goes.

The acquisition waits for the first chunk

The capture is only armed once the first chunk of the pattern has been loaded and started, so that the stimulus cannot arrive after the trigger. If the script generates nothing at all, the acquisition is refused with a Refused error.

The full working pattern is on Stimulus and capture together.