All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-help] How to generate a waveform / digital output (Alexis)
@ 2010-05-30 16:14 Ettore Pedretti
  2010-05-31 10:23 ` Daniele Nicolodi
  0 siblings, 1 reply; 6+ messages in thread
From: Ettore Pedretti @ 2010-05-30 16:14 UTC (permalink / raw)
  To: xenomai

Hi,

I finally managed to return to the site where we have the National
Instruments PCI-6711 board. The old problem with analogy_ni_pcimio
seem solved. I can attach the driver and cmd_write seems to work.

I have been trying unsuccessfully to modify cmd_write to generate a
waveform. What I would like to do is to generate a sawtooth waveform
and send a digital pulse (trigger for an infrared camera) at the end
of the waveform. That should be running continuously until stopped.

I tried to modify your example "cmd_write" and the comedi programme
called "ao_waveform.c ". Many commands seem not to be implemented on
the analogy side. I tried to use the documentation on the comedi site
and the API description on the xenomai/analogy side but I got  even
more confused. It does not seem like a simple matter of exchanging
comedi_  for a4l_ as you indicated in one thread.

Do you have any example similar to ao_waveform.c I could try to modify
for my application? That would be a start. I have been unsuccessfully
searching the threads for something vaguely similar.

All the best
Ettore


-- 
Ettore Pedretti, SUPA
School of Physics and Astronomy
University of St Andrews, North Haugh,
St Andrews, Fife, KY16 9SS, Scotland
Ph: +44-1334-461666, Fax: +44-1334-463104
The University of St Andrews is a charity registered in Scotland : No SC013532


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
  2010-05-30 16:14 [Xenomai-help] How to generate a waveform / digital output (Alexis) Ettore Pedretti
@ 2010-05-31 10:23 ` Daniele Nicolodi
  2010-05-31 23:24   ` Ettore Pedretti
  0 siblings, 1 reply; 6+ messages in thread
From: Daniele Nicolodi @ 2010-05-31 10:23 UTC (permalink / raw)
  To: xenomai

[-- Attachment #1: Type: text/plain, Size: 737 bytes --]

On 30/05/10 18:14, Ettore Pedretti wrote:
> Do you have any example similar to ao_waveform.c I could try to modify
> for my application? That would be a start. I have been unsuccessfully
> searching the threads for something vaguely similar.

Hi Ettore,

I'm attaching two programs I wrote to generate waveforms with analogy.

The first, analogy-waveform, generates the points describing the
waveform in a buffer and keeps feeding the DAC with data from this
buffer in a circular way.

The second, analogy-phasemod, produces instead a phase modulated sine
wave. It would be much more complex to use the same technique, therefore
I continuously compute new data points.

I hope those examples will be useful to you.

Cheers,
-- 
Daniele


[-- Attachment #2: analogy-phasemod.c --]
[-- Type: text/plain, Size: 11945 bytes --]

/* Use an analog output subdevice with an asynchronous command to
 * generate a phase modulated sine wave. */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#include <analogy/analogy.h>

#define DEBUG(frmt, args...) fprintf(stderr, "%s:%d:%s:DEBUG: "frmt"\n" , __FILE__, __LINE__, __FUNCTION__, ##args)
#define ERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt"\n" , __FILE__, __LINE__, __FUNCTION__, ##args)
#define PERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt": %s\n" , __FILE__, __LINE__, __FUNCTION__, ##args, strerror(errno))

#ifndef PI
#define PI 3.14159265358979323846
#endif

#define WAVEFORM_SINE		1
#define WAVEFORM_SAWTOOTH	2
#define WAVEFORM_TRIANGULAR	3
#define WAVEFORM_STEPS		4

static int analogy_internal_trigger(a4l_desc_t *dsc, unsigned int subdevice, unsigned int num)
{
     a4l_insn_t insn;
     unsigned int data[1];

     memset(&insn, 0, sizeof(insn));
     insn.type = A4L_INSN_INTTRIG;
     insn.idx_subd = subdevice;
     insn.data_size = 1;
     insn.data = data;

     data[0] = num;

     return a4l_snd_insn(dsc, &insn);
}

#if 0
static int analogy_find_range(a4l_desc_t *dsc, unsigned int idx_subd, unsigned int idx_chan, 
			      unsigned long unit, double min, double max, a4l_rnginfo_t **rng)
{
     a4l_chinfo_t *chinfo;
     a4l_rnginfo_t *rnginfo;
     int i, ret;
     long lmin, lmax;
     unsigned int idx_rng = -ENOENT;

     /* initializes variables */
     lmin = (long)(min * A4L_RNG_FACTOR);
     lmax = (long)(max * A4L_RNG_FACTOR);
     if (rng != NULL)
	  *rng = NULL;

     /* retrieves the ranges count */
     ret = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chinfo);
     if (ret < 0)
	  return ret;

     for (i = 0; i < chinfo->nb_rng; i++) {

	  ret = a4l_get_rnginfo(dsc, idx_subd, idx_chan, i, &rnginfo);
	  if (ret < 0)
	       return ret;

	  if (A4L_RNG_UNIT(rnginfo->flags) == unit &&
	      rnginfo->min <= lmin && rnginfo->max >= lmax) {

	       idx_rng = i;
	       if (rng != NULL)
		    *rng = rnginfo;

	  }
     }

     return idx_rng;
}
#endif

typedef struct _waveform {
     int kind;		/* waveform kind */
     double frequency;	/* waveform frequency */
     double amplitude;	/* peak-to-peak amplitude */
     double offset;	/* offset */
} waveform_t;

typedef struct _options {
     char *filename;
     int subdevice;
     int channel;
     int nchan;
     int aref;
     int range;
     int unit;
     int freq;
     waveform_t *waveform;
} options_t;

#define FILENAME "analogy0"

void init_options(options_t *options)
{
     memset(options, 0, sizeof(options_t));
     options->filename = FILENAME;
     options->subdevice = -1;
     options->channel = 0;
     options->nchan = 1;
     options->aref = AREF_GROUND;
     options->range = -1;
     /* options->unit = A4L_RNG_VOLT_UNIT; bug in analogy */
     options->unit = A4L_RNG_NO_UNIT;
     options->freq = 100000.0;
}

void init_waveform(waveform_t *waveform)
{
     memset(waveform, 0, sizeof(waveform_t));
     waveform->kind = WAVEFORM_SINE;
     waveform->amplitude = 1.0;
     waveform->offset = 0.0;
     waveform->frequency = 1000.0;
}

int parse_options(options_t *options, waveform_t *waveform, int argc, char **argv)
{
     static struct option opts[] = {
	  { "device", 1, 0, 'd' },
	  { "subdevice", 1, 0, 's' },
	  { "channel", 1, 0, 'c' },
	  { "aref", 1, 0, 'a' },
	  { "range", 1, 0, 'r' },
	  { "frequency", 1, 0, 'f' },
	  { "waveform", 1, 0, 'w' },
	  { "offset", 1, 0, 'o' },
	  { "amplitude", 1, 0, 'a' },
	  { 0, 0, 0, 0 },
     };

     while (1) {
	  int index = 0;
	  char c = getopt_long(argc, argv, "", opts, &index);
	  
	  if (c == -1)
	       break;

	  switch (c) {
	  case 'd':
	       options->filename = optarg;
	       break;
	  case 's':
	       options->subdevice = strtoul(optarg, NULL, 0);
	       break;
	  case 'c':
	       options->channel = strtoul(optarg, NULL, 0);
	       break;
	  case 'a':
	       if (strcmp(optarg, "diff") == 0) {
		    options->aref = AREF_DIFF;
		    break;
	       }
	       if (strcmp(optarg, "ground") == 0) {
		    options->aref = AREF_GROUND;
		    break;
	       }
	       if (strcmp(optarg, "other") == 0) {
		    options->aref = AREF_OTHER;
		    break;
	       }
	       if (strcmp(optarg, "common") == 0) {
		    options->aref = AREF_COMMON;
		    break;
	       }
	       fprintf(stderr, "unknow analog reference\n");
	       exit(-1);
	       break;
	  case 'r':
	       options->range = strtoul(optarg, NULL, 0);
	       break;
	  case 'w':
	       if (strcmp(optarg, "sin") == 0) {
		    waveform->kind = WAVEFORM_SINE;
		    break;
	       }
	       if (strcmp(optarg, "saw") == 0) {
		    waveform->kind = WAVEFORM_SAWTOOTH;
		    break;
	       }
	       if (strcmp(optarg, "tri") == 0) {
		    waveform->kind = WAVEFORM_TRIANGULAR;
		    break;
	       }
	       if (strcmp(optarg, "ste") == 0) {
		    waveform->kind = WAVEFORM_STEPS;
		    break;
	       }
	       fprintf(stderr, "unknow waveform\n");
	       exit(-1);
	       break;
	       
	  case 'o':
	       waveform->offset = strtod(optarg, NULL);
	       break;

	  case 'f':
	       waveform->frequency = strtod(optarg, NULL);
	       break;

	  default:
	       fprintf(stderr, "unknown option\n");
	       exit(-1);
	  }
     }

     if (optind < argc) {
	  /* amplitude */
	  waveform->amplitude = strtod(argv[optind++], NULL);
     }

     DEBUG("frequency=%f", waveform->frequency);
     DEBUG("amplitude=%f", waveform->amplitude);
     DEBUG("offset=%f", waveform->offset);

     return argc;
}

typedef struct _generator {
     int kind;
     double frequency;	/* waveform frequency */
     double amplitude;	/* peak-to-peak amplitude in DAC units */
     double offset;	/* offset in DAC units */
     double dt;
     double t;		/* time */
} generator_t;

void generate(generator_t *gen, unsigned short *buffer, unsigned long size)
{
     double phase = 0;
     unsigned long samples = size / sizeof(unsigned short);
     //DEBUG("generate start=%p len=%ld samples=%ld", buffer, size, samples);
     for (unsigned long i = 0; i < samples; i++) {
	  //if (i < 100) {
	  //     buffer[i] = gen->offset;
	  //} else {
	       phase = sin(2*PI * gen->t);
	       buffer[i] = gen->amplitude * cos(2*PI * gen->frequency * gen->t + phase) + gen->offset;
	       gen->t += gen->dt;
	       //}
	  //fprintf(stdout, "%d\n", buffer[i]);
     }
}

int main(int argc, char **argv)
{
     unsigned int chanlist[16];

     int ret;
     options_t options;
     init_options(&options);

     waveform_t waveform;
     init_waveform(&waveform);

     parse_options(&options, &waveform, argc, argv);

     /* open device */
     int rv;
     a4l_desc_t dsc;
     rv = a4l_open(&dsc, options.filename);
     if (rv < 0) {
	  fprintf(stderr, "error opening %s\n", options.filename);
	  return -1;
     }

     DEBUG("device=%s fd=%d", options.filename, dsc.fd);
     DEBUG("subdevices=%d", dsc.nb_subd);
     DEBUG("read subdevice=%d", dsc.idx_read_subd);
     DEBUG("write subdevice=%d", dsc.idx_write_subd);

     /* subdevice */
     if (options.subdevice < 0) {
	  options.subdevice = dsc.idx_write_subd;
     }
     DEBUG("subdevice=%d", options.subdevice);

     /* allocate additional informations buffer */
     dsc.sbdata = malloc(dsc.sbsize);
     if (dsc.sbdata == NULL) {
	  ERROR("malloc");
	  return -ENOMEM;
     }

     /* get additional informations */
     rv = a4l_fill_desc(&dsc);
     if (rv < 0) {
	  ERROR("analogy fill desc");
	  goto out;
     }

     /* get channel infos */
     a4l_chinfo_t *info;
     rv = a4l_get_chinfo(&dsc, options.subdevice, options.channel, &info);
     if (rv < 0) {
	  ERROR("analogy get chinfo");
	  goto out;
     }

     /* get range */
     double min = waveform.offset - waveform.amplitude;
     double max = waveform.offset + waveform.amplitude;
     if (options.range < 0) {
	  options.range = a4l_find_range(&dsc, options.subdevice, options.channel, options.unit, min, max, NULL);
	  DEBUG("range=%d", options.range);
     }
     a4l_rnginfo_t *range;
     rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, options.range, &range);
     if (rv < 0) {
	  ERROR("analogy get rngnfo");
	  goto out;
     }

     generator_t generator;
     memset(&generator, 0, sizeof(generator));
     generator.kind = waveform.kind;
     generator.frequency = waveform.frequency;
     generator.dt = 1.0 / options.freq;

     /* physical to sample */
     unsigned short value = 0;
     double raw = 0.0;
     a4l_dtoraw(info, range, &value, &raw, 1);
     double zero = value;
     
     a4l_dtoraw(info, range, &value, &(waveform.amplitude), 1);
     generator.amplitude = value - zero;

     a4l_dtoraw(info, range, &value, &(waveform.offset), 1);
     generator.offset = value;
     
     DEBUG("amplitude=%f", generator.amplitude);
     DEBUG("offset=%f", generator.offset);

     /* setup command */
     a4l_cmd_t cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.idx_subd = options.subdevice;
     cmd.flags = A4L_CMD_WRITE;
     cmd.start_src = TRIG_INT;
     cmd.start_arg = 0;
     cmd.scan_begin_src = TRIG_TIMER;
     cmd.scan_begin_arg = 1e9 / options.freq;
     cmd.convert_src = TRIG_NOW;
     cmd.convert_arg = 0;
     cmd.scan_end_src = TRIG_COUNT;
     cmd.scan_end_arg = options.nchan;
     cmd.stop_src = TRIG_NONE;
     cmd.stop_arg = 0;
     cmd.nb_chan = 1,
     cmd.chan_descs = chanlist;

     /* setup channel description */
     chanlist[0] = PACK(options.channel, options.range, options.aref);
	       
     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);

     /* get buffer size to map */
     unsigned long bufsize;
     rv = a4l_get_bufsize(&dsc, options.subdevice, &bufsize);
     if (rv < 0) {
	  ERROR("analogy get bufsize");
	  goto out;
     }
     DEBUG("buffer size=%lu", bufsize);

     /* map analog input subdevice buffer */
     void *map = NULL;
     rv = a4l_mmap(&dsc, options.subdevice, bufsize, &map);
     if (rv < 0) {
	  ERROR("analogy mmap");
	  goto out;
     }

     /* send the command to the output device */
     rv = a4l_snd_command(&dsc, &cmd);
     if (rv < 0) {
	  ERROR("analogy snd command");
	  goto out;
     }

     /* preload output buffer */
     generate(&generator, map, bufsize);

     /* update buffer state */
     unsigned long none;
     rv = a4l_mark_bufrw(&dsc, options.subdevice, bufsize, &none);
     if (rv < 0) {
	  ERROR("analogy bufrw");
	  goto out;
     }
     
     /* send internal trigger */
     ret = analogy_internal_trigger(&dsc, options.subdevice, 0);
     if (ret < 0) {
	  ERROR("comedi_internal_trigger\n");
	  exit(1);
     }

     /* keep updating the output buffer */
     unsigned long front = 0;
     unsigned long cnt = 0;
     while (1) {
	  /* wait for device to empty buffer */
	  rv = a4l_poll(&dsc, options.subdevice, A4L_INFINITE);
	  if (rv < 0) {
	       ERROR("analogy poll");
	       goto out;
	  }
	  front = (unsigned long)rv;

	  /* handle ring buffer wrap around */
	  unsigned long tmp = front;
	  unsigned long towrite;
	  while (tmp) {
	       if (((cnt % bufsize) + tmp) > bufsize) {
		    towrite = bufsize - (cnt % bufsize);
	       } else {
		    towrite = tmp;
	       }

	       /* generate new data */
	       generate(&generator, map + (cnt % bufsize), towrite);
	       tmp -= towrite;

	       /* update counter */
	       cnt += towrite;
	  }
	  	  
	  /* update buffer state */
	  rv = a4l_mark_bufrw(&dsc, options.subdevice, front, &front);
	  if (rv < 0) {
	       ERROR("analogy bufrw");
	       goto out;
	  }
     }

out:
     /* free buffer */
     if (dsc.sbdata != NULL)
	  free(dsc.sbdata);

     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);
     
     /* close file descriptor */
     a4l_close(&dsc);
     
     return rv;
}

[-- Attachment #3: analogy-waveform.c --]
[-- Type: text/plain, Size: 13349 bytes --]

/* Use an analog output subdevice with an asynchronous command to
 * generate a waveform.
 *
 * A 32-bit accumulator is incremented by a phase factor which is the
 * amount that the generator advances each time step.  The accumulator
 * is then shifted right by 16 bits to get a 16 bit offset into a
 * lookup table.  The value in the lookup table at that offset is then
 * put into a buffer for output to the DAC.
 */

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <math.h>
#include <string.h>

#include <analogy/analogy.h>

#define DEBUG(frmt, args...) fprintf(stderr, "%s:%d:%s:DEBUG: "frmt"\n" , __FILE__, __LINE__, __FUNCTION__, ##args)
#define ERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt"\n" , __FILE__, __LINE__, __FUNCTION__, ##args)
#define PERROR(frmt, args...) fprintf(stderr, "%s:%d:%s:ERROR: "frmt": %s\n" , __FILE__, __LINE__, __FUNCTION__, ##args, strerror(errno))

#ifndef PI
#define PI 3.14159265358979323846
#endif

#define WAVEFORM_SINE		1
#define WAVEFORM_SAWTOOTH	2
#define WAVEFORM_TRIANGULAR	3
#define WAVEFORM_STEPS		4

static int analogy_internal_trigger(a4l_desc_t *dsc, unsigned int subdevice, unsigned int num)
{
     a4l_insn_t insn;
     unsigned int data[1];

     memset(&insn, 0, sizeof(insn));
     insn.type = A4L_INSN_INTTRIG;
     insn.idx_subd = subdevice;
     insn.data_size = 1;
     insn.data = data;

     data[0] = num;

     return a4l_snd_insn(dsc, &insn);
}

static int analogy_find_range(a4l_desc_t *dsc, unsigned int idx_subd, unsigned int idx_chan, 
			      unsigned long unit, double min, double max, a4l_rnginfo_t **rng)
{
     a4l_chinfo_t *chinfo;
     a4l_rnginfo_t *rnginfo;
     int i, ret;
     long lmin, lmax;
     unsigned int idx_rng = -1;

     /* initializes variables */
     lmin = (long)(min * A4L_RNG_FACTOR);
     lmax = (long)(max * A4L_RNG_FACTOR);
     if (rng != NULL)
	  *rng = NULL;

     /* retrieves the ranges count */
     ret = a4l_get_chinfo(dsc, idx_subd, idx_chan, &chinfo);
     if (ret < 0)
	  return ret;

     for (i = 0; i < chinfo->nb_rng; i++) {

	  ret = a4l_get_rnginfo(dsc, idx_subd, idx_chan, i, &rnginfo);
	  if (ret < 0)
	       return ret;

	  if (A4L_RNG_UNIT(rnginfo->flags) == unit &&
	      rnginfo->min <= lmin && rnginfo->max >= lmax) {

	       idx_rng = i;
	       if (rng != NULL)
		    *rng = rnginfo;

	  }
     }

     return idx_rng;
}

typedef struct _waveform {
     int kind;		/* waveform kind */
     double frequency;	/* waveform frequency */
     double amplitude;	/* peak-to-peak amplitude */
     double offset;	/* offset */
} waveform_t;

typedef struct _options {
     char *filename;
     int subdevice;
     int channel;
     int nchan;
     int aref;
     int range;
     int unit;
     int freq;
     waveform_t *waveform;
} options_t;

#define FILENAME "analogy0"

void init_options(options_t *options)
{
     memset(options, 0, sizeof(options_t));
     options->filename = FILENAME;
     options->subdevice = -1;
     options->channel = 0;
     options->nchan = 1;
     options->aref = AREF_GROUND;
     options->range = -1;
     /* options->unit = A4L_RNG_VOLT_UNIT; bug in analogy */
     options->unit = A4L_RNG_NO_UNIT;
     options->freq = 100000.0;
}

void init_waveform(waveform_t *waveform)
{
     memset(waveform, 0, sizeof(waveform_t));
     waveform->kind = WAVEFORM_SINE;
     waveform->amplitude = 1.0;
     waveform->offset = 0.0;
     waveform->frequency = 10.0;
}

int parse_options(options_t *options, waveform_t *waveform, int argc, char **argv)
{
     static struct option opts[] = {
	  { "device", 1, 0, 'd' },
	  { "subdevice", 1, 0, 's' },
	  { "channel", 1, 0, 'c' },
	  { "aref", 1, 0, 'a' },
	  { "range", 1, 0, 'r' },
	  { "frequency", 1, 0, 'f' },
	  { "waveform", 1, 0, 'w' },
	  { "offset", 1, 0, 'o' },
	  { "amplitude", 1, 0, 'a' },
	  { 0, 0, 0, 0 },
     };

     while (1) {
	  int index = 0;
	  char c = getopt_long(argc, argv, "", opts, &index);
	  
	  if (c == -1)
	       break;

	  switch (c) {
	  case 'd':
	       options->filename = optarg;
	       break;
	  case 's':
	       options->subdevice = strtoul(optarg, NULL, 0);
	       break;
	  case 'c':
	       options->channel = strtoul(optarg, NULL, 0);
	       break;
	  case 'a':
	       if (strcmp(optarg, "diff") == 0) {
		    options->aref = AREF_DIFF;
		    break;
	       }
	       if (strcmp(optarg, "ground") == 0) {
		    options->aref = AREF_GROUND;
		    break;
	       }
	       if (strcmp(optarg, "other") == 0) {
		    options->aref = AREF_OTHER;
		    break;
	       }
	       if (strcmp(optarg, "common") == 0) {
		    options->aref = AREF_COMMON;
		    break;
	       }
	       fprintf(stderr, "unknow analog reference\n");
	       exit(-1);
	       break;
	  case 'r':
	       options->range = strtoul(optarg, NULL, 0);
	       break;
	  case 'w':
	       if (strcmp(optarg, "sin") == 0) {
		    waveform->kind = WAVEFORM_SINE;
		    break;
	       }
	       if (strcmp(optarg, "saw") == 0) {
		    waveform->kind = WAVEFORM_SAWTOOTH;
		    break;
	       }
	       if (strcmp(optarg, "tri") == 0) {
		    waveform->kind = WAVEFORM_TRIANGULAR;
		    break;
	       }
	       if (strcmp(optarg, "ste") == 0) {
		    waveform->kind = WAVEFORM_STEPS;
		    break;
	       }
	       fprintf(stderr, "unknow waveform\n");
	       exit(-1);
	       break;
	       
	  case 'o':
	       waveform->offset = strtod(optarg, NULL);
	       break;

	  case 'f':
	       waveform->frequency = strtod(optarg, NULL);
	       break;

	  default:
	       fprintf(stderr, "unknown option\n");
	       exit(-1);
	  }
     }

     if (optind < argc) {
	  /* amplitude */
	  waveform->amplitude = strtod(argv[optind++], NULL);
     }

     fprintf(stderr, "amplitude=%f\n", waveform->amplitude);
     fprintf(stderr, "offset=%f\n", waveform->offset);

     return argc;
}

#define WAVEFORMSHIFT 16
#define WAVEFORMLEN   (1 << WAVEFORMSHIFT)
#define WAVEFORMMASK  (WAVEFORMLEN - 1)

typedef struct _dds {
     int kind;
     double frequency;	/* waveform frequency */
     double amplitude;	/* peak-to-peak amplitude in DAC units */
     double offset;	/* offset in DAC units */
     
     unsigned int adder;
     unsigned int acc;
     sampl_t waveform[WAVEFORMLEN];
} dds_t;

void dds_init_sine(dds_t *dds)
{
     for (int i = 0; i < WAVEFORMLEN ; i++) {
	  dds->waveform[i] = rint(dds->offset + 0.5 * dds->amplitude * cos(i*2*PI/(WAVEFORMLEN-1)));
     }
}

void dds_init_sawtooth(dds_t *dds)
{
     for (int i = 0; i < WAVEFORMLEN; i++) {
	  dds->waveform[i] = rint(dds->offset + dds->amplitude * ((double)i)/(WAVEFORMLEN-1));
	  //fprintf(stdout, "%d %f %d\n", i, ((double)i)/(WAVEFORMLEN-1), dds->waveform[i]);
     }
     //fflush(stdout);
}

void dds_init_triangular(dds_t *dds)
{
     fprintf(stderr, "here\n");
     int i = 0;
     for ( ; i < WAVEFORMLEN/2; i++) {
	  dds->waveform[i] = rint(dds->offset + dds->amplitude * ((double)i)/WAVEFORMLEN*2);
	  //fprintf(stdout, "%d %d\n", i, dds->waveform[i]);
     }
     for ( ; i < WAVEFORMLEN; i++) { 
	  dds->waveform[i] = rint(dds->offset + 2.0 * dds->amplitude - dds->amplitude * ((double)i)/WAVEFORMLEN*2);
	  //fprintf(stdout, "%d %d\n", i, dds->waveform[i]);
     }
     //fflush(stdout);
}

void dds_init_steps(dds_t *dds)
{
     int i = 0;
     for ( ; i < WAVEFORMLEN/2; i++) {
	  dds->waveform[i] = rint(dds->offset + dds->amplitude * (i*10/WAVEFORMLEN*2)/10);
	  //printf("%d %d\n", i, dds->waveform[i]);
     }
     for ( ; i < WAVEFORMLEN; i++) { 
	  dds->waveform[i] = rint(dds->offset + 2.0 * dds->amplitude - dds->amplitude * (i*10/WAVEFORMLEN*2)/10);
     }
     //fflush(stdout);
}

void dds_init(dds_t *dds, double frequency)
{
     fprintf(stderr, "initialise waveform table\n");
     dds->acc = 0;
     dds->adder = dds->frequency / frequency * (1 << 16) * (1 << WAVEFORMSHIFT);
     //fprintf(stderr, "adder=%12d\n", dds->adder);
     switch (dds->kind) {
     case WAVEFORM_SINE:
	  dds_init_sine(dds);
	  break;
     case WAVEFORM_SAWTOOTH:
	  dds_init_sawtooth(dds);
	  break;
     case WAVEFORM_TRIANGULAR:
	  dds_init_triangular(dds);
	  break;
     case WAVEFORM_STEPS:
	  dds_init_steps(dds);
	  break;
     }
     fprintf(stderr, "done\n");
}

void dds_output(dds_t *dds, sampl_t *buf, int n)
{
     sampl_t *p = buf;
     
     int ii;

     for (int i = 0; i < n; i++) {
	  ii = (dds->acc >> 16) & WAVEFORMMASK;
	  *p = dds->waveform[(dds->acc >> 16) & WAVEFORMMASK];
	  //fprintf(stdout, "%d %d\n", ii, *p);
	  p++;
	  dds->acc += dds->adder;
     }
     //fflush(stdout);
}

/* chunks size */
#define BUFLEN 0x8000
sampl_t data[BUFLEN];

int main(int argc, char **argv)
{
     int n, m;
     int total = 0;
     unsigned int chanlist[16];

     int ret;
     options_t options;
     init_options(&options);

     waveform_t waveform;
     init_waveform(&waveform);

     parse_options(&options, &waveform, argc, argv);

     /* open device */
     int rv;
     a4l_desc_t dsc;
     rv = a4l_open(&dsc, options.filename);
     if (rv < 0) {
	  fprintf(stderr, "error opening %s\n", options.filename);
	  return -1;
     }

     DEBUG("device=%s fd=%d", options.filename, dsc.fd);
     DEBUG("subdevices=%d", dsc.nb_subd);
     DEBUG("read subdevice=%d", dsc.idx_read_subd);
     DEBUG("write subdevice=%d", dsc.idx_write_subd);
     DEBUG("sbsize=%d", dsc.sbsize);

     /* subdevice */
     if (options.subdevice < 0) {
	  options.subdevice = dsc.idx_write_subd;
     }
     DEBUG("subdevice=%d", options.subdevice);

     /* allocate additional informations buffer */
     dsc.sbdata = malloc(dsc.sbsize);
     if (dsc.sbdata == NULL) {
	  ERROR("malloc");
	  return -ENOMEM;
     }

     /* get additional informations */
     rv = a4l_fill_desc(&dsc);
     if (rv < 0) {
	  ERROR("analogy fill desc");
	  goto out;
     }

     a4l_chinfo_t *info;
     rv = a4l_get_chinfo(&dsc, options.subdevice, options.channel, &info);
     if (rv < 0) {
	  ERROR("analogy get chinfo");
	  goto out;
     }

     for (int i = 0; i < info->nb_rng; i++) {
	  a4l_rnginfo_t *range;
	  rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, i, &range);
	  if (rv < 0) {
	       ERROR("analogy get rngnfo");
	       goto out;
	  }
	  DEBUG("range=%d %ld %ld", i, range->max, range->min);
     }

     /* range */
     double min = waveform.offset - waveform.amplitude;
     double max = waveform.offset + waveform.amplitude;
     DEBUG("min=%f max=%f", min, max);
     if (options.range < 0) {
	  options.range = analogy_find_range(&dsc, options.subdevice, options.channel, options.unit, min, max, NULL);
	  DEBUG("range=%d", options.range);
     }
     a4l_rnginfo_t *range;
     rv = a4l_get_rnginfo(&dsc, options.subdevice, options.channel, options.range, &range);
     if (rv < 0) {
	  ERROR("analogy get rngnfo");
	  goto out;
     }

     dds_t dds;
     dds.kind = waveform.kind;
     dds.frequency = waveform.frequency;

     /* physical to sample */
     unsigned short value = 0;
     double raw = 0.0;
     a4l_dtoraw(info, range, &value, &raw, 1);
     double zero = value;
     
     a4l_dtoraw(info, range, &value, &(waveform.amplitude), 1);
     dds.amplitude = value - zero;

     a4l_dtoraw(info, range, &value, &(waveform.offset), 1);
     dds.offset = value;
     
     DEBUG("amplitude=%f", dds.amplitude);
     DEBUG("offset=%f", dds.offset);

     /* setup command */
     a4l_cmd_t cmd;
     memset(&cmd, 0, sizeof(cmd));
     cmd.idx_subd = options.subdevice;
     cmd.flags = A4L_CMD_WRITE;
     cmd.start_src = TRIG_INT;
     cmd.start_arg = 0;
     cmd.scan_begin_src = TRIG_TIMER;
     cmd.scan_begin_arg = 1e9 / options.freq;
     cmd.convert_src = TRIG_NOW;
     cmd.convert_arg = 0;
     cmd.scan_end_src = TRIG_COUNT;
     cmd.scan_end_arg = options.nchan;
     cmd.stop_src = TRIG_COUNT;
     cmd.stop_arg = 10000000;
     cmd.nb_chan = 1,
     cmd.chan_descs = chanlist;

     chanlist[0] = PACK(options.channel, options.range, options.aref);
	       
     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);

     /* send the command to the input device */
     rv = a4l_snd_command(&dsc, &cmd);
     if (rv < 0) {
	  ERROR("analogy snd command");
	  goto out;
     }

     dds_init(&dds, options.freq);     
     dds_output(&dds, data, BUFLEN);

     n = BUFLEN * sizeof(sampl_t);
     m = a4l_sys_write(dsc.fd, (void *)data, n);
     if (m < 0) {
	  ERROR("write");
	  exit(1);
     } else if (m < n) {
	  fprintf(stderr, "failed to preload output buffer\n");
	  exit(1);
     }
     
     /* send internal trigger */
     ret = analogy_internal_trigger(&dsc, options.subdevice, 0);
     if (ret < 0) {
	  ERROR("comedi_internal_trigger\n");
	  exit(1);
     }

     while (1) {
	  dds_output(&dds, data, BUFLEN);
	  n = BUFLEN * sizeof(sampl_t);
	  while (n > 0) {
	       m = a4l_sys_write(dsc.fd, (void *)data+(BUFLEN*sizeof(sampl_t)-n), n);
	       if (m < 0) {
		    ERROR("write: %s", strerror(-m));
		    exit(0);
	       }
	       n -= m;
	  }
	  total += BUFLEN;
     }


out:
     /* free buffer */
     if (dsc.sbdata != NULL) {
	  free(dsc.sbdata);
     }

     /* cancel any command which might be in progress */
     a4l_snd_cancel(&dsc, cmd.idx_subd);
     
     /* close file descriptor */
     a4l_close(&dsc);
     
     return rv;
}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
  2010-05-31 10:23 ` Daniele Nicolodi
@ 2010-05-31 23:24   ` Ettore Pedretti
  2010-06-01  1:37     ` Ettore Pedretti
  0 siblings, 1 reply; 6+ messages in thread
From: Ettore Pedretti @ 2010-05-31 23:24 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: xenomai

Hi Daniele,

Thanks very much for your help. It is very appreciated. I compiled
your programs. When I run them I get:

fangorn:~/control/CHAMP/analogy# ./analogy-waveform
amplitude=1.000000
offset=0.000000
analogy-waveform.c:364:main:DEBUG: device=analogy0 fd=0
analogy-waveform.c:365:main:DEBUG: subdevices=14
analogy-waveform.c:366:main:DEBUG: read subdevice=-1
analogy-waveform.c:367:main:DEBUG: write subdevice=1
analogy-waveform.c:368:main:DEBUG: sbsize=16456
analogy-waveform.c:374:main:DEBUG: subdevice=1
analogy-waveform.c:405:main:DEBUG: range=0 10000000 -10000000
analogy-waveform.c:411:main:DEBUG: min=-1.000000 max=1.000000
analogy-waveform.c:414:main:DEBUG: range=-1
analogy-waveform.c:419:main:ERROR: analogy get rngnfo

and dmesg:

Analogy: a4l_rt_ioctl: minor=0
Analogy: a4l_rt_ioctl: minor=0
Analogy: a4l_rt_ioctl: minor=0
Analogy: a4l_ioctl_cancel: minor=0
Analogy: a4l_ioctl_cancel: non functional subdevice
Analogy: a4l_rt_close: minor=0

What am I doing wrong? do I need to pass a parameter?

Cheers

Ettore

-- 
Ettore Pedretti, SUPA
School of Physics and Astronomy
University of St Andrews, North Haugh,
St Andrews, Fife, KY16 9SS, Scotland
Ph: +44-1334-461666, Fax: +44-1334-463104
The University of St Andrews is a charity registered in Scotland : No SC013532


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
  2010-05-31 23:24   ` Ettore Pedretti
@ 2010-06-01  1:37     ` Ettore Pedretti
  2010-06-02 21:06       ` Alexis Berlemont
  0 siblings, 1 reply; 6+ messages in thread
From: Ettore Pedretti @ 2010-06-01  1:37 UTC (permalink / raw)
  To: Daniele Nicolodi; +Cc: xenomai

Hi Daniele,

Thanks again for your code. It works when I select range=0

./analogy-waveform --r 0
./analogy-phasemod --r 0

I get a sine wave out of the card

Thanks a bunch!!

Ettore

On 31 May 2010 16:24, Ettore Pedretti <ep41@domain.hid> wrote:
> Hi Daniele,
>
> Thanks very much for your help. It is very appreciated. I compiled
> your programs. When I run them I get:
>
> fangorn:~/control/CHAMP/analogy# ./analogy-waveform
> amplitude=1.000000
> offset=0.000000
> analogy-waveform.c:364:main:DEBUG: device=analogy0 fd=0
> analogy-waveform.c:365:main:DEBUG: subdevices=14
> analogy-waveform.c:366:main:DEBUG: read subdevice=-1
> analogy-waveform.c:367:main:DEBUG: write subdevice=1
> analogy-waveform.c:368:main:DEBUG: sbsize=16456
> analogy-waveform.c:374:main:DEBUG: subdevice=1
> analogy-waveform.c:405:main:DEBUG: range=0 10000000 -10000000
> analogy-waveform.c:411:main:DEBUG: min=-1.000000 max=1.000000
> analogy-waveform.c:414:main:DEBUG: range=-1
> analogy-waveform.c:419:main:ERROR: analogy get rngnfo
>
> and dmesg:
>
> Analogy: a4l_rt_ioctl: minor=0
> Analogy: a4l_rt_ioctl: minor=0
> Analogy: a4l_rt_ioctl: minor=0
> Analogy: a4l_ioctl_cancel: minor=0
> Analogy: a4l_ioctl_cancel: non functional subdevice
> Analogy: a4l_rt_close: minor=0
>
> What am I doing wrong? do I need to pass a parameter?
>
> Cheers
>
> Ettore
>
> --
> Ettore Pedretti, SUPA
> School of Physics and Astronomy
> University of St Andrews, North Haugh,
> St Andrews, Fife, KY16 9SS, Scotland
> Ph: +44-1334-461666, Fax: +44-1334-463104
> The University of St Andrews is a charity registered in Scotland : No SC013532
>



-- 
Ettore Pedretti, SUPA
School of Physics and Astronomy
University of St Andrews, North Haugh,
St Andrews, Fife, KY16 9SS, Scotland
Ph: +44-1334-461666, Fax: +44-1334-463104
The University of St Andrews is a charity registered in Scotland : No SC013532


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
  2010-06-01  1:37     ` Ettore Pedretti
@ 2010-06-02 21:06       ` Alexis Berlemont
  2010-06-03 13:19         ` Daniele Nicolodi
  0 siblings, 1 reply; 6+ messages in thread
From: Alexis Berlemont @ 2010-06-02 21:06 UTC (permalink / raw)
  To: Ettore Pedretti; +Cc: xenomai

Hi,

Ettore Pedretti wrote:
> Hi Daniele,
> 
> Thanks again for your code. It works when I select range=0
> 
> ./analogy-waveform --r 0
> ./analogy-phasemod --r 0
> 
> I get a sine wave out of the card
> 

If you are OK with it, I will integrate this code into cmd_write (or
instead of it).

Many thanks.

> Thanks a bunch!!
> 
> Ettore
> 
> On 31 May 2010 16:24, Ettore Pedretti <ep41@domain.hid> wrote:
> > Hi Daniele,
> >
> > Thanks very much for your help. It is very appreciated. I compiled
> > your programs. When I run them I get:
> >
> > fangorn:~/control/CHAMP/analogy# ./analogy-waveform
> > amplitude=1.000000
> > offset=0.000000
> > analogy-waveform.c:364:main:DEBUG: device=analogy0 fd=0
> > analogy-waveform.c:365:main:DEBUG: subdevices=14
> > analogy-waveform.c:366:main:DEBUG: read subdevice=-1
> > analogy-waveform.c:367:main:DEBUG: write subdevice=1
> > analogy-waveform.c:368:main:DEBUG: sbsize=16456
> > analogy-waveform.c:374:main:DEBUG: subdevice=1
> > analogy-waveform.c:405:main:DEBUG: range=0 10000000 -10000000
> > analogy-waveform.c:411:main:DEBUG: min=-1.000000 max=1.000000
> > analogy-waveform.c:414:main:DEBUG: range=-1
> > analogy-waveform.c:419:main:ERROR: analogy get rngnfo
> >
> > and dmesg:
> >
> > Analogy: a4l_rt_ioctl: minor=0
> > Analogy: a4l_rt_ioctl: minor=0
> > Analogy: a4l_rt_ioctl: minor=0
> > Analogy: a4l_ioctl_cancel: minor=0
> > Analogy: a4l_ioctl_cancel: non functional subdevice
> > Analogy: a4l_rt_close: minor=0
> >
> > What am I doing wrong? do I need to pass a parameter?
> >
> > Cheers
> >
> > Ettore
> >
> > --
> > Ettore Pedretti, SUPA
> > School of Physics and Astronomy
> > University of St Andrews, North Haugh,
> > St Andrews, Fife, KY16 9SS, Scotland
> > Ph: +44-1334-461666, Fax: +44-1334-463104
> > The University of St Andrews is a charity registered in Scotland : No SC013532
> >
> 
> 
> 
> -- 
> Ettore Pedretti, SUPA
> School of Physics and Astronomy
> University of St Andrews, North Haugh,
> St Andrews, Fife, KY16 9SS, Scotland
> Ph: +44-1334-461666, Fax: +44-1334-463104
> The University of St Andrews is a charity registered in Scotland : No SC013532
> 
> _______________________________________________
> Xenomai-help mailing list
> Xenomai-help@domain.hid
> https://mail.gna.org/listinfo/xenomai-help

-- 
Alexis.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Xenomai-help] How to generate a waveform / digital output (Alexis)
  2010-06-02 21:06       ` Alexis Berlemont
@ 2010-06-03 13:19         ` Daniele Nicolodi
  0 siblings, 0 replies; 6+ messages in thread
From: Daniele Nicolodi @ 2010-06-03 13:19 UTC (permalink / raw)
  To: Alexis Berlemont; +Cc: xenomai

On 02/06/10 23:06, Alexis Berlemont wrote:
> Hi,
> 
> Ettore Pedretti wrote:
>> Hi Daniele,
>>
>> Thanks again for your code. It works when I select range=0
>>
>> ./analogy-waveform --r 0
>> ./analogy-phasemod --r 0
>>
>> I get a sine wave out of the card
>>
> 
> If you are OK with it, I will integrate this code into cmd_write (or
> instead of it).

You can of course include this code in the analogy distribution.
Be warned, however, that this is just proven at the "works for me"
level, and the option parsing and wrong usage reporting sections can see
some nice improvements.

I would like however to retain the copyright on the code, the license
should be GPL v3 or later, it this suits in xenomai. Otherwise GPL v2 is
fine also.

Thanks. Cheers,
-- 
Daniele


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-06-03 13:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-30 16:14 [Xenomai-help] How to generate a waveform / digital output (Alexis) Ettore Pedretti
2010-05-31 10:23 ` Daniele Nicolodi
2010-05-31 23:24   ` Ettore Pedretti
2010-06-01  1:37     ` Ettore Pedretti
2010-06-02 21:06       ` Alexis Berlemont
2010-06-03 13:19         ` Daniele Nicolodi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.