Really basic ADC C application

Applications, development tools, FPGA, C, WEB
Post Reply
hgomersall
Posts: 5
Joined: Tue May 12, 2015 7:10 pm

Really basic ADC C application

Post by hgomersall » Tue May 12, 2015 7:21 pm

I've written a little program to pull data from the ADC and push it across via UDP to a host PC. Now I can write it, and it compiles fine, but the data it outputs is wrong.

It's based on one of the examples "acquire_signal_on_fast_analog_input.c", which also doesn't do very much useful.

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include <rp.h>

#include <sys/time.h>
#include <sys/socket.h>

int main(int argc, char **argv){

	/* Print error, if rp_Init() function failed */
	if(rp_Init() != RP_OK){
		fprintf(stderr, "Rp api init failed!\n");
	}
	
	uint32_t array_size = 3 * 1024; //Current buffer size. 

	float *buff = (float *)malloc(array_size * sizeof(float));

	/* Starts acquisition */
    rp_AcqSetSamplingRate(RP_SMP_125M);
	rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
    rp_AcqSetTriggerLevel(0.5);

    rp_pinState_t gain_state = RP_HIGH;
    rp_AcqSetGain(RP_CH_1, gain_state);
    rp_AcqSetGain(RP_CH_2, gain_state);

    struct timeval t1, t2;
    double elapsedTime;
    int loops = 100;
    gettimeofday(&t1, NULL);

    rp_AcqStart();
    /* Get the whole buffer into buf */
    rp_AcqGetLatestDataV(RP_CH_2, &array_size, buff);
    
    gettimeofday(&t2, NULL);

    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0/loops;      // sec to ms
    elapsedTime += ((t2.tv_usec - t1.tv_usec) / 1000.0)/loops;   // us to ms
    
	int i;
	for (i = 0; i < array_size; ++i)
	{
		printf("Data: %f\n", buff[i]);
	}

    printf("%f ms\n", elapsedTime);    

	/* Releasing resources */
	free(buff);
	rp_Release();

	return 0;
}
The output is many very low values (at the bottom of the scale), not the signal I know to be on the input line.

Example output:

Code: Select all

Data: -0.041504
Data: -0.043945
Data: -0.053711
Data: -0.053711
Data: -0.029297
Data: -0.036621
Data: -0.043945
Data: -0.021973
Data: -0.043945
Data: -0.029297
Data: -0.043945
Data: -0.043945
Data: -0.043945
Data: -0.043945
I can't understand what the difficulty is. I assume that it's pretty simple...

I've checked the device is working ok by running the scope app, which works just fine.

Any assistance is much appreciated.

Cheers,
Henry

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

Re: Really basic ADC C application

Post by Nils Roos » Tue May 12, 2015 8:11 pm

Hi Henry,

You set the scope to trigger on a positive transition through 0.5V on channel A and then record 24.5us from channel B, but you are not actually waiting for the trigger event to occur.
The function rp_AcqGetLatestDataV() does not wait for a trigger event, it will return old data if no trigger happened since setting the trigger parameters.

Try polling rp_AcqGetTriggerState() and read data only once it indicates RP_TRIG_STATE_TRIGGERED .

Have fun
Nils

hgomersall
Posts: 5
Joined: Tue May 12, 2015 7:10 pm

Re: Really basic ADC C application

Post by hgomersall » Wed May 13, 2015 12:02 pm

Thank you - There were various triggering issues that weren't obvious to me to start with. I managed to get the data out and it looks sort of sensible, except for one glaring issue...

If I pull off the entire buffer (16k of it), the first half is always out of sync, or contains some residual stuff. Am I right in thinking that a captured buffer is only 8k? Is this adjustable?

Cheers,

Henry

hgomersall
Posts: 5
Joined: Tue May 12, 2015 7:10 pm

Re: Really basic ADC C application

Post by hgomersall » Wed May 13, 2015 12:11 pm

Just further to my previous reply, a slightly curious thing occurs when one outputs the trigger channel. In this case, it is apparent that the value corresponding to the trigger doesn't occur right in the middle of the array, but slightly offset at a lower address (say 5 samples).

In this case, the trigger channel is still recorded for more samples back though, so my previous statement about half the array being the acquisition size seems to be not quite true (i.e. there seem to be recorded values before the middle of the array). If one only gets say the latest 1000 samples, a short trigger cannot be seen at all.

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

Re: Really basic ADC C application

Post by Nils Roos » Wed May 13, 2015 12:26 pm

The glaring issue also has a simple explanation and an easy remedy:

The buffer is filled in a circular fashion, and the trigger event does not neccessarily happen at the start of the buffer. You need to read the trigger pointer, which gives you the index of the sample in the whole buffer where the trigger event occurred.
Eg. if your trigger pointer reads 1000, data[1000] to data[16383] contain the first 15384 samples of the signal and data[0] to data[999] contain the remaining 1000 samples.

hgomersall
Posts: 5
Joined: Tue May 12, 2015 7:10 pm

Re: Really basic ADC C application

Post by hgomersall » Wed May 13, 2015 2:29 pm

Thanks Nils,

I originally though that was the solution, but the value returned from

Code: Select all

rp_AcqGetWritePointerAtTrig()
doesn't seem to be consistent with much in the resultant array.

The following code is used to produce a few plots:

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include <rp.h>

#include <sys/time.h>

#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define SERVERPORT "4950"	// the port users will be connecting to

int main(int argc, char **argv){

	/* Print error, if rp_Init() function failed */
	if(rp_Init() != RP_OK){
		fprintf(stderr, "Rp api init failed!\n");
	}
	
	uint32_t array_size = 16 * 1024; //Current buffer size. 

	float *buff = (float *)malloc(array_size * sizeof(float));

    /* Set up network stuff */
    int sockfd;
	struct addrinfo hints, *servinfo, *p;
	int rv;
	int numbytes;

	if (argc != 3) {
		fprintf(stderr,"usage: talker hostname message\n");
		exit(1);
	}

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;

	if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
		return 1;
	}

	// loop through all the results and make a socket
	for(p = servinfo; p != NULL; p = p->ai_next) {
		if ((sockfd = socket(p->ai_family, p->ai_socktype,
				p->ai_protocol)) == -1) {
			perror("talker: socket");
			continue;
		}

		break;
	}

	if (p == NULL) {
		fprintf(stderr, "talker: failed to bind socket\n");
		return 2;
	}
    /* Finished setting up network stuff */
    rp_AcqReset();

    rp_pinState_t gain_state = RP_HIGH;

    rp_AcqSetGain(RP_CH_1, gain_state);
    rp_AcqSetGain(RP_CH_2, gain_state);

    rp_AcqGetGain(RP_CH_2, &gain_state);
    if (gain_state == RP_LOW){
        printf("Low\n");
    } else {
        printf("High\n");
    }

    rp_AcqSetTriggerLevel(0.5);

	/* Starts acquisition */
    rp_AcqSetSamplingRate(RP_SMP_125M);
	rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
	rp_acq_trig_state_t state = RP_TRIG_STATE_WAITING;

    uint32_t decimation_factor;
    rp_acq_decimation_t decimation = RP_DEC_1;
    rp_AcqSetDecimation(decimation);
    rp_AcqGetDecimation(&decimation_factor);
    printf("Decimation factor: %d\n", decimation_factor);

    int32_t trigger_delay;
    rp_AcqGetTriggerDelay(&trigger_delay);
    printf("Trigger delay: %d\n", trigger_delay);
    
    int loops = 1;
    
    uint32_t write_pointer;

    for(int j=loops; j > 0; j--) {
        rp_AcqStart();    

        while (state == RP_TRIG_STATE_WAITING){
            rp_AcqGetTriggerState(&state);

            if(state == RP_TRIG_STATE_TRIGGERED){
                state = RP_TRIG_STATE_WAITING;
                printf("triggered\n");
                break;
                
            } else {
                printf("not triggered\n");
            }
        }
    }

    uint32_t get_size = array_size;
    
    printf("request size: %d\n", get_size);                
    rp_AcqGetLatestDataV(RP_CH_2, &get_size, buff);
    rp_AcqGetWritePointerAtTrig(&write_pointer);
    printf("out size: %d\n", get_size);
    printf("write pointer: %d\n", write_pointer);

    for(int n=0; n<16; n++){
        if ((numbytes = sendto(sockfd, &buff[n*1024], 1024 * sizeof(float), 0,
                        p->ai_addr, p->ai_addrlen)) == -1) {
            perror("talker: sendto");
            exit(1);
        }
    }
    
    /* free network resources */
    freeaddrinfo(servinfo);
	close(sockfd);

	/* Releasing red pitaya resources */
	free(buff);
	rp_Release();



	return 0;
}
The data is pushed across a UDP connection to a python script from where I can plot the arrays.

The two plots below show the case when I grab 8192 samples:
Image
and 16384 samples:
Image.

The right hand side of the 16384 plot is the same as the 8192 plot. The pulses should all be equally spaced. The peak just about in the centre is always there, as is the one in the right half of the plot, so I assume they are the ones aligned with the trigger.

The left edge doesn't align with the right, so it's not a simple wrapping issue, but it does change between captures. I can't quite see what the left half the plot does, though curiously, the samples to the immediate left of the centre peak are clearly part of the same capture.

Does this clarify the issue?

Many thanks!

hgomersall
Posts: 5
Joined: Tue May 12, 2015 7:10 pm

Re: Really basic ADC C application

Post by hgomersall » Thu May 14, 2015 11:59 am

Further clarification, the value provided by

Code: Select all

rp_AcqGetWritePointerAtTrig
doesn't seem to have much relation to the trigger values.

Kilroy
Posts: 29
Joined: Thu Feb 19, 2015 11:03 am
Location: Moenchengladbach, Germany
Contact:

Re: Really basic ADC C application

Post by Kilroy » Mon May 18, 2015 10:59 am

The value returned is the write pointer at the time the trigger event occurs. But as far as I understood, that is the index in the buffer and not the index in your acquired data because you use the rp_AcqGetLatestDataV function.
Regards Uwe

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 39 guests