Triggering during fast streaming mode does not work

Post general discussions on using our drivers to write your own software here
Post Reply
IgorLopez
Newbie
Posts: 0
Joined: Sat Jul 25, 2015 2:58 pm

Triggering during fast streaming mode does not work

Post by IgorLopez »

Hi,

I am having a problem with triggering of a session running in fast streaming mode.
The app is set up to capture both channels on my PicoScope 2204A where I would like the capturing to start as soon I get the first falling edge on channel B and then should it capture for 50 ms, e.g. 100000 samples using 500 ns sampletime.
The problem is that the collected data does not start with the first falling edge.

This is how the code looks like (In it are code I have for understanding how it works like counters and timestamps which can be disregarded)

Code: Select all

#define _GNU_SOURCE

/* Headers for Linux */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* Definition of PS2000 driver routines on Linux */
#include 

#define __stdcall
#define Sleep(x) usleep(1000*(x))
enum BOOL {FALSE,TRUE};

/* End of Linux-specific definitions */

typedef enum {
	MODEL_NONE = 0,
  MODEL_PS2104 = 2104,
	MODEL_PS2105 = 2105,
	MODEL_PS2202 = 2202,
	MODEL_PS2203 = 2203,
	MODEL_PS2204 = 2204,
	MODEL_PS2205 = 2205
} MODEL_TYPE;

typedef struct
{
	PS2000_THRESHOLD_DIRECTION	channelA;
	PS2000_THRESHOLD_DIRECTION	channelB;
	PS2000_THRESHOLD_DIRECTION	channelC;
	PS2000_THRESHOLD_DIRECTION	channelD;
	PS2000_THRESHOLD_DIRECTION	ext;
} DIRECTIONS;

typedef struct
{
	PS2000_PWQ_CONDITIONS					*	conditions;
	int16_t														nConditions;
	PS2000_THRESHOLD_DIRECTION		  direction;
	uint32_t										lower;
	uint32_t										upper;
	PS2000_PULSE_WIDTH_TYPE					type;
} PULSE_WIDTH_QUALIFIER;


typedef struct
{
	PS2000_CHANNEL channel;
	float threshold;
	int16_t direction;
	float delay;
} SIMPLE;

typedef struct
{
	int16_t hysterisis;
	DIRECTIONS directions;
	int16_t nProperties;
	PS2000_TRIGGER_CONDITIONS * conditions;
	PS2000_TRIGGER_CHANNEL_PROPERTIES * channelProperties;
	PULSE_WIDTH_QUALIFIER pwq;
 	uint32_t totalSamples;
	int16_t autoStop;
	int16_t triggered;
} ADVANCED;


typedef struct
{
	SIMPLE simple;
	ADVANCED advanced;
} TRIGGER_CHANNEL;

typedef struct {
	int16_t DCcoupled;
	int16_t range;
	int16_t enabled;
} CHANNEL_SETTINGS;

typedef struct  {
	int16_t handle;
	MODEL_TYPE model;
  PS2000_RANGE firstRange;
	PS2000_RANGE lastRange;
	TRIGGER_CHANNEL trigger;
	int16_t maxTimebase;
	int16_t timebases;
	int16_t noOfChannels;
	CHANNEL_SETTINGS channelSettings[PS2000_MAX_CHANNELS];
	int16_t				hasAdvancedTriggering;
	int16_t				hasFastStreaming;
	int16_t				hasEts;
	int16_t				hasSignalGenerator;
} UNIT_MODEL;

UNIT_MODEL unitOpened;
uint16_t calBackFinished = 0; // call back semaphore,
uint32_t calBackCounter = 0;
uint32_t loopCounter1 = 0;
uint32_t loopCounter2 = 0;

#define BUFF_SIZE 100000
int16_t SCLData[BUFF_SIZE];
int16_t SDAData[BUFF_SIZE];
int16_t SCLDataLog[BUFF_SIZE];
int16_t SDADataLog[BUFF_SIZE];
clock_t calBackTimestamp[5000];
clock_t loopTimestampBefore[5000];
clock_t loopTimestampAfter[5000];
uint32_t sampleBuff[5000];
void __stdcall ps2000FastStreamingReady(int16_t **overviewBuffers, int16_t overflow, uint32_t triggerdAt, int16_t triggered, int16_t auto_stop, uint32_t nValues)
{
	//memcpy(&(SCLData[unitOpened.trigger.advanced.totalSamples]), overviewBuffers[0], nValues*sizeof(SCLData[0]));
	//memcpy(&(SDAData[unitOpened.trigger.advanced.totalSamples]), overviewBuffers[1], nValues*sizeof(SDAData[0]));
	unitOpened.trigger.advanced.totalSamples += nValues;
	unitOpened.trigger.advanced.autoStop = auto_stop;
	calBackFinished = 1;
	if (5000 > calBackCounter) {
		calBackTimestamp[calBackCounter] = clock();
		sampleBuff[calBackCounter] = nValues;
		calBackCounter++;
	}
}


int main(int argc, char **argv)
{
	int32_t ok;
	int16_t overflow;
	int16_t triggered;
	uint32_t triggerAt;
	clock_t firstBlockTime;
	clock_t lastBlockTime;
	int16_t firstCaptured = 0;
	PS2000_CHANNEL chan;
	double startTime = 0;
	double duration_us;

	loopTimestampBefore[0] = clock();
	loopTimestampAfter[0] = clock();
	loopCounter1++;
	calBackTimestamp[0] = clock();
	sampleBuff[0] = 0;
	calBackCounter++;

	unitOpened.trigger.advanced.autoStop = 0;
	unitOpened.trigger.advanced.totalSamples = 0;

	for (chan=PS2000_CHANNEL_A; chan <= PS2000_CHANNEL_B; chan++) {
		unitOpened.channelSettings[chan].enabled = TRUE;
		unitOpened.channelSettings[chan].DCcoupled = TRUE;
		unitOpened.channelSettings[chan].range = PS2000_5V;
	}
	unitOpened.handle = ps2000_open_unit();
	if (0 < unitOpened.handle) {
		ok = ps2000_set_ets(unitOpened.handle, PS2000_ETS_OFF, 0, 0);
		if (0 == ok) {
			fprintf(stdout, "ETS is disabled\n");
		} else {
			fprintf(stdout, "failed to disable ETS with call ps2000_set_ets\n");
		}
		for (chan=PS2000_CHANNEL_A; chan <= PS2000_CHANNEL_B; chan++) {
			ok = ps2000_set_channel(unitOpened.handle, chan, unitOpened.channelSettings[chan].enabled, unitOpened.channelSettings[chan].DCcoupled, unitOpened.channelSettings[chan].range);
			if (0 == ok) {
				fprintf(stdout, "function call ps2000_set_channel for channel %d failed\n", chan);
			}
		}
		ok = ps2000_set_trigger(unitOpened.handle, PS2000_CHANNEL_B, 500, PS2000_FALLING, 0, 0);
		if (0 == ok) {
			fprintf(stdout, "function call: ps2000_set_trigger failed\n");
		}
		ok = ps2000_run_streaming_ns(unitOpened.handle, 500, PS2000_NS, BUFF_SIZE, TRUE, 1, BUFF_SIZE);
		if (0 == ok) {
			fprintf(stdout, "function call: ps2000_run_streaming_ns failed\n");
		}
		while(0 == unitOpened.trigger.advanced.autoStop) {
			ok = 0;
			if (5000 > loopCounter1) {
				loopTimestampBefore[loopCounter1]=clock();
			}
			calBackFinished = 0;
			while(0 == ok) {
				ok = ps2000_get_streaming_last_values(unitOpened.handle, ps2000FastStreamingReady);
				loopCounter2++;
			}
			if (0 == firstCaptured) {
				firstBlockTime = clock();
				firstCaptured = 1;
			}
			if (5000 > loopCounter1) {
				loopTimestampAfter[loopCounter1]=clock();
				loopCounter1++;
			}
		}
		lastBlockTime = clock();
		duration_us = 1000000*((double) (lastBlockTime - firstBlockTime))/CLOCKS_PER_SEC;
		ps2000_stop(unitOpened.handle);
		ps2000_get_streaming_values_no_aggregation(unitOpened.handle, &startTime, SCLDataLog, SDADataLog, NULL, NULL, &overflow, &triggerAt, &triggered, BUFF_SIZE);
		// Write data to file

		// Close the unit
		ps2000_close_unit(unitOpened.handle);
	} else {
		fprintf(stdout, "function call ps2000_open_unit failed\n");
	}
}
and my buffers have data with proper sampletime but not correct starting point, e.g. SDADataLog should always start with a low section

Hitesh

Re: Triggering during fast streaming mode does not work

Post by Hitesh »

Hi Igor,

In streaming mode, data collection begins as soon as the ps2000_run_streaming_ns function is called.

If you require only the post-trigger samples, you should be able to use the delay parameter in the ps2000_set_trigger function in order to capture the post-trigger samples in the driver.

Once data collection is complete, you can call the ps2000_get_streaming_values_no_aggregation or ps2000_get_streaming_values in order to retrieve the data from the driver.

If you need to collect data by copying data out using the callback, you will need to ignore any pre-trigger samples. I would also suggest looking at the example in the SDK for Windows OS platforms as this shows how to collect data using the streaming callback.

Regards,

IgorLopez
Newbie
Posts: 0
Joined: Sat Jul 25, 2015 2:58 pm

Re: Triggering during fast streaming mode does not work

Post by IgorLopez »

Hi Hitesh,

I have already set the delay to 0 and auto_trigger_ms to 0 like this:

Code: Select all

ok = ps2000_set_trigger(unitOpened.handle, PS2000_CHANNEL_B, 500, PS2000_FALLING, 0, 0);
ps2000_set_trigger from doc:

Code: Select all

delay, the delay, as a percentage of the requested number of data
points, between the trigger event and the start of the block. It
should be in the range -100% to +100%. Thus, 0% means that the
trigger event is at the first data value in the block, and -50% means
that it is in the middle of the block. If you wish to specify the delay
as a floating-point value,
auto_trigger_ms, the delay in milliseconds after which the
oscilloscope will collect samples if no trigger event occurs. If this is
set to zero the oscilloscope will wait for a trigger indefinitely.
The reason I need to have the streaming triggered is that I want to start the application running on my PC and then issue a command on my raspberry PI (sudo i2cdetect -y 1) in order to test my I2C slave which currently does not ACK and I want to see how the SDA look like when the PI (I2C master) is addressing my slave. And the only way to get this with my PicoScope is to capture the whole 50 ms it takes for the PI to go through all addresses and then search for my slaves address. I can detect when the PI starts query the slaves by the first falling edge on the SDA pin.
I guess another approach is to use the callback and check if triggered is set and then start copying captured data to the buffers. Will try this but I did have problems with my first attempt using the callback (I have commented out the memcpy statements) and instead used the ps2000_get_streaming_values_no_aggregation function once streaming stopped.

Hitesh

Re: Triggering during fast streaming mode does not work

Post by Hitesh »

Hi Igor,

Please find below the code used for the streaming callback in the PicoScope 2000 Series Windows SDK C Console example:

Code: Select all

/****************************************************************************
 *
 * Streaming callback
 *
 * This demonstrates how to copy data to application buffers
 *
 ****************************************************************************/
void  __stdcall ps2000FastStreamingReady2( int16_t **overviewBuffers,
											int16_t overflow,
											uint32_t triggeredAt,
											int16_t triggered,
											int16_t auto_stop,
											uint32_t nValues)
{
	int16_t channel = 0;

	unitOpened.trigger.advanced.totalSamples += nValues;
	unitOpened.trigger.advanced.autoStop = auto_stop;

	g_triggered = triggered;
	g_triggeredAt = triggeredAt;

	g_overflow = overflow;

	if(nValues > 0 && g_appBufferFull == 0) 
	{
		for(channel = (int16_t) PS2000_CHANNEL_A; channel < DUAL_SCOPE; channel++)
		{
			if(bufferInfo.unit.channelSettings[channel].enabled)
			{
				if(unitOpened.trigger.advanced.totalSamples <= bufferInfo.bufferSizes[channel * 2] && !g_appBufferFull)
				{
					g_nValues = nValues;
				}
				else if(g_startIndex < bufferInfo.bufferSizes[channel * 2])
				{
					g_nValues = bufferInfo.bufferSizes[channel * 2] - (g_startIndex + 1); // Only copy data into application buffer up to end
					unitOpened.trigger.advanced.totalSamples = bufferInfo.bufferSizes[channel * 2]; // Total samples limited to application buffer
					g_appBufferFull = 1;
				}
				else
				{
					// g_startIndex might be >= buffer length
					g_nValues = 0;
					unitOpened.trigger.advanced.totalSamples = bufferInfo.bufferSizes[channel * 2];
					g_appBufferFull = 1;
				}

				// Copy data...

				// Max buffers
				if(overviewBuffers[channel * 2] && bufferInfo.appBuffers[channel * 2])
				{
					memcpy_s((void *) (bufferInfo.appBuffers[channel * 2] + g_startIndex), g_nValues * sizeof(int16_t), 
									(void *) (overviewBuffers[channel * 2]), g_nValues * sizeof(int16_t));

				}

				// Min buffers
			
				if(overviewBuffers[channel * 2 + 1] && bufferInfo.appBuffers[channel * 2 + 1])
				{
					memcpy_s((void *) (bufferInfo.appBuffers[channel * 2 + 1] + g_startIndex), g_nValues * sizeof(int16_t), 
									(void *) (overviewBuffers[channel * 2 + 1]), g_nValues * sizeof(int16_t));
				}
			}

		}

		g_prevStartIndex = g_startIndex;
		g_startIndex = unitOpened.trigger.advanced.totalSamples;
	}
}
This requires a large array to be set up for each channel (don't forget max/min if using aggregation) so that data can be copied into it in the callback. The driver by design collects some samples with the callback function indicating that data is available, and then while the data collection loop in the main program is executing, receive a very small number of samples.

Below is code from the main program:

Code: Select all

// Simple trigger, 500mV, rising
	ok = ps2000_set_trigger(unitOpened.handle, PS2000_CHANNEL_A, 
		mv_to_adc(500, unitOpened.channelSettings[PS2000_CHANNEL_A].range), PS2000_RISING, 0, 0);

	unitOpened.trigger.advanced.autoStop = 0;
	unitOpened.trigger.advanced.totalSamples = 0;
	unitOpened.trigger.advanced.triggered = 0;

	//Reset global values
	g_nValues = 0;
	g_triggered = 0;
	g_triggeredAt = 0;
	g_startIndex = 0;
	g_prevStartIndex = 0;
	g_appBufferFull = 0;

	bufferInfo.unit = unitOpened;

	// Allocate memory for data arrays

	// Max A buffer at index 0, min buffer at index 1
	bufferInfo.appBuffers[PS2000_CHANNEL_A * 2] = (int16_t *) calloc(appBufferSize, sizeof(int16_t));
	bufferInfo.bufferSizes[PS2000_CHANNEL_A * 2] = appBufferSize;

	if(unitOpened.channelSettings[PS2000_CHANNEL_B].enabled)
	{
		// Max B buffer at index 2, min buffer at index 3
		bufferInfo.appBuffers[PS2000_CHANNEL_B * 2] = (int16_t *) calloc(appBufferSize, sizeof(int16_t));
		bufferInfo.bufferSizes[PS2000_CHANNEL_B * 2] = appBufferSize;
	}

	/* Collect data at 10us intervals
	* 100000 points with an aggregation of 100 : 1
	*	Auto stop after the 100000 samples
	*  Start it collecting,
	*/
	//ok = ps2000_run_streaming_ns ( unitOpened.handle, 10, PS2000_US, NUM_STREAMING_SAMPLES, 1, 100, overviewBufferSize );

	/* Collect data at 1us intervals
	* 1000000 points after trigger with 0 aggregation
	* Auto stop after the 1000000 samples
	* Start it collecting,
	* NOTE: The actual sampling interval used by the driver might not be that which is specified below. Use the sampling intervals
	* returned by the ps2000_get_timebase function to work out the most appropriate sampling interval to use. As these are low memory
	* devices, the fastest sampling intervals may result in lost data.
	*/
	ok = ps2000_run_streaming_ns ( unitOpened.handle, 1, PS2000_US, NUM_STREAMING_SAMPLES, 1, 1, overviewBufferSize ); // No aggregation
	
	printf ( "OK: %d\n", ok );

	/* From here on, we can get data whenever we want...*/	
	
	while (!_kbhit() && !unitOpened.trigger.advanced.autoStop && !g_appBufferFull)
	{
		ps2000_get_streaming_last_values (unitOpened.handle, ps2000FastStreamingReady2);
		
		if (nPreviousValues != unitOpened.trigger.advanced.totalSamples)
		{
			sample_count = unitOpened.trigger.advanced.totalSamples - nPreviousValues;
			
			//Printing to console can take up resources
			//printf ("Values collected: %ld, Total samples: %ld ", sample_count, unitOpened.trigger.advanced.totalSamples);
			
			/*if(g_triggered)
			{
				printf("Triggered at index: %lu, overall %lu", g_triggeredAt, nPreviousValues + g_triggeredAt);
			}*/

			nPreviousValues = unitOpened.trigger.advanced.totalSamples;
			//printf("\n");

			if(g_appBufferFull)
			{
				unitOpened.trigger.advanced.totalSamples = appBufferSize;
				printf("\nApplication buffer full - stopping data collection.\n");
			}
			
		}
		
	}

	ps2000_stop (unitOpened.handle);
Hope this helps.

Post Reply