Api: When do I have to call acqStart/AcqReset()

Applications, development tools, FPGA, C, WEB
8lu3
Posts: 30
Joined: Thu Feb 25, 2016 7:05 pm

Api: When do I have to call acqStart/AcqReset()

Post by 8lu3 » Tue Mar 22, 2016 4:56 pm

Hello,
in which situation do I have to call rp_AcqReset(), rp_AcqStart()? Just once, before every call of setTriggerSrc or whenever changes like setDecimation oder setTriggerLevel are made?

thank you

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Api: When do I have to call acqStart/AcqReset()

Post by Nils Roos » Tue Mar 22, 2016 9:52 pm

You need to call rp_AcqStart() in order to resume recording after a trigger event was registered (and once at the start).

rp_AcqReset() resets most acquisition parameters to default values, so you probably just want to call it once at the very beginning.

8lu3
Posts: 30
Joined: Thu Feb 25, 2016 7:05 pm

Re: Api: When do I have to call acqStart/AcqReset()

Post by 8lu3 » Tue Mar 22, 2016 11:59 pm

Just to be sure:
When acq_Start() is called, the fpga waits until a given trigger event happens. Then trigger state is set to 'triggered' and the fpga begins to acquire fresh samples until the buffer is filled.
Right?

This code is from the example 'acquire_trigger_software':

Code: Select all

uint32_t buff_size = 16384;
        float *buff = (float *)malloc(buff_size * sizeof(float));

        rp_AcqReset();
        rp_AcqSetDecimation(1);
        rp_AcqSetTriggerLevel(0.1); //Trig level is set in Volts while in SCPI 
        rp_AcqSetTriggerDelay(0);

        rp_AcqStart();

        /* After acquisition is started some time delay is needed in order to acquire fresh samples in to buffer*/
        /* Here we have used time delay of one second but you can calculate exact value taking in to account buffer*/
        /*length and smaling rate*/

        sleep(1);
        rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW);
        rp_acq_trig_state_t state = RP_TRIG_STATE_TRIGGERED;

        while(1){
                rp_AcqGetTriggerState(&state);
                if(state == RP_TRIG_STATE_TRIGGERED){
                sleep(1);
                break;
                }
        }

        rp_AcqGetOldestDataV(RP_CH_1, &buff_size, buff);
I have some questions about it:
Why is sleep called between rp_AcqStart and rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW)?
Is it possible to reverse the order?
When is trigger source set to 'TRIGGER_SRC_DISABLED'?
What happens when I load acquired data with rp_AcqGetOldestDataV(RP_CH_1, &buff_size, buff), before the buffer is filled with fresh samples?
Like it could happen (at least I think so) if I remove sleep(1) from the while-loop:

Code: Select all

while(1){
                rp_AcqGetTriggerState(&state);
                if(state == RP_TRIG_STATE_TRIGGERED){
                break;
                }
        }
        rp_AcqGetOldestDataV(RP_CH_1, &buff_size, buff);
And I guess setting the Trigger_Level doesn't make sense when using TRIGGER_SRC_NOW, right?

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Api: When do I have to call acqStart/AcqReset()

Post by Nils Roos » Wed Mar 23, 2016 2:09 pm

When acq_Start() is called, the fpga waits until a given trigger event happens. Then trigger state is set to 'triggered' and the fpga begins to acquire fresh samples until the buffer is filled.
Right?
Not quite. When rp_AcqStart() is called, the oscilloscope starts writing samples into its internal buffers immediately, while waiting for the trigger-condition to be met. Once a trigger is recognized, the oscilloscope logic continues to record as many samples as you programmed with rp_AcqSetTriggerDelay(). After this number of samples has been recorded, it resets the trigger source register to RP_TRIG_SRC_DISABLED.
I have some questions about it:
Why is sleep called between rp_AcqStart and rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW)?
Is it possible to reverse the order?
When is trigger source set to 'TRIGGER_SRC_DISABLED'?
This should be clear from the above.

In my opinion, the example code is not a good demonstration of how to use the oscilloscope API. You'd rather program the amount of data you want with rp_AcqSetTriggerDelay(), then call rp_AcqStart() and rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW) - no sleep neccessary here. Then just wait for the trigger-source to return to RP_TRIG_SRC_DISABLED. Putting a sleep() or usleep() into this loop is prudent to avoid totally blocking the core the code is running on.
What happens when I load acquired data with rp_AcqGetOldestDataV(RP_CH_1, &buff_size, buff), before the buffer is filled with fresh samples?
Like it could happen (at least I think so) if I remove sleep(1) from the while-loop:
In the case of this example, it could indeed happen like you said. You would then read old or invalid samples. It could also happen that you read data while it is being updated, in which case you'd get a mix of old and new samples.
And I guess setting the Trigger_Level doesn't make sense when using TRIGGER_SRC_NOW, right?
Indeed.

8lu3
Posts: 30
Joined: Thu Feb 25, 2016 7:05 pm

Re: Api: When do I have to call acqStart/AcqReset()

Post by 8lu3 » Wed Mar 23, 2016 5:20 pm

Nils Roos wrote:
When acq_Start() is called, the fpga waits until a given trigger event happens. Then trigger state is set to 'triggered' and the fpga begins to acquire fresh samples until the buffer is filled.
Right?
Not quite. When rp_AcqStart() is called, the oscilloscope starts writing samples into its internal buffers immediately, while waiting for the trigger-condition to be met. Once a trigger is recognized, the oscilloscope logic continues to record as many samples as you programmed with rp_AcqSetTriggerDelay(). After this number of samples has been recorded, it resets the trigger source register to RP_TRIG_SRC_DISABLED.
Hmm. The documentation says
When acquiring is started, the FPGA waits for the trigger condition on the specified source and when the condition is met, it starts writing the signal to the buffer.
http://libdoc.redpitaya.com/rp_8h.html# ... eece37bf62 .
I took a closer look into the api source. It seems like the fpga is using a circular buffer. Thus, the latest sample should be at pos and the oldest sample should be at pos+1 (where pos is the write pointer), right?
I've run this small program:

Code: Select all

int main(){
	if(rp_Init() != RP_OK){
		fprintf(stderr, "Rp api init failed!\n");
		return 0;
	}
	rp_AcqReset();
	uint32_t pos;
	int k = 3;
	while(k>0){
		usleep(10);
		--k;
		rp_AcqGetWritePointer(&pos);
		printf("pos: %d\n",pos);
	}
	rp_AcqStart();
	printf("start\n");
	k=3;
	while(k>0){
		usleep(10);
		--k;
		rp_AcqGetWritePointer(&pos);
		printf("pos: %d\n",pos);
	}
	rp_Release();
}
}
It produces following strange output:

Code: Select all

LD_LIBRARY_PATH=/opt/redpitaya/lib ./test
pos: 5233
pos: 7119
pos: 6789
start
pos: 1228
pos: 2901
pos: 9314
At least the first three positions should be equal, shouldn't they?

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Api: When do I have to call acqStart/AcqReset()

Post by Nils Roos » Wed Mar 23, 2016 5:46 pm

Hmm. The documentation says ...
Let me put it this way: the API and its documentation both still have room for improvements.

When questions of this kind arise, I usually look into the source to come up with an answer.
I took a closer look into the api source. It seems like the fpga is using a circular buffer. Thus, the latest sample should be at pos and the oldest sample should be at pos+1 (where pos is the write pointer), right?
Yes. As a sidenote: be aware that the write pointer keeps moving as long as the oscilloscope is waiting for a trigger.
At least the first three positions should be equal, shouldn't they?
That depends on what you have been doing before. It was already found that rp_AcqReset() is not really resetting the state of the oscilloscope - see this post, and read on for a work-around.

8lu3
Posts: 30
Joined: Thu Feb 25, 2016 7:05 pm

Re: Api: When do I have to call acqStart/AcqReset()

Post by 8lu3 » Wed Mar 23, 2016 7:33 pm

So, when I want to acquire 16384 samples I call rp_AcqSetTriggerDelay(16384). When trigger source turns to disabled all samples are acquired and I can read them by calling rp_AcqGetLatestDataV(channel, &buff_size, buffer) (where buff_size = 16384), ok? (For size = 16384 it doesn't matter if one calls getLatest or getOldest)
I extended my test program a little bit:

Code: Select all

int main(){
	if(rp_Init() != RP_OK){
		fprintf(stderr, "Rp api init failed!\n");
		return 0;
	}
	rp_AcqReset();
	//rp_AcqSetTriggerDelay(1);					//scope is allready stopped, since program exits with stopped scope
	//rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW);
	uint32_t pos, tr_pos;
	rp_acq_trig_src_t src = 0;
	rp_acq_trig_state_t state = 0;
	int k = 3;
	while(k>0){
		usleep(10);
		--k;
		rp_AcqGetWritePointerAtTrig(&tr_pos);
		rp_AcqGetWritePointer(&pos);
		rp_AcqGetTriggerSrc(&src);
		rp_AcqGetTriggerState(&state);
		printf("pos: %d; pos when triggered: %d; trigger source: %d; trigger state: %d\n",pos, tr_pos, src, state);
	}
	rp_AcqSetTriggerDelay(16384);
	printf("start\n");
	rp_AcqStart();
	k=3;
	while(k>0){
		usleep(10);
		--k;
		rp_AcqGetWritePointerAtTrig(&tr_pos);
		rp_AcqGetWritePointer(&pos);
		rp_AcqGetTriggerSrc(&src);
		rp_AcqGetTriggerState(&state);
		printf("pos: %d; pos when triggered: %d; trigger source: %d; trigger state: %d\n",pos, tr_pos, src, state);
	}
	printf("trigger\n");
	rp_AcqSetTriggerSrc(RP_TRIG_SRC_NOW);
	k=3;
	while(k>0){
		usleep(1);
		--k;
		rp_AcqGetWritePointerAtTrig(&tr_pos);
		rp_AcqGetWritePointer(&pos);
		rp_AcqGetTriggerSrc(&src);
		rp_AcqGetTriggerState(&state);
		printf("pos: %d; pos when triggered: %d; trigger source: %d; trigger state: %d\n",pos, tr_pos, src, state);
	}
	//scope is not acquiring samples to buffer anymore ->'stopped'
	rp_Release();
}
It generates the following output:

Code: Select all

pos: 0; pos when triggered: 0; trigger source: 0; trigger state: 1
pos: 0; pos when triggered: 0; trigger source: 0; trigger state: 1
pos: 0; pos when triggered: 0; trigger source: 0; trigger state: 1
start
pos: 11261; pos when triggered: 0; trigger source: 0; trigger state: 1
pos: 740; pos when triggered: 0; trigger source: 0; trigger state: 1
pos: 11715; pos when triggered: 0; trigger source: 0; trigger state: 1
trigger
pos: 11759; pos when triggered: 7207; trigger source: 1; trigger state: 0
pos: 15401; pos when triggered: 7207; trigger source: 0; trigger state: 1
pos: 15401; pos when triggered: 7207; trigger source: 0; trigger state: 1
One can see how the buffer is filled and the scope then stops to acquire fresh samples.
But shouldn't the position be 15401 when the trigger event happend (instead of 7207) or do I mistake rp_AcqGetWritePointerAtTrig(&tr_pos)?
Last edited by 8lu3 on Wed Mar 23, 2016 10:01 pm, edited 1 time in total.

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Api: When do I have to call acqStart/AcqReset()

Post by Nils Roos » Wed Mar 23, 2016 8:27 pm

The output of your program puzzled me at first, until I noticed that rp_SetTriggerDelay() adds 8192 to its parameter internally.
So you'd do rp_setTriggerDelay(8191); if you wanted to record 16384 samples after the trigger.
But shouldn't the position be 15402 when the trigger event happend (instead of 7207) or do I mistake rp_AcqGetWritePointerAtTrig(&tr_pos)?
The other way round, the write position should stop at 7206 (provided you set the trigger delay as explained above).

8lu3
Posts: 30
Joined: Thu Feb 25, 2016 7:05 pm

Re: Api: When do I have to call acqStart/AcqReset()

Post by 8lu3 » Wed Mar 23, 2016 10:01 pm

Ok, that makes more sense now.
But, I'm not sure if I understand it fully.
I think the write_pointer points to the latest sample.
rp_AcqGetLatestDataV copies buffer values from (pos-len) to (pos-1). But, it think the buffer values (pos-len+1) to pos have to be copied, since pos refers to the latest sample.
Furthermore, I don't understand why it's 7207 and not 7209, as 15401-7207 is 8194 and not 8192.

Do you know the reason why there is a trigger delay offset?

And I guess bypassing the trigger delay offset has some bad side-effects?
Bypassing will reduce the time used for acquiring the samples drastically. So, it would be nice if bypassing is possible without any disadvantages.

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Api: When do I have to call acqStart/AcqReset()

Post by Nils Roos » Thu Mar 24, 2016 11:27 pm

Do you know the reason why there is a trigger delay offset?
No, but if I had to guess I would say it is done to have an equal amount of pre- and post-trigger samples in the default case.
Bypassing will reduce the time used for acquiring the samples drastically.
What makes you think that ?
The trigger delay only controls the position of the window of acquired samples in relation to the trigger event. The offset just shifts the position of this window for a given value, and you can counteract it by eg. setting a negative trigger delay.

Post Reply
jadalnie klasyczne ekskluzywne meble wypoczynkowe do salonu ekskluzywne meble tapicerowane ekskluzywne meble do sypialni ekskluzywne meble włoskie

Who is online

Users browsing this forum: No registered users and 90 guests