Re: RTAI and comedi: leaving real time?

Thanks for your help again Paolo!

On Wed, 2007-05-23 at 22:12 +0200, Paolo Mantegazza wrote:
> L.C. Karssen wrote:
> > After getting rid of the syscalls during hard RT as described below, I
> > found that the DIO lines are no longer being flipped. Only the analog
> > out works. 
> > When I replaced the call to comedi_dio_bitfield() with 8 calls to
> > comedi_dio_write() (one for each DIO channel) it works again.
> > Unfortunately this takes too much time. I set a period of 20us, but when
> > I record the time using rt_get_time_ns to check the time difference
> > between to successive iterations of my for-loop I see that about once in
> > every three iterations the time difference is 40us, indicating that the
> > execution took more that one period. 
> > 
> 
> One of the known "beuties" of using PCs for hard real time is that 
> execution time of the very same stuff is not the same always, especially 
> if you do some IO.
I understand that there may be a small time difference each time you run
code that does IO. However, I don't think it should be more than 10us.
The way I understand it, comedi_dio_bitfield() sets all the bits at once
(which is what I want). And of course calling comedi_dio_write() 8 times
costs more time. For my experiments I would like to have as short a
timing as possible. Therefore 20us is much better that the 40us it takes
when using 8 comedi_dio_writes().

The point I was trying to make was that I don't see any output on the
oscilloscope when looking at the DIO lines. The AO works OK. So it looks
like writing DIO with the bitfield-function in hard RT (when
#include-ing rtai_comedi.h) doesn't work. 


> 
> > Just to emphasise that my usage of comedi_dio_bitfield() is in principle
> > OK: Using comedi_dio_bitfield() in my code works when including
> > comedilib.h instead of rtai_comedi.h (but this results in syscalls being
> > made).
> > 
> 
> I'm wondering why you do not try to track the problem by making a direct 
> call both with comedi and using RTAI call, without hard real mode, just 
> to see where the problem is. In my view it is likely just a matter of a 
> few printf and prink at right places, possibly including comedi function 
> to follow the whole path.
I'm not sure how I should do that. How can I distinguish between
comedi_dio_bitfield() being called through the RTAI wrapper (so with
rtai_comedi.h) and comedi_dio_bitfield() in its "normal" form (so with
the comedilib.h file #included)? I can't have both function definitions
in the same program, can I?

B.t.w., I'm a physicist, not a programmer, so maybe I'm missing
something basic here. 

> 
> > So, can anybody tell me if using comedi_dio_bitfield() in hard RT works
> > for him/her? In RTAILabs rtai_comedi_dioout.c I see that only
> > comedi_dio_write() is used. I also noticed that rtai_comedi.h doesn't
> > have a wrapper for the (new) comedi_dio_bitfield2() function (which is
> > supposed to supersede the comedi_dio_bitfield() function if I'm not
> > mistaken).
> 
> It is simple to add the wrapper and test it, see above. just the 
> declaration and a new cal number in rtai_comedi.h the related call and 
> table insertion in the module, Likely a cut and paste with few changes.
I tried to do as you suggested. This is what I did:
- In /usr/src/rtai/addons/comedi/rtai_comedi.h I added the line

#define _KCOMEDI_DIO_BITFIELD2 		29

just above the deprecated GET_RANGETYPE and after the POLL line. I also
copied and edited the prototype of the ordinary bitfield function:

RTAI_PROTO(int, comedi_dio_bitfield2,(void *dev, unsigned int subdev,
unsigned int mask, unsigned int *bits, unsigned int base_channel))
{
        int retval;
	unsigned int lbits;
        struct { void *dev; unsigned int subdev; unsigned int mask;
unsigned int *bits; unsigned int base_channel; } arg = { dev, subdev,
mask, &lbits, base_channel };
	retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG,
_KCOMEDI_DIO_BITFIELD2, &arg).i[LOW];
	*bits = lbits;
	return retval;


- In /usr/src/rtai/addons/comedi/kcomedi_module.c I copied and adapted
the bitfield RTAI_SYSCALL_MODE line:

static RTAI_SYSCALL_MODE int _comedi_dio_bitfield2(void *dev, unsigned
int subdev, unsigned int mask, unsigned int *bits, unsigned int
base_channel)
{
  return comedi_dio_bitfield2(dev, subdev, mask, bits, base_channel);
}

Then, in the rtai_comedi_fun[] struct I added the line

,[_KCOMEDI_DIO_BITFIELD2]        = { 0, _comedi_dio_bitfield2 }

below the line with ,[_KCOMEDI_POLL]                = { 0, comedi_poll }

(so that it was in the same order as in the rtai_comedi.h file. A bit
further down I added the line .

,[_KCOMEDI_DIO_BITFIELD2]        = { 0, comedi_dio_bitfield2 }


But when I run make in this directory I get a long list of errors,
starting with:

/usr/src/rtai/addons/comedi/kcomedi-module.c: At top level:
/usr/src/rtai/addons/comedi/kcomedi-module.c:401: error:
`comedi_dio_bitfield2' undeclared here (not in a function)
/usr/src/rtai/addons/comedi/kcomedi-module.c:401: error: initializer
element is not constant
/usr/src/rtai/addons/comedi/kcomedi-module.c:401: error: (near
initialization for `rtai_comedi_fun[29].fun')
/usr/src/rtai/addons/comedi/kcomedi-module.c:401: error: initializer
element is not constant
/usr/src/rtai/addons/comedi/kcomedi-module.c:401: error: (near
initialization for `rtai_comedi_fun[29]')


I have no idea what's missing here. 

> 
> Paolo.
> 
> > 
> > 
> > Thanks,
> > 
> > Lennart.
> > 
> > 
> > On Tue, 2007-05-22 at 14:09 +0000, L.C. Karssen wrote:
> > 
> >>I think I solved/worked around the problem. I don't include comedilib.h
> >>anymore and I changed the comedi_t pointer for a comedi device to a void
> >>pointer (as expected by rtai_comedi.h). Furthermore I removed all
> >>references to the comedi_range struct and the calls to
> >>comedi_get_range() and comedi_perror(). These functions are not defined
> >>in rtai_comedi.h (but are defined in comedilib.h, which I no lnger
> >>include).
> >>This removes any errors about either missing or double definitions. 
> >>No more syscalls are added to /proc/rtai/scheduler. Everything seems to
> >>work now.
> >>
> >>It's probably not the nicest solution, but it works. If somebody has a
> >>better solution, I'll be glad to hear it. 
> >>
> >>
> >>Lennart.
> >>
> >>On Mon, 2007-05-21 at 19:09 +0200, L.C. Karssen wrote:
> >>
> >>>On Mon, 2007-05-21 at 16:30 +0000, L.C. Karssen wrote:
> >>>
> >>>>On Mon, 2007-05-21 at 19:52 +0200, Paolo Mantegazza wrote:
> >>>>
> >>>>>L.C. Karssen wrote:
> >>>>>
> >>>>>>On Mon, 2007-05-21 at 09:42 +0000, L.C. Karssen wrote:
> >>>>>>
> >>>>>>
> >>>>>>>On Sun, 2007-05-13 at 23:37 +0200, Paolo Mantegazza wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>>>L.C. Karssen writes: 
> >>>>>>>>
> >>>>>>>>
> >>>>
> >>>>Furthermore, I looked at rtai_comedi_dioout.c from RTAILab and found
> >>>>that it includes rtai_comedi.h. I have the following RTAI and comedi
> >>>>related includes:
> >>>>#include "/usr/local/include/comedilib.h"
> >>>>#include <rtai_lxrt.h>
> >>>>
> >>>>I included rtai_comedi.h but that resulted in a lot of errors because of
> >>>>overshadowed definitions (because of comedilib.h). 
> >>>
> >>>An example of such an error:
> >>>
> >>>In file included from daqwrite.c:25:
> >>>/usr/realtime/include/rtai_comedi.h:123: error: conflicting types for
> >>>'comedi_open'
> >>>/usr/local/include/comedilib.h:68: error: previous declaration of
> >>>'comedi_open' was here
> >>>
> >>>
> >>>In comedilib.h:68:
> >>>comedi_t *comedi_open(const char *fn);
> >>>
> >>>In rtai_comedi.h:123:
> >>>RTAI_PROTO(void *, comedi_open,(const char *filename))
> >>>{
> >>>	char lfilename[COMEDI_NAMELEN];
> >>>        struct { char *minor; } arg = { lfilename };
> >>>	strncpy(lfilename, filename, COMEDI_NAMELEN - 1);
> >>>        return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG,
> >>>_KCOMEDI_OPEN, &arg).v[LOW];
> >>>}
> >>>
> >>>
> >>>
> >>>>When only including
> >>>>rtai_comedi.h I get a lot of syntax errors. I'm going to check why that
> >>>>happens.
> >>>
> >>>When not including /usr/local/comedilib.h I get errors because of
> >>>missing definitions of e.g. comedi_t, comedi_range and comedi_dev. The
> >>>typedefs of these are in comedilib.h. 
> >>>I need those to initialise my comedi device, as in the following code
> >>>for example: 
> >>> comedi_t *comedi_dev;
> >>> comedi_dev = comedi_open(comedi_devname);
> >>>
> >>>
> >>>Lennart
> >>>
> >>>
> >>>>Thanks,
> >>>>
> >>>>Lennart
> >>>>
> >>>>>Paolo
> >>>>>
> >>>>>
> >>>>>>
> >>>>>>>Any help is appreciated!
> >>>>>>>
> >>>>>>>
> >>>>>>>Lennart.
> >>>>>>>
> >>>>>>>
> >>>>>>>int do_comedi(struct data_struct *options)
> >>>>>>>{
> >>>>>>>   comedi_t *comedi_dev = options->device;
> >>>>>>>   unsigned int ao_subdev  = options->AO_subdevice;  // Analog Output
> >>>>>>>   unsigned int dio_subdev = options-> DIO_subdevice; // Digital IO
> >>>>>>>   int range=0; // AO has only one range: 10V -> -10V
> >>>>>>>   comedi_insn insn;
> >>>>>>>   lsampl_t data;
> >>>>>>>   unsigned int dio_bits;
> >>>>>>>   int aref = AREF_GROUND;
> >>>>>>>   unsigned int dio_mask = 0xFFFFFFFF; // Tells which DIO bits are to
> >>>>>>>be flipped (all).
> >>>>>>>
> >>>>>>>   int period;
> >>>>>>>   struct bits *data_arr = options->bitsarr;
> >>>>>>>   
> >>>>>>>   RT_TASK* task;
> >>>>>>>   int priority=0;
> >>>>>>>   int stack_size=4096;
> >>>>>>>   int msg_size=0;
> >>>>>>>   
> >>>>>>>   int i;
> >>>>>>>
> >>>>>>>   /* Prepare the AO instruction as much as possible. Later, in real
> >>>>>>>time
> >>>>>>>    *  we'll only fill in the data sample. */
> >>>>>>>   insn.insn = INSN_WRITE;
> >>>>>>>   insn.n = 1;
> >>>>>>>   insn.subdev = ao_subdev;
> >>>>>>>
> >>>>>>>   /* A better scheduler than linux' one */
> >>>>>>>   struct sched_param mysched;
> >>>>>>>   
> >>>>>>>   /* We don't want to be swapped out the mem */
> >>>>>>>   mlockall (MCL_CURRENT | MCL_FUTURE);
> >>>>>>>   /* Allow nonroot users hard realtime access */
> >>>>>>>   rt_allow_nonroot_hrt();
> >>>>>>>
> >>>>>>>   /* Initialise Scheduler as SCHED_FIFO. Greatly improves scheduler!
> >>>>>>>*/ 
> >>>>>>>   mysched.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
> >>>>>>>   if( sched_setscheduler( 0, SCHED_FIFO, &mysched ) == -1 ) 
> >>>>>>>   {
> >>>>>>>	fprintf(stderr, "Error in setting the Scheduler!\n");
> >>>>>>>	exit(1);
> >>>>>>>   }
> >>>>>>>   
> >>>>>>>   /* Register this thread as a RT task. As long as it's
> >>>>>>>      not switched to hard_real_time, it's still a normal process and
> >>>>>>>      can do all normal things */
> >>>>>>>   task = rt_task_init(nam2num("do_comedi"), priority, stack_size,
> >>>>>>>msg_size);
> >>>>>>>
> >>>>>>>   // Set mode to periodic. Other option is 'oneshot'
> >>>>>>>   rt_set_periodic_mode();
> >>>>>>>   period = (int) nano2count((RTIME)options->period*1000);
> >>>>>>>
> >>>>>>>   start_rt_timer(period);
> >>>>>>>
> >>>>>>>   // Switch to hard realtime mode
> >>>>>>>   rt_make_hard_real_time();
> >>>>>>>
> >>>>>>>   // Start scheduler 
> >>>>>>>   rt_task_make_periodic(task, rt_get_time() + period, period);
> >>>>>>>   
> >>>>>>>   
> >>>>>>>   for (i=0; i<options->n_rows; i++)
> >>>>>>>   {
> >>>>>>>	
> >>>>>>>	/* Prepare and write digital data. */
> >>>>>>>	dio_bits = data_arr[i].DIO;
> >>>>>>>	comedi_dio_bitfield(comedi_dev, dio_subdev, dio_mask, &dio_bits);
> >>>>>>>
> >>>>>>>	/* Prepare and write AO data */
> >>>>>>>	data = data_arr[i].AO0;
> >>>>>>>	insn.data = &data;
> >>>>>>>	insn.chanspec = CR_PACK(0, range, aref);
> >>>>>>>	if(comedi_do_insn(comedi_dev, &insn)<0)
> >>>>>>>	{
> >>>>>>>	    comedi_perror("/dev/comedi0");
> >>>>>>>	    exit(1);
> >>>>>>>	}
> >>>>>>>
> >>>>>>>	data = data_arr[i].AO1;
> >>>>>>>	insn.data = &data;
> >>>>>>>	insn.chanspec = CR_PACK(1, range, aref);
> >>>>>>>	if(comedi_do_insn(comedi_dev, &insn)<0)
> >>>>>>>	{
> >>>>>>>	    comedi_perror("/dev/comedi0");
> >>>>>>>	    exit(1);
> >>>>>>>	}
> >>>>>>>	rt_task_wait_period();
> >>>>>>>   }
> >>>>>>>
> >>>>>>>   rt_make_soft_real_time();
> >>>>>>>
> >>>>>>>#ifdef DEBUG
> >>>>>>>   printf("We're back in soft realtime.\n");
> >>>>>>>#endif
> >>>>>>>   
> >>>>>>>   // Stop timer
> >>>>>>>   stop_rt_timer();
> >>>>>>>
> >>>>>>>   // Unregister RT task
> >>>>>>>   rt_task_delete(task);
> >>>>>>>
> >>>>>>>   // Unlock mem
> >>>>>>>   munlockall();
> >>>>>>>
> >>>>>>>   return 0;
> >>>>>>>}
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>>Paolo. 
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>>Lennart.
> >>>>>>>>>-- 
> >>>>>>>>>*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> >>>>>>>>>L.C. Karssen
> >>>>>>>>>Department of Physics and Astronomy
> >>>>>>>>>Faculty of Science
> >>>>>>>>>Utrecht University
> >>>>>>>>>Princetonplein 1
> >>>>>>>>>3584 CC  Utrecht
> >>>>>>>>>The Netherlands 
> >>>>>>>>>
> >>>>>>>>>tel.: +31 (0)30-253-2208
> >>>>>>>>>fax.: +31 (0)30-253-7468
> >>>>>>>>>e-mail: L.C.Karssen_at_phys.uu.nl
> >>>>>>>>>www: http://www1.phys.uu.nl/wwwaoud
> >>>>>>>>>-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- 
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>>_______________________________________________
> >>>>>>>>>RTAI mailing list
> >>>>>>>>>RTAI_at_rtai.org
> >>>>>>>>>https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai
> >>>>>>>>
> >>>>>>>>
> 
-- 
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
L.C. Karssen
Debye Institute
Dept. of Physics & Astronomy
Utrecht University
Princetonplein 1
3584 CC  Utrecht
The Netherlands

tel.: +31 (0)30-253-2208
e-mail: L.C.Karssen_at_phys.uu.nl
www: http://www1.phys.uu.nl/wwwaoud
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

Received on 2007-05-23Z19:17:49