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.
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.
1. 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.
2. 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.
Stream-Out Configuration
Name |
Start Address |
Type |
Access |
STREAM_OUT#(0:3)_TARGET
Channel that data will be written to. Before writing data to _BUFFER_###, you must write to _TARGET so the device knows how to interpret and store values.
|
4040 |
UINT32 |
R/W
|
STREAM_OUT#(0:3)_TARGET
- Starting Address: 4040
Channel that data will be written to. Before writing data to _BUFFER_###, you must write to _TARGET so the device knows how to interpret and store values.
- Data type: UINT32 (type index = 1)
-
Readable and writable
- Default value: 0
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0_TARGET,
STREAM_OUT1_TARGET,
STREAM_OUT2_TARGET,
STREAM_OUT3_TARGET
Show All
|
4040,
4042,
4044,
4046
Show All
|
|
STREAM_OUT#(0:3)_BUFFER_ALLOCATE_NUM_BYTES
Size of the buffer in bytes as a power of 2. Should be at least twice the size of updates that will be written and no less than 32. Before writing data to _BUFFER_###, you must write to _BUFFER_ALLOCATE_NUM_BYTES to allocate RAM for the data. Max is 16384.
|
4050 |
UINT32 |
R/W
|
STREAM_OUT#(0:3)_BUFFER_ALLOCATE_NUM_BYTES
- Starting Address: 4050
Size of the buffer in bytes as a power of 2. Should be at least twice the size of updates that will be written and no less than 32. Before writing data to _BUFFER_###, you must write to _BUFFER_ALLOCATE_NUM_BYTES to allocate RAM for the data. Max is 16384.
- Data type: UINT32 (type index = 1)
-
Readable and writable
- Default value: 0
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0_BUFFER_ALLOCATE_NUM_BYTES,
STREAM_OUT1_BUFFER_ALLOCATE_NUM_BYTES,
STREAM_OUT2_BUFFER_ALLOCATE_NUM_BYTES,
STREAM_OUT3_BUFFER_ALLOCATE_NUM_BYTES
Show All
|
4050,
4052,
4054,
4056
Show All
|
|
STREAM_OUT#(0:3)_ENABLE
When STREAM_OUT#_ENABLE is enabled, the stream out target is generally updated by one value from the stream out buffer per stream scan. For example, there will generally be one instance of e.g. STREAM_OUT0 in the stream scan list, which will cause one STREAM_OUT0_BUFFER value to be consumed and written to STREAM_OUT0_TARGET for every stream scan. The stream scan list could also contain two instances of STREAM_OUT0, in which case two values from STREAM_OUT0_BUFFER value would be consumed and written for every stream scan.
|
4090 |
UINT32 |
R/W
|
STREAM_OUT#(0:3)_ENABLE
- Starting Address: 4090
When STREAM_OUT#_ENABLE is enabled, the stream out target is generally updated by one value from the stream out buffer per stream scan. For example, there will generally be one instance of e.g. STREAM_OUT0 in the stream scan list, which will cause one STREAM_OUT0_BUFFER value to be consumed and written to STREAM_OUT0_TARGET for every stream scan. The stream scan list could also contain two instances of STREAM_OUT0, in which case two values from STREAM_OUT0_BUFFER value would be consumed and written for every stream scan.
- Data type: UINT32 (type index = 1)
-
Readable and writable
- Default value: 0
- This register uses system RAM. The maximum RAM is 64KB. For more information, see 4.4 RAM
-
T7:
Constant |
Value |
DISABLED |
0 |
ENABLED |
1 |
Expanded Names |
Addresses |
STREAM_OUT0_ENABLE,
STREAM_OUT1_ENABLE,
STREAM_OUT2_ENABLE,
STREAM_OUT3_ENABLE
Show All
|
4090,
4092,
4094,
4096
Show All
|
|
Configuration can be done before or after stream has started.
3. 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.
Stream-Out Buffers
Name |
Start Address |
Type |
Access |
STREAM_OUT#(0:3)_BUFFER_U16
Data destination when sending 16-bit integer data. Each value uses 2 bytes of the stream-out buffer. This register is a buffer.
|
4420 |
UINT16 |
W
|
STREAM_OUT#(0:3)_BUFFER_U16
- Starting Address: 4420
Data destination when sending 16-bit integer data. Each value uses 2 bytes of the stream-out buffer. This register is a buffer.
- Data type: UINT16 (type index = 0)
-
Write-only
- Default value: 0
- This register is a Buffer Register
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0_BUFFER_U16,
STREAM_OUT1_BUFFER_U16,
STREAM_OUT2_BUFFER_U16,
STREAM_OUT3_BUFFER_U16
Show All
|
4420,
4421,
4422,
4423
Show All
|
|
STREAM_OUT#(0:3)_BUFFER_F32
Data destination when sending floating point data. Appropriate cal constants are used to convert F32 values to 16-bit binary data, and thus each of these values uses 2 bytes of the stream-out buffer. This register is a buffer.
|
4400 |
FLOAT32 |
W
|
STREAM_OUT#(0:3)_BUFFER_F32
- Starting Address: 4400
Data destination when sending floating point data. Appropriate cal constants are used to convert F32 values to 16-bit binary data, and thus each of these values uses 2 bytes of the stream-out buffer. This register is a buffer.
- Data type: FLOAT32 (type index = 3)
-
Write-only
- Default value: 0
- This register is a Buffer Register
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0_BUFFER_F32,
STREAM_OUT1_BUFFER_F32,
STREAM_OUT2_BUFFER_F32,
STREAM_OUT3_BUFFER_F32
Show All
|
4400,
4402,
4404,
4406
Show All
|
|
Once the waveform data points are stored, configure STREAM_OUT#(0:3)_LOOP_NUM_VALUES and STREAM_OUT#(0:3)_SET_LOOP.
4. Start Stream
Next, start stream with STREAM_OUT#(0:3) in the scan list.
Name |
Start Address |
Type |
Access |
STREAM_OUT#(0:3)
Include one or more of these registers in STREAM_SCANLIST_ADDRESS#(0:127) to trigger stream-out updates. When added to the scan list these do count against the max scan rate just like normal input addresses, but they do not return any data in the stream read.
|
4800 |
UINT16 |
R
|
STREAM_OUT#(0:3)
- Starting Address: 4800
Include one or more of these registers in STREAM_SCANLIST_ADDRESS#(0:127) to trigger stream-out updates. When added to the scan list these do count against the max scan rate just like normal input addresses, but they do not return any data in the stream read.
- Data type: UINT16 (type index = 0)
-
Read-only
- Default value: 0
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0,
STREAM_OUT1,
STREAM_OUT2,
STREAM_OUT3
Show All
|
4800,
4801,
4802,
4803
Show All
|
|
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.
5. 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.
Name |
Start Address |
Type |
Access |
STREAM_OUT#(0:3)_BUFFER_STATUS
The number of values in the buffer that are not currently being used.
|
4080 |
UINT32 |
R
|
STREAM_OUT#(0:3)_BUFFER_STATUS
- Starting Address: 4080
The number of values in the buffer that are not currently being used.
- Data type: UINT32 (type index = 1)
-
Read-only
- Default value: 0
-
T7:
Expanded Names |
Addresses |
STREAM_OUT0_BUFFER_STATUS,
STREAM_OUT1_BUFFER_STATUS,
STREAM_OUT2_BUFFER_STATUS,
STREAM_OUT3_BUFFER_STATUS
Show All
|
4080,
4082,
4084,
4086
Show All
|
|
For a more thorough description of how a Stream-Out buffer works, see 3.2.1.1 Stream-Out Description.
6. 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.
For more information, see maximum stream speeds.