Capture Configuration#

The capture_config module provides classes for configuring capture operations on the Saleae Logic MSO device.

A CaptureConfig object must be built and passed to MSO.capture() to initiate an actual capture on the hardware. There are a lot of different knobs that control a capture, and the class CaptureConfig handles most of the validation of those various settings.

When a capture happens, sometimes values on the CaptureConfig object change slightly, i.e. to reflect the actual sample rate that was used during the capture (not all sample rates are supported, some interpolation happens, especially at high sample rates). A Capture object always contains the CaptureConfig objects that best represents the capture settings along with it.

Not all settings need to be set explicitly to get started, many will get sensible defaults (or device defaults) when a capture is taken.

Note: capture durations are not exact. The Logic MSO will always give you at least the requested number of samples, but may give up to 255 more samples than requested due to it’s truncation logic.

Overview#

This module defines the configuration objects that control:

  • Which channels to capture (analog and digital)

  • Sample rates and other analog settings

  • Capture duration and trigger settings

Classes#

CaptureConfig#

@dataclass
class CaptureConfig:
    enabled_channels: list[ChannelConfig]
    analog_settings: Optional[AnalogSettings] = None
    capture_settings: Optional[CaptureSettings] = None

The main configuration object for captures. A capture must have at least one enabled channel, and should include either analog_settings or capture_settings if a capture other than the defaults below is desired.

Parameters:

  • enabled_channels: List of analog and digital channels to capture

  • analog_settings: Optional analog capture settings (defaults to device maximum sample rate and DROP mode)

  • capture_settings: Optional capture settings (defaults to 1ms timed capture)

Methods:

You likely won’t need to use these, they are used behind the scenes to persist CaptureConfig objects in human-readable JSON in capture directories.

  • to_dict: Converts configuration to device format that the capture binary understands

    def to_dict(self, output_dir: Path, mso_part_number: MsoPodPartNumber) -> Dict[str, Any]:
    
  • to_dir: Writes a full configuration to several files in a given directory

    def to_dir(self, output_dir: Path, mso_part_number: MsoPodPartNumber) -> Path:
    
  • from_dir: Reads a configuration from a given directory

    @classmethod
    def from_dir(cls, dir_path: Path) -> "CaptureConfig":
    

AnalogChannel#

@dataclass
class AnalogChannel:
    channel: int
    name: Optional[str] = None
    center_voltage: float = 0.0
    voltage_range: float = 10.0
    probe_attenuation: ProbeAttenuation = ProbeAttenuation.PROBE_10X  # Default to the 10x probe included with the MSO
    coupling: Coupling = Coupling.DC
    bandwidth_mhz: BandwidthLimit = BandwidthLimit.MHz_350

Represents an analog channel configuration.

Parameters:

  • channel: The channel number (0-based index)

  • name: Optional descriptive name for the channel (defaults to “CH_volts”)

  • center_voltage: Center voltage for the channel (default: 0.0V)

  • voltage_range: Voltage range for the channel (default: 10.0V)

  • probe_attenuation: Probe attenuation setting (default: 1x)

  • coupling: Coupling type (default: DC)

  • bandwidth_mhz: Bandwidth limit (default: 350MHz)

DigitalChannel#

@dataclass
class DigitalChannel(ChannelConfig):
    channel: int
    name: Optional[str] = None
    port: Optional[int] = None
    threshold_volts: Optional[float] = None
    minimum_pulse_width_samples: Optional[int] = None

Represents a digital channel configuration.

Parameters:

  • channel: The channel number (0-based index)

  • name: Optional descriptive name for the channel (defaults to “P_CH_logic”)

  • port: The port number for the digital channel (required)

  • threshold_volts: Voltage threshold for digital signal detection (default: None, uses global threshold)

  • minimum_pulse_width_samples: Minimum pulse width in samples to filter out noise (default: None)

Note: Digital channels require a port number to be specified. All digital channels on the same port share the same voltage threshold, so setting threshold_volts on one channel will apply to all channels on that port.

AnalogSettings#

@dataclass
class AnalogSettings:
    downsample_mode: DownsampleMode = DownsampleMode.AVERAGE
    sample_rate: float = 1_600_000_000  # Defaults to 1.6 GSPS

Configures analog capture settings.

Parameters:

  • downsample_mode: How to handle downsampling (default: AVERAGE)

  • sample_rate: The sample rate in Hz (default: 1.6GS/s)

TimedCapture#

@dataclass
class TimedCapture(CaptureSettings):
    capture_length_seconds: float

Configures a capture based on duration.

Parameters:

  • capture_length_seconds: How long to capture in seconds

AnalogTriggered#

@dataclass
class AnalogTriggered(CaptureSettings):
    trigger: EdgeTrigger
    pre_trigger_seconds: float = 0.0005
    post_trigger_seconds: float = 0.0005
    timeout_seconds: float = 1.0

Configures a capture triggered by an analog signal reaching a specific threshold. See the trigger documentation for more information on configuring a trigger.

Parameters:

  • trigger: The trigger settings

  • pre_trigger_seconds: Time before trigger to capture (default: 0.5ms)

  • post_trigger_seconds: Time after trigger to capture (default: 0.5ms)

  • timeout_seconds: Maximum time to wait for trigger before throwing a timeout error (default: 1.0s)

Enums#

ProbeAttenuation#

If you are using the probes included with your Logic MSO, leave this attenuation setting at Probe10x which is the default. Those probes attenuate the signal by 10x inherently. If you are connecting a signal directly to the input of your Logic MSO with e.g. the BNC adapter and coaxial cable, then use the Probe1x setting to inform the MSO it will be receiving more signal per ADC count.

class ProbeAttenuation(Enum):
    PROBE_10X = "Probe10x"  # default, use this when using the probes included with MSO
    PROBE_1X = "Probe1x"

DownsampleMode#

class DownsampleMode(Enum):
    DROP = "Drop"
    AVERAGE = "Average"

Example Capture Configurations#

from pathlib import Path
from saleae import mso_api
from saleae.mso_api.part_number import MsoPodPartNumber as PN


# Capture 100ms of data in a timed capture on 2 analog channels and 4 digital ones
config1 = mso_api.CaptureConfig(
    enabled_channels=[
        mso_api.AnalogChannel(channel=0, name="clock", center_voltage=2.0, voltage_range=5.0),
        mso_api.AnalogChannel(channel=1, name="data", center_voltage=2.0, voltage_range=5.0),
        mso_api.DigitalChannel(port=0, channel=0, name="MISO", threshold_volts=1.5),
        mso_api.DigitalChannel(port=0, channel=1, name="MOSI"),
        mso_api.DigitalChannel(port=0, channel=2, name="CLK"),
        mso_api.DigitalChannel(port=0, channel=3, name="CS")
    ],
    analog_settings=mso_api.AnalogSettings(
        downsample_mode=mso_api.DownsampleMode.AVERAGE,
        sample_rate=100e6
    ),
    capture_settings=mso_api.TimedCapture(capture_length_seconds=0.1)
)

# Trigger a capture on the rising edge of an analog channel at full sample rate (default)
config2 = mso_api.CaptureConfig(
    enabled_channels=[
        # signals directly connected via coax must be set to 1x attenuation mode
        mso_api.AnalogChannel(
            channel=0, name="clock",
            probe_attenuation=mso_api.ProbeAttenuation.PROBE_1X
        ),
        mso_api.AnalogChannel(
            channel=1, name="signal",
            probe_attenuation=mso_api.ProbeAttenuation.PROBE_1X
        ),
    ],
    capture_settings=mso_api.AnalogTriggered(
        # specify by channel_name, or channel_index, both work
        trigger=mso_api.EdgeTrigger(
            channel_name="clock", threshold_volts=1.6,
            direction=mso_api.EdgeTriggerDirection.RISING
        ),
        # capture 1/2 millisecond of data on either side of the trigger
        pre_trigger_seconds=0.5e-3,
        post_trigger_seconds=0.5e-3,
    )
)

# running config.to_dict() or mso.capture(config, ...) will throw
# errors if the configuration is invalid
for n, config in enumerate([config1, config2], start=1):
    _ = config.to_dict(Path("my-capture-save-dir"), PN.MsoPod_4ch_200Mhz_12b_1000Ms)
    print(f"configuration #{n} is valid")
configuration #1 is valid
configuration #2 is valid