3.2 Stream Mode [T-Series Datasheet]
Stream Mode Overview
Streaming is a fast data input mode. It is more complicated than command-response mode, so it requires more configuration. Using stream is simplified by the LJM stream functions; to stream without them, see Low-Level Streaming below.
For a given stream session, a list of channels/addresses are sampled as input to the device. This list of channels (known as a scan list) is input, as quickly as possible, immediately after a clock pulse. Stream clock pulses are hardware-timed at a constant scan rate. By default, a stream session begins scanning immediately after being started and continuously scans until stopped.
A LabJack device cannot run more than one stream session at any given time.
Command-response can be done while a stream is active, but streaming needs exclusive control of the analog input system, so analog inputs (including the internal temperature sensor) cannot be read via command-response while a stream is active.
Stream can also output data.
Stream sessions can be configured to collect a limited number of scans. (See Burst Stream)
The T7 and T8 support some advanced stream features:
Stream sessions can be configured to delay scanning until after the device detects a trigger pulse.
Stream clock pulses can also be read externally at either a constant or a variable rate. *T7 Only
Maximum Stream Speed
The maximum stream speed and requirements to achieve the maximum speed varies by device.
Stream-In and/or Stream-Out
There are three input/output combinations of stream mode:
Stream-in: The device collects data and streams it to the host.
Stream-out: The device does not collect data but does outputs data. See Stream-Out below.
Stream-in-out: The device collects data and streams it to the host. It also streams data out.
The stream channels determine which of these modes are used. Streamable channels may be either stream-in or stream-out.
Streamable Registers
The Modbus Map shows which registers can be streamed (by expanding the "details" area). Input registers that can be streamed include:
AIN# | See 14.0 Analog Inputs. |
FIO_STATE | See 13.0 Digital I/O. |
EIO_STATE | See 13.0 Digital I/O. |
CIO_STATE | See 13.0 Digital I/O. |
MIO_STATE | See 13.0 Digital I/O. |
FIO_EIO_STATE | See 13.0 Digital I/O. |
EIO_CIO_STATE | See 13.0 Digital I/O. |
CIO_MIO_STATE | See 13.0 Digital I/O. |
DIO#(0:22) | See 13.0 Digital I/O. |
DIO#(0:22)_EF_READ_A | |
DIO#(0:22)_EF_READ_A_AND_RESET | |
DIO#(0:22)_EF_READ_B | |
CORE_TIMER | |
SYSTEM_TIMER_20HZ | |
STREAM_DATA_CAPTURE_16 | See below. |
Stream Data Framing
Stream data is returned channel interleaved by scan. A scan consists of a sample from every channel in the scan list. For example, if you have a scan list of [AIN0, AIN1, AIN2]
data will be returned like the following:
[AIN0Sample1, AIN1Sample1, AIN2Sample1, AIN0Sample2, AIN1Sample2, AIN2Sample2, ... AIN0SampleN, AIN1SampleN, AIN2SampleN]
Data from every AIN channel will be returned in each scan when using a device that samples its analog inputs simultaneously. See the Simultaneous Sampling section for more information.
Digital Only Stream
On some T-series devices it is possible to stream digital channels without any AIN channels in the scan list. This is referred to as a digital only stream.
16-bit or 32-bit Data
Stream data is transferred as 16-bit values, but 32-bit data can be captured by using STREAM_DATA_CAPTURE_16:
16-bit
In the normal case of an analog input such as AIN0, the 16-bit binary value is actually is what is transferred. LJM converts it to a float on the host using the calibration constants that LJM reads before starting the stream. To read binary AIN stream data, enable the LJM configuration LJM_STREAM_AIN_BINARY by setting it to 1.
32-bit
Some streamable registers (e.g. DIO4_EF_READ_A) have 32-bit data. When streaming a register that produces 32-bit data, the lower 16 bits (LSW) will be returned and the upper 16 bits (MSW) will be saved in STREAM_DATA_CAPTURE_16. To get the full 32-bit value, add STREAM_DATA_CAPTURE_16 to the stream scan list after any applicable 32-bit register, then combine the two values in software (LSW + 65536*MSW). Note that STREAM_DATA_CAPTURE_16 may be placed in multiple locations in the scan list.
Configuring AIN for Stream
STREAM_SETTLING_US and STREAM_RESOLUTION_INDEX control settling and resolution during stream.
The normal AIN configuration registers for range and negative channel still apply to stream.
T7 only: Stream mode is not supported on the hi-res converter. (Resolution indices 9-12 are not supported in stream.)
Stream Timing
When using LJM, there are three ways that stream can be too slow:
Sample rate is too high
Device buffer overflow
LJM buffer overflow
Sample rate is too high: When the sample rate is too high, it causes a STREAM_SCAN_OVERLAP error and stream is terminated.
Scans are triggered by hardware interrupts. If a scan begins and the previous scan has not finished, the device stops streaming and returns a STREAM_SCAN_OVERLAP error (errorcode 2942), which LJM returns immediately upon the next call to LJM_eStreamRead.
Device buffer overflow: When the device buffer overflows, LJM inserts a dummy sample (with the value -9999.0) in place of each skipped sample, or it causes a STREAM_AUTO_RECOVER_END_OVERFLOW error and stream is terminated.
As samples are collected, they are placed in a FIFO ring buffer on the device until retrieved by the host. The size of the buffer is variable and can be set to a maximum of 32768 bytes. Write to STREAM_BUFFER_SIZE_BYTES to allocate memory for the buffer. The stream buffer will be allocated within shared memory. Because we use a ring buffer, two bytes of the allocated space is required to track the number of samples in the buffer, and as a result the usable buffer size will be equal to the value of STREAM_BUFFER_SIZE_BYTES minus 2 bytes.
If the device buffer overflows, the device will continue streaming but will discard data until the buffer is emptied, after which data will be stored in the buffer again. The device keeps track of how many scans are discarded and reports that value. Based on the number of scans discarded, the LJM library adds the proper number of dummy samples (with the value -9999.0) such that the correct timing is maintained. This will only work if the first channel in the scan cannot return 0xFFFF.
If the device buffer overflows for too much time, a STREAM_AUTO_RECOVER_END_OVERFLOW error occurs and stream is terminated.
If the device buffer is overflowing, see the LJM stream help page for some mitigation strategies.
LJM buffer overflow: When the LJM buffer overflows, it causes a LJME_LJM_BUFFER_FULL error and stream is terminated.
LJM reads samples from the device buffer and buffers them internally. LJM reads these samples in an internal thread, regardless of what your code does. LJM's buffer can run out of space if it is not read often enough using LJM_eStreamRead, so make sure the LJMScanBacklog parameter does not continually increase.
LJM_eStreamRead blocks until enough data is read from the device, so your code does not need to perform waits.
If the LJM buffer is overflowing, see the LJM stream help page for some mitigation strategies.
Channel-to-Channel (Interchannel) Timing
Channels in a scan list are input or output as quickly as possible after the start of a scan, in the order of the scan list.
For descriptions of typical interchannel delays, see Appendix A-1 Data Rates.
Timing pulses are generated on SPC so that the channel-to-channel timing can be measured. Pulses on SPC are as follows:
Falling edge at the start of a scan.
Rising edge at the start of a sample.
Falling edge at the end of a sample.
Rising edge at the end of a scan.
Device Clock Scan Time
To calculate the time a scan was collected relative to the device clock, multiply the scan's offset from the first scan with the interval length. The interval length is the inverse of the scan rate:
TimeSinceFirstScan = Offset * (1 / ScanRate)
For example, with a 500 Hz scan rate, the 1000th scan collected is 2 seconds after the first scan, according to the device clock.
You can use STREAM_START_TIME_STAMP to relate the start of stream with other events:
System Clock Scan Time
With writing custom code, you can assign timestamps to each stream scan. These timestamps can be the host computer's system time (calendar time) or the steady clock (absolute) time. These timestamps are based on the computer's real-time clock rather than the device's clock.
Assigning a timestamp to each scan can be beneficial for logging and for multi-device synchronization. It can also help to correct clock drift between your system clock and the device clock.
Using this technique it is realistic that the time accuracy of every scan's timestamp is within 1 ms of your system's clock, unless suboptimal conditions apply, such as asymmetric network routes or network congestion.
Example Technique:
First, start stream. Then read the following registers using normal command-response.
Once stream is started, use STREAM_START_TIME_STAMP to determine when stream started,hen read CORE_TIMER in order to correlate scan times with system host clock times:
Read the CORE_TIMER and your system time quickly in a loop for e.g. five times. You can assume the CORE_TIMER value is, on average, halfway between when you begin the CORE_TIMER read and when you receive the CORE_TIMER value. Throw out any measurements that take an abnormal amount of time. (If most round-trip reads of CORE_TIMER take 1 ms and one CORE_TIMER read takes 3 ms, it's likely that either the outbound or inbound communication had an unusual delay—but unlikely that both had an equal delay.)
Next, calculate the CORE_TIMER value for each scan. Use the actual scan rate to calculate the CORE_TIMER value for each scan starting from STREAM_START_TIME_STAMP. If you're using LJM, LJM_eStreamStart returns the actual scan rate in the ScanRate parameter, which can be slightly different from the specified scan rate. If you're not using LJM, see low-level streaming below.
Once you have your current system clock correlated with CORE_TIMER and each scan is assigned a CORE_TIMER value, you can convert each CORE_TIMER value into a system clock time.
Additional considerations:
Make sure your code handles when the CORE_TIMER rolls over.
If you're assigning wall-clock timestamps, consider what should happen when the clock skips forward or backward due to an NTP update.
To prevent clock drift, you must continually re-synchronize the system clock to CORE_TIMER. The T-series clock error at room temperature is 20 ppm. This is 2 ms per 100 seconds, so a re-sync of core-clock to host-clock must be done at least every 50 seconds to maintain 1 ms accuracy.
Check your own computer's clock specs for a source of additional clock error.
Burst Stream
Burst stream is when stream collects a pre-determined number of scans, then stops. To set the stream burst size, write to STREAM_NUM_SCANS:
The LJM library collects burst stream data with the StreamBurst function.
It may be beneficial to set STREAM_BUFFER_SIZE_BYTES to a large value for fast burst stream. See above for details about STREAM_BUFFER_SIZE_BYTES.
T7-Pro only: Burst stream is well-suited for WiFi connections, because WiFi has a lower throughput than other connection types.
Externally Clocked Stream - T7/T8
Externally-clocked stream allows T-series devices to stream from external pulses. It also allows for variable stream scan rates.
Clock Source
The scan rate is generated from the internal crystal oscillator. Alternatively, the scan rate can be a division of an external clock provided on CIO3.
To subdivide the external clock pulses for a slower scan rate, use STREAM_EXTERNAL_CLOCK_DIVISOR.
To use externally clocked stream with LJM, see the externally clocked stream section of the LJM User's Guide.
Using a DIO_EF as a Clock Source
One option to generate a stream clock is to use the PWM DIO_EF. The clock signal from a single PWM output could be shared between multiple devices. For example, configure a 50 kHz output with 50% duty cycle on the FIO0 terminal of one LabJack. Jumper FIO0 to CIO3 for use with externally clocked stream. The following pseudocode demonstrates the configuration that is required:
STREAM_CLOCK_SOURCE = 2 # Configure externally clocked stream on CIO3
DIO_EF_CLOCK0_ENABLE = 0
DIO_EF_CLOCK0_DIVISOR = 1 # No divisor, the base clock is 80 MHz on the T7
DIO_EF_CLOCK0_ROLL_VALUE = 1600 # 80 MHz / 1600 = 50 kHz output
DIO_EF_CLOCK0_ENABLE = 1
DIO0_EF_ENABLE = 0
DIO0_EF_INDEX = 0 # PWM output on FIO0/DIO0
DIO0_EF_OPTIONS = 0 # Use DIO_EF_CLOCK0 (50kHz output configured above)
DIO0_EF_CONFIG_A = 800 # 800 / 1600 = 50% duty cycle
DIO0_EF_ENABLE = 1
Triggered Stream - T7/T8
T7 minimum firmware 1.0186
T8 minimum firmware 1.021
Stream can be configured to start scanning when a trigger is detected. Trigger sources are DIO_EF modes:
Frequency In (requires two edges to trigger)
Pulse Width In (requires two edges in either direction to trigger)
Conditional Reset (requires one edge to trigger)
Frequency In and Conditional Reset allow you to select rising or falling edges and Pulse Width In will trigger from either edge.
See Appendix A for hysteresis voltage information.
Configuring stream to use a trigger requires setting up a DIO_EF and adding the STREAM_TRIGGER_INDEX register to normal stream configuration. Note that it is not necessary to set any DIO_EF_CONFIG registers; it is only necessary to change the index and enable the feature.
STREAM_TRIGGER_INDEX (address 4024):
0 = No trigger. Stream will start when Enabled.
2000 = DIO_EF0 will start stream.
2001 = DIO_EF1 will start stream.
2002 = DIO_EF2 will start stream.
2003 = DIO_EF3 will start stream.
2006 = DIO_EF6 will start stream.
2007 = DIO_EF7 will start stream.
The delay between the trigger and the first collected sample is one scan period.
To use triggered stream with LJM, see the triggered stream section of the LJM User's Guide.
A more complicated stream trigger can be implemented with a Lua script. For example, a Lua script could check for an arbitrary stream trigger condition in conjunction with triggered stream being started as normal. Once the Lua script detects that the stream condition is fulfilled, it writes a pulse to a digital out (such as DIO3) which is then detected by the normal trigger (as specified by STREAM_TRIGGER_INDEX).
Stream Out
Stream-out is a set of streamable registers that move data from a buffer to an output. The output can be digital I/O (DIO) or a DAC. The buffer can be read linearly to generate a irregular waveform or be read in a looping mode to generate a periodic waveform.
A T-series device can output up to 4 waveforms using stream-out.
In terms of timing and data rates, stream-out channels count the same as input channels so see the normal documentation of Streaming Data Rates.
Alternate waveform generation techniques are described in the Waveform Generation App Note.
The stream out waveform only resets when the stream out channel is reset. This allows the stream to be stopped and started again to begin stream out from where the waveform left off. To restart a stream out from the beginning of the waveform after stopping stream, stream out can be reconfigured.
Performing Stream-Out Using LJM
LJM's stream-out functions simplify the use of stream-out. They are available in LJM 1.2100 and later.
To output a periodic waveform from the device, use LJM_PeriodicStreamOut.
To output an irregular waveform, use LJM_InitializeAperiodicStreamOut and LJM_WriteAperiodicStreamOut.
Performing Stream-Out Manually (Advanced)
For each waveform being streamed out:
Choose which target channel will output the waveform
Configure stream-out
STREAM_OUT#(0:3)_TARGET
STREAM_OUT#(0:3)_BUFFER_ALLOCATE_NUM_BYTES
STREAM_OUT#(0:3)_ENABLE
Update the stream-out buffer
STREAM_OUT#(0:3)_LOOP_NUM_VALUES
STREAM_OUT#(0:3)_BUFFER_F32 or STREAM_OUT#(0:3)_BUFFER_U16
STREAM_OUT#(0:3)_SET_LOOP
Start stream with STREAM_OUT#(0:3) in the scan list
Stream loop: read and update buffer as needed
Stop stream
Executing stream-out for multiple output waveforms is a matter of performing the above steps in the order above and using corresponding STREAM_OUT#(0:3) addresses in the scan list.
Target Selection
The following target list represents the I/O on the device that can be configured to output a waveform using stream-out. The list includes the analog and digital output lines.
DAC0
DAC1
FIO_STATE
FIO_DIRECTION
EIO_STATE
EIO_DIRECTION
CIO_STATE
CIO_DIRECTION
MIO_STATE
MIO_DIRECTION
The above listed digital IO registers use the higher byte as an inhibit mask. Bits set in the inhibit mask will prevent the corresponding DIO from being changed. For example, writing a value of 0xFAFF to FIO_STATE will set FIO0 and FIO2 to high. FIO1 and FIO3-7 will remain unchanged.
Digital IO registers (FIO_STATE, EIO_STATE, CIO_STATE, MIO_STATE) do not configure direction. Use the corresponding _DIRECTION register (FIO_DIRECTION, EIO_DIRECTION, CIO_DIRECTION, MIO_DIRECTION) to configure direction. This can be done either before or during stream.
Configure Stream-Out
Configuration will set the buffer size and target. The target specifies which physical I/O to use. Data in the buffer will be output onto the target I/O as a generated waveform.
Configuration can be done before or after stream has started.
Update Buffer
Each stream-out has its own buffer. Data is loaded into the buffer by writing to the appropriate buffer register. Output waveform data points are stored in the buffer as 16-bit values, so values greater than 16-bits will be converted automatically before being stored in the buffer. Use only one buffer per STREAM_OUT channel.
For outputting an analog waveform (DAC output), write an array of floating-point numbers to the STREAM_OUT#(0:3)_BUFFER_F32 register.
For outputting a digital waveform, pass an array of integer 0 or 1 values to the STREAM_OUT#(0:3)_BUFFER_U16 register.
Once the waveform data points are stored, configure STREAM_OUT#(0:3)_LOOP_NUM_VALUES and STREAM_OUT#(0:3)_SET_LOOP.
Start Stream
Next, start stream with STREAM_OUT#(0:3) in the scan list.
The order of STREAM_OUT#(0:3) in the scan list determines when the target updated. For example, if STREAM_OUT3 is before STREAM_OUT0 in the scan list, STREAM_OUT3_TARGET will be updated before STREAM_OUT0_TARGET.
Stream Loop
Read from stream, if there are stream-in channels.
Also, if the output waveform needs to be updated, read STREAM_OUT#(0:3)_BUFFER_STATUS to determine when to write new values to the buffer. When to write values depends on how large the buffer is and how many values need to be written.
For a more thorough description of how a Stream-Out buffer works, see the Stream-Out Description below.
Stop Stream
Stopping a stream that streams out is no different from stopping stream-in.
Example
This example demonstrates how to configure DAC0 to output an analog waveform that resembles a triangle wave, and also quickly measure two analog inputs AIN0 and AIN2 in streaming context.
Configuration steps specific to stream-out
STREAM_OUT0_ENABLE = 0 → Turn off just in case it was already on.
STREAM_OUT0_TARGET = 1000 → Set the target to DAC0.
STREAM_OUT0_BUFFER_ALLOCATE_NUM_BYTES = 512 → A buffer to hold up to 256 values.
STREAM_OUT0_ENABLE = 1 → Turn on Stream-Out0.
With the LJM library, write these registers with a call to eWriteNames or multiple calls to eWriteName.
General stream configuration
STREAM_SCANLIST_ADDRESS0= AIN0 → Add AIN0 to the list of things to stream in.
STREAM_SCANLIST_ADDRESS1= STREAM_OUT0 → Add STREAM_OUT0 (DAC0 is target) to the list of things to stream-out.
STREAM_SCANLIST_ADDRESS2= AIN2 → Add AIN2 to the list of things to stream in.
STREAM_ENABLE = 1 → Start streaming.
LJM_eStreamStart does this.
With the LJM library, this is all done with the call to eStreamStart.
Other settings related to streaming analog inputs have been omitted here but are covered under the section for stream mode.
Load the waveform data points
The following data points have been chosen to produce the triangle waveform: 0.5V, 1V, 1.5V, 1V, so the next step is to write these datum to the appropriate buffer. Because it is a DAC output (floating point number), use the STREAM_OUT0_BUFFER_F32 register.
STREAM_OUT0_BUFFER_F32 = [0.5, 1, 1.5, 1] → Write the four values one at a time or as an array.
STREAM_OUT0_LOOP_NUM_VALUES = 4 → Loop four values.
STREAM_OUT0_SET_LOOP = 1 → Begin using new data set immediately.
With the LJM library, write the array using eWriteNameArray, and write the other 2 values with a call to eWriteNames or multiple calls to eWriteName.
Observe result with stream mode
Every time the stream is run, AIN0 is read, then DAC0 is updated with a data point from Stream-Out0's buffer, then AIN2 is read. Thus, the streaming speed dictates the frequency of the output waveform.
Sequential Data
Once a sequence of values has been set via the STREAM_OUT#_SET_LOOP register, that sequence of values will loop and only be interrupted at the end of the sequence. Therefore, to have stream-out continuously output a sequence of values that is larger than the size of one stream-out buffer, probably the easiest way to do so is to:
1. Start by dividing the stream-out buffer into 2 halves,
2. Write one half of the buffer with your sequential data,
3. In a loop, every time the STREAM_OUT#_BUFFER_STATUS reads as being half full/empty, write another half buffer-worth of values.
Note that the buffer is a circular array, so you could end up overwriting values if you're not careful.
Here's an example:
Stream-out buffer is 512 bytes, divide that by 2 to get the number of samples the buffer can hold => 256 samples
256 samples divided by 2 to get the "loop" size, AKA the set-of-data-to-be-written-at-a-time size => 128 samples
Write 128 samples:
Write 128 to STREAM_OUT0_LOOP_NUM_VALUES
Write 128 samples to STREAM_OUT0_BUFFER_F32 (This should probably be done by array write, which is much faster than writing values individually.)
Write 1 to STREAM_OUT0_SET_LOOP
Loop while you have more sequential data to write:
Read STREAM_OUT0_BUFFER_STATUS
If STREAM_OUT0_BUFFER_STATUS is 128 or greater, write the next 128 samples, along with STREAM_OUT0_LOOP_NUM_VALUES = 128 and STREAM_OUT0_SET_LOOP = 1
Sleep for something like 1 / scanRate seconds to prevent unnecessary work for the hardware
Maximum Speed Estimations
T4: With 1 channel and a looping waveform, stream-out can perform at 40 kHz.
T7: With 1 channel and a looping waveform, stream-out can perform at 100 kHz. When streaming out to DACs at high speeds, you may notice effects of the time constant, depending on the output waveform.
T8: With 1 channel and a looping waveform, stream-out can perform at 20 kHz.
For more information, see maximum stream speeds.
Stream-Out Description
Low-Level Stream
Stream mode is complicated but can easily be executed using the high-level LJM stream functions. LJM is recommend for all users, except users that need to integrate a T-series device into a system that cannot use LJM. The rest of this section is about manually executing stream protocol without LJM.
Executing stream mode involves the following:
Stream setup
Stream start
Stream-in data collection, if any stream includes stream-in channels
Stream-out buffer updates, if stream includes stream-out channels (See the Stream-Out section)
Stream stop
Spontaneous Stream vs. Command-Response Stream:
Data can be sent to the host in one of two data collection modes:
Spontaneous: In spontaneous mode, packets are automatically sent to the host as soon as there is enough data to fill a packet. The packet size is adjustable. See the register definitions below.
Command-Response (CR): In CR mode, the stream data is stored in the device’s buffer and must be read out using a command. CR mode is useful for when the connection is unreliable.
T-series devices connected via either USB and Ethernet are capable of both spontaneous stream and command-response stream.
T7-Pro only: T7-Pro devices connected via WiFi are capable of only command-response stream.
Setup
Manual stream setup requires configuration of the registers that LJM_eStreamStart automatically configures:
Additional Configuration Notes
Additionally, address 4018 (STREAM_DATATYPE) must be written with the value 0. Note that address 4018 (STREAM_DATATYPE) is not in ljm_constants.json and is not compatible with LJM_NameToAddress.
STREAM_ENABLE must be written last.
Stream Burst
Writing a non-zero value to the register STREAM_NUM_SCANS will cause the device to automatically stop sending stream data after a certain number of scans. We commonly refer to this noncontinuous stream-mode acquisition as a stream burst.
After STREAM_NUM_SCANS scans have been acquired, the device will no longer scan new data and the status/error STREAM_BURST_COMPLETE will be returned from the LabJack. Upon receiving STREAM_BURST_COMPLETE, stream should be fully disabled by writing 0 to STREAM_ENABLE.
In most cases, STREAM_NUM_SCANS should not be configured when using LJM. LJM will set STREAM_NUM_SCANS when using StreamBurst.
Data Collection
Spontaneous Stream: Once stream has been initiated with STREAM_ENABLE, the device sends data to the target indicated by STREAM_AUTO_TARGET until STREAM_ENABLE is written with the value 0. Stream-out streams that do not contain stream-in channels (see above) do not send data.
Modbus Feedback Spontaneous Packet Protocol:
Bytes 0-1: Transaction ID
Bytes 2-3: Protocol ID
Bytes 4-5: Length, MSB-LSB
Bytes 6: 1 (Unit ID)
Byte 7: 76 (Function #)
Byte 8: 16
Byte 9: Reserved
Bytes 10-11: Backlog Bytes
Bytes 12-13: Status Code
Byte 14-15: Additional status information
Byte 16+: Stream Data (raw sample = 2 bytes MSB-LSB)
Command-Response Stream: When collecting data using command-response stream mode, data must be read from STREAM_DATA_CR (address 4500). Data is automatically discarded as it is read.
Modbus Feedback Command-Response Packet Protocol:
Bytes 0-1: Transaction ID
Bytes 2-3: Protocol ID
Bytes 4-5: Length, MSB-LSB
Bytes 6: 1 (Unit ID)
Byte 7: 76 (Function #)
Bytes 8-9: Number of samples in this read
Bytes 10-11: Backlog Bytes
Bytes 12-13: Status Code
Byte 14-15: Additional status information
Byte 16+: Stream Data (raw sample = 2 bytes MSB-LSB)
Backlog Bytes:
Backlog Bytes is the number bytes contained in the device stream buffer after reading. To convert BacklogBytes to the number of scans still on the device:
BacklogScans = BacklogBytes / (bytesPerSample * samplesPerScan)
Where bytesPerSample is 2 and samplesPerScan is the number of channels.
Status Codes:
2940: Auto-recovery Active.
2941: Auto-recovery End. Additional Status Information is the number of scans skipped. A scan consisting of all 0xFFFF values indicates the separation between old data and new data.
2942: Scan Overlap
2943: Auto-recovery End Overflow
2944: Stream Burst Complete
Stop
To stop stream, write 0 to STREAM_ENABLE. All stream modes expect to be stopped, except for burst stream (see STREAM_NUM_SCANS for more information on bust stream).
Code Example
A general low-level stream example written in C/C++ can be found here.
Simultaneous Sampling - T8 Only
The T8 is the only T-series device that samples its analog inputs simultaneously, all other T-series devices sample sequentially.
There are two ways to sample multiple analog inputs: sequentially or simultaneously. When sampling sequentially, each AIN is sampled one after another. The time between sequential samples creates a phase delay in the data. This phase difference can result in errors when comparing two signals such as voltage and current. When sampling simultaneously, the analog inputs will be sampled at the same time and rate, thereby eliminating the phase difference and any associated errors.
Simultaneous AIN Captures when Streaming
AIN#_CAPTURE
registers are not streamable, however all simultaneously sampled AIN behave
similar to AIN#_CAPTURE
registers when streaming; the stream scan timing determines when new simultaneous AIN readings are captured. New AIN samples always get captured precisely at the start of the stream scan.
Operational Differences Between Simultaneous and Sequential Sampling
Simultaneously sampled stream has a few important operational differences from sequentially sampled stream.
The first time a request for a new analog input reading (AIN0-7) is encountered, the data for all 8 analog inputs will be loaded into the data-buffer.
If there is any AIN in the stream scan list, stream data will contain samples from all of the AIN channels. As a result, more than one AIN in the low-level stream scan list will result in an error. However, our high-level LJM library will accept any number of AIN in the aScanList parameter for eStreamStart and process them internally such that the low-level scan list is trimmed to a single AIN. Calling eStreamRead will return trimmed data in the order that AIN registers are placed in the scan list for
eStreamStart
.Because the stream scan timing always determines when the AIN readings are captured, you can only acquire one sample from each AIN in a stream scan and the AIN are always sampled simultaneously. For example, if you have an LJM scan list of
[AIN0, AIN1, AIN2]
LJM will return simultaneously captured readings from AIN0, AIN1, and AIN2 in each scan.Reading fewer analog input channels does not result in faster scan rates. Each scan collects data from all analog inputs and places the samples in the data buffer. If some analog inputs do not appear in the scan list passed to LJM, they will be discarded. There is no benefit in terms of device loading or data throughput.
The LJM Library is currently required to stream from devices that perform simultaneous sampling.