[Rtai] realtime comedi commands

Paolo Mantegazza mantegazza at aero.polimi.it
Fri Mar 6 16:51:33 CET 2009


We've upgraded the test in "showroom/v3.x/user/comedi" to run in hard 
real time from user space. It requires the latest versions in Vulcano 
CVSes, but just the directory"addons/comedi" should be upgraded if you 
have 3.7-test2 already in place. I'll relase test3 next week in the hope 
somebody can cross check the newest stuff in RTAI comedi more easily.

I think you should anticipate a look at it, it might turn into being of 
some help.

Paolo.

Martin Martin wrote:
> Hello, I am having problems with the following code:
> 
> kernel.c:
> 
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/moduleparam.h>
> #include <rtai_registry.h>
> #include <rtai_sem.h>
> 
> #undef  __attribute_pure__
> #undef  __attribute_used__
> #undef  __always_inline
> 
> #include <math.h>
> #include "rtai_comedi.h"
> #include "shared.h"
> 
> 
> 
> extern int comedi_map(comedi_t *, unsigned, void *);   // avoid compiler warnings
> extern int comedi_unmap(comedi_t *, unsigned);         // avoid compiler warnings
> 
> 
> 
> 
> /******************************* Semaphores *********************************/
> SEM sem;
> /******************************* Semaphores *********************************/
> /************************* Rtai Parameters ***************************/
> unsigned long int tick_p=100000000;                                             
> unsigned int task_pr=1;                                                      
> unsigned long int stack_s=1000000;                                             
> RT_TASK task; 
> RTIME tick_period;                                                           
> /************************* Rtai Parameters ****************************/
> /************************* Shared Memory   ****************************/
> struct data_str *data;
> /************************* Shared Memory   ****************************/
> /************************* Comedi Parameters *************************/
> void *ptr = NULL;     
> const char *dev_path = "/dev/comedi0";
> comedi_cmd cmd;
> comedi_t *dev=NULL;
> unsigned int subdev = 0; 
> int comedi_o=0;
> /************************* Comedi Parameters *************************/
> /************************* Other Parameters **************************/
> int debug=1;
> /************************* Other Parameters **************************/
> 
> int callback(void)
> {
>         int ret, ofs;
>                      
>         ofs = comedi_get_buffer_offset(dev, subdev);
>         ret = comedi_get_buffer_contents(dev, subdev);
>         
>         rt_printk("sample: %d\n", *(sampl_t *)(ptr + ofs));
>                 
>         ret = comedi_mark_buffer_read(dev, subdev,sizeof(sampl_t));
>         return 0;
> }
> 
> int open_comedi(void)
> {
>      if ((dev = comedi_open(dev_path))==NULL)
>      {
>             printk("Unable to open comedi device\n");
>             return(ERROR);
>      } 
>         
>      comedi_map(dev, subdev, &ptr);
>              
>      comedi_register_callback(dev,subdev,COMEDI_CB_EOS,callback,NULL);     
>     
>      comedi_o=1;
>      rt_printk("Comedi device is open\n");
>     return(OK); 
> }
> 
> void close_comedi(void)
> {
>   if (comedi_o==1)
>   {
>     comedi_cancel(dev,subdev);
>     printk("Comedi operations canceled\n");
>        
>     comedi_unmap(dev, subdev);
>     printk("Comedi device unmaped\n");
>        
>     comedi_close(dev);
>     printk("Comedi device closed\n");  
>     
>     comedi_o=0;    
>   }
> }
> 
> void fun(void)
> {
>    int ret;   
>    while (1)
>    {
>     rt_sem_wait(&sem);
>     switch(data->flag)
>     {
>     
>       case READY:
>               open_comedi();
>               rt_printk("Working\n");
>               ret = comedi_command(dev,&(data->cmd));
>               rt_printk("Command executed\n");
>               close_comedi();
>               data->flag=NOT_READY;
>               break;
>       case NOT_READY:       
>               rt_printk("No command ready to execute\n");
>               break; 
>       default:
>               rt_printk("Invalid state\n");   
>       }
>       rt_task_wait_period();
>     }
>  }
> 
> 
> int init_rt_task(void)
> {
>      int rvalue=0;
>       
>       rvalue=rt_task_init(&task,fun, 0, stack_s, task_pr, 1, 0);
>     if (rvalue==0)
>     {
>       if (debug==1)
>         printk("Real time task succcesfully initialized\n");
>     }
>     else if (rvalue==EINVAL)
>     {
>       if (debug==1)
>           printk("Task structure pointed by task is already in use\n");
>       return(-1);
>     }
>     else if (rvalue==ENOMEM)
>     { 
>       if (debug==1)
>           printk("stack_size bytes couldn't be allocated for the stack\n");
>       return(-1);
>     }
>     else 
>     {
>       if (debug==1)
>           printk ("Unable to start real time task\n"); 
>       return(-1);
>     }
>     
>     rt_set_periodic_mode();
>     tick_period = start_rt_timer(nano2count(tick_p));
>     rt_task_make_periodic(&task, rt_get_time() + tick_period,tick_period);
>     return(0);
> }
> 
> int init_shm(void)
> {
>   data = rtai_kmalloc(nam2num(SHMNAM), sizeof(struct data_str));
>   data->flag=NOT_READY;
>   strcpy(data->device,dev_path);
>   printk("Shared memory created\n");
>   return(0);
> }
> 
> int init_module(void)
> {
>        init_shm();
>        rt_typed_sem_init(&sem, 0, BIN_SEM | FIFO_Q );  
>        if (!rt_register(nam2num("BSEM"), &sem, IS_SEM, 0))
>        { 
>               if (debug==1)
>                 printk("Unable to register semaphore\n");
>        }
>        else 
>        {
>                if (debug==1)
>                  printk("Semaphore registered succesfully\n");
>        }
>         
>        //open_comedi();
>                 
>        if (init_rt_task()!=0)
>        { 
>            if (debug==1)
>               printk("Unable to start realtime\n");
>        }
>        else 
>        {
>           if (debug==1)
>               printk("Realtime initialized\n");    
>        }
>        
>        fun();
>        
>        return 0;
> }
> 
> void cleanup_module(void)
> {
>        stop_rt_timer();
>        printk ("Timer stopped\n");
>        
>        rt_task_delete(&task); 
>        printk ("Reltime task deleted\n");
>        
>        rt_drg_on_name(nam2num("BSEM"));
>        printk("Unregistering semaphore\n");
>        
>        rt_sem_delete(&sem);
>        printk ("Semaphore deleted\n");
>        
>        close_comedi();
> }
> 
> user.c:
> 
> #include <stdio.h>
> #include <sched.h>
> #include <unistd.h>
> #include <sys/types.h>
> #include <sys/mman.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <signal.h>
> #include <rtai_lxrt.h>
> #include <rtai_sem.h>
> #include <rtai.h>
> #include "comedilib.h"
> #include "shared.h"
> 
> 
> /************************* Shared Memory *************************/
> struct data_str *data;
> /************************* Shared Memory *************************/
> /*************************    Comedi     *************************/     
> comedi_t *dev=NULL;
> unsigned int chanlist[1];               
> /*************************    Comedi     *************************/ 
> /*************************     Other     *************************/
> int debug=1;
> /*************************     Other     *************************/
> 
> 
> static int end;
> 
> static void endme(int dummy) 
> { 
>     end=1; 
> }
> 
> void init_shared_memory(void)
> {
>   data = rtai_malloc (nam2num(SHMNAM),1);
>   if (data!=NULL);
>     printf("Shared memory detected\n");
>    
> }
> 
> char * get_string_from_trigger(unsigned int value)
> {
>    if (value==TRIG_ANY)
>         return("TRIG_ANY");
>    else if (value==TRIG_INVALID)
>      return("TRIG_INVALID"); 
>    else if (value==TRIG_NONE)
>      return("TRIG_NONE");
>    else  if (value==TRIG_NOW)
>         return("TRIG_NOW");     
>    else if(value==TRIG_FOLLOW)
>      return("TRIG_FOLLOW");
>    else if(value==TRIG_TIME)
>         return("TRIG_TIME");
>    else if (value==TRIG_TIMER)
>      return("TRIG_TIMER");
>    else if (value==TRIG_COUNT)
>         return("TRIG_COUNT");
>    else if (value==TRIG_EXT)
>         return("TRIG_EXT");
>    else if (value==TRIG_INT)
>      return("TRIG_INT");
>    else if (value==TRIG_OTHER)
>      return("TRIG_OTHER");
>    else if(value==TRIG_BOGUS)
>      return("TRIG_BOGUS");
>    else if(value==TRIG_DITHER)
>      return("TRIG_DITHER");     
>    else if(value==TRIG_DEGLITCH)
>      return("TRIG_DEGLITCH");
>    else if(value==TRIG_CONFIG)
>      return("TRIG_CONFIG");
>    else if(value==TRIG_WAKE_EOS)
>      return("TRIG_WAKE_EOS");
>    else if(value==TRIG_RT)
>      return("TRIG_RT");
>    else if(value==TRIG_WRITE)
>      return("TRIG_WRITE");
>    else if(value==TRIG_ROUND_MASK)
>      return("TRIG_ROUND_MASK");
>    else if(value==TRIG_ROUND_NEAREST)
>      return("TRIG_ROUND_NEAREST");
>    else if(value==TRIG_ROUND_DOWN)
>      return("TRIG_ROUND_DOWN");        
>    else if(value==TRIG_ROUND_UP)
>      return("TRIG_ROUND_UP");
>    else if(value==TRIG_ROUND_UP_NEXT)
>      return("TRIG_ROUND_UP_NEXT");
>    else 
>      return("TRIG_NONE");
> }
> 
> 
> void show_cmd(unsigned int mode)
> {
>    printf("\n\nSHOW COMMAND:\n");
>    printf("subdev:>%d\n",data->cmd.subdev);    
>    (mode==0)?printf("flags:>%d\n",data->cmd.flags):printf("flags:>%s\n",get_string_from_trigger(data->cmd.flags));
>    (mode==0)?printf("start_src:>%d\n",data->cmd.start_src):printf("start_src:>%s\n",get_string_from_trigger(data->cmd.start_src));
>    printf("start_arg:>%d\n",data->cmd.start_arg);
>    (mode==0)?printf("scan_begin_src:>%d\n",data->cmd.scan_begin_src):printf("scan_begin_src:>%s\n",get_string_from_trigger(data->cmd.scan_begin_src));
>    printf("scan_begin_arg:>%d\n",data->cmd.scan_begin_arg);
>    (mode==0)?printf("convert_src:>%d\n",data->cmd.convert_src):printf("convert_src:>%s\n",get_string_from_trigger(data->cmd.convert_src));
>    printf("convert_arg:>%d\n",data->cmd.convert_arg);
>    (mode==0)?printf("scan_end_src:>%d\n",data->cmd.scan_end_src):printf("scan_end_src:>%s\n",get_string_from_trigger(data->cmd.scan_end_src));
>    printf("scan_end_arg:>%d\n",data->cmd.scan_end_arg);
>    (mode==0)?printf("stop_src:>%d\n",data->cmd.stop_src):printf("stop_src:>%s\n",get_string_from_trigger(data->cmd.stop_src));
>    printf("stop_arg:>%d\n",data->cmd.stop_arg);
>    printf("chanlist_len:>%d\n\n",data->cmd.chanlist_len);    
> }
> 
> void prepare_cmd(void)
> {
>                 
>     data->cmd.subdev = 0;
>     data->cmd.flags = 0;
> 
>     data->cmd.start_src = TRIG_NOW;
>     data->cmd.start_arg = 0;
> 
>     data->cmd.scan_begin_src = TRIG_TIMER;
>     data->cmd.scan_begin_arg = 10000000;
> 
>     data->cmd.convert_src = TRIG_TIMER;
>     data->cmd.convert_arg = 0;
> 
>     data->cmd.scan_end_src = TRIG_COUNT;
>     data->cmd.scan_end_arg = 1;
> 
>     data->cmd.stop_src = TRIG_COUNT;
>     data->cmd.stop_arg = 1000000000;
> 
>     data->cmd.chanlist = chanlist;
>     data->cmd.chanlist_len = 1;
> 
>     chanlist[0] = CR_PACK(0,0,0);
> 
>     data->cmd.data=0;
>     data->cmd.data_len=0;
> }
> 
> 
> int test_cmd(void)
> {
>     int ret=0;
>     
>     if (debug==1)
>     {
>       printf("\n\nTEST_CMD:\n");    
>       printf("Command before test:>\n");
>       show_cmd(1);     
>     }
>     
>     //Test if the command is valid.
>     if ((ret=comedi_command_test(dev, &data->cmd))!=0)
>     {
>       if (debug==1)
>       { 
>        printf("The first test has returned:%d\n\n",ret);
>        printf("Command after the first test:>\n");
>        show_cmd(1);
>       } 
>        //If the first test fails, then a second test is done to adjust the wrong parameters.
>        if ((ret=comedi_command_test(dev, &data->cmd))!=0)
>        {
>             if (debug==1)
>             {
>              printf("The second test has returned:%d\n\n",ret);
>              printf("Command after the second test:>\n");
>              show_cmd(1);
>             }
>             //If the second test fails, then a third test is performed.
>             if ((ret=comedi_command_test(dev, &data->cmd))!=0)
>             {
>               if (debug==1)
>               {
>                    printf("The third test has returned:%d\n\n",ret);
>                    printf("Comando after the third test:>\n");
>                    show_cmd(1);
>               }
>               return(ERROR);  //If the three tests fail then the command is invalid.
>             } 
>        }
>     }
>  return(OK);
> }
> 
> int main(void)
> {
> 
>   RT_TASK* task;    
>   int priority=0;   
>   int stack_size=0; 
>   int msg_size=0;   
>   SEM *s;
> 
>   struct sched_param mysched;
> 
>   mysched.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
>   if(sched_setscheduler( 0, SCHED_FIFO, &mysched ) == -1 ) 
>   {
>     puts("ERROR IN SETTING THE SCHEDULER");
>     perror("errno");
>     exit(1);
>   }
>   
>   signal(SIGINT, endme); 
>    
>   task = rt_task_init( nam2num("Name"), priority, stack_size, msg_size);
>   s=(SEM*)rt_get_adr(nam2num("BSEM"));
>   init_shared_memory();
>   dev=comedi_open(data->device);
>   prepare_cmd();
>   test_cmd();
>   data->flag=READY;
>   rt_sem_signal(s);  
>   
>    
>   rt_task_delete(task);
>   return 0;
> }
> 
> shared.h:
> 
> #include <rtai_shm.h>
> #include "comedi.h"
> 
> #ifndef _SHARED_H
> #define _SHARED_H
> 
> #define NOT_READY -1
> #define READY 1
> #define ERROR -2
> #define OK 2
> #define SHMNAM "SHMEM"
> 
> struct data_str
> {
>   char device[20];
>   comedi_cmd cmd;
>   unsigned int flag;
> };
> 
> #endif
> 
> Makefile:
> 
> obj-m    := kernel.o
> 
> KDIR    := /lib/modules/$(shell uname -r)/build
> PWD        := $(shell pwd)
> EXTRA_CFLAGS := -mhard-float -D__KERNEL__ -DMODULE -O2 -Wall -I/usr/local/include -I/usr/realtime/include -I/usr/include
> 
> default:
>     $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
>     gcc -g -Wall -lcomedi $(shell /usr/realtime/bin/rtai-config --lxrt-cflags) $(shell /usr/realtime/bin/rtai-config --lxrt-ldflags) -llxrt -I/usr/realtime/include -I/usr/include -lm user.c -o user 
> 
> clean:
>     -rm *.o
> 
> I prepare a comedi command in user space and then I pass it through RTAI shared memory to kernel space where it should be executed. When the command is executed I get the following kernel message:
> 
> BUG: spinlock bad magic on CPU#14, /1116405760
> 
>   lock: cccccccc, .magic: 00000000, .owner: <none>/-1, .owner_cpu: 0
> 
>   <c02072e4> _raw_spin_lock+0x20/0xea  <c0315172> _spin_lock_irqsave
> 
>  +0x1f/0x25
> 
>   <c0315100> _spin_lock+0xb/0xd  <c0126c74> __mod_timer+0x79/0x9e
> 
>   <f90f38ac> waveform_ai_cmd+0xdc/0xe8 [comedi_test]  <f912645b> fun
> 
>  +0x5b/0x70 [kernel]
> 
>   <f8e7f9f3> rt_startup+0x56/0x71 [rtai_sched]  <f9126400> fun+0x0/0x70
> 
>  [kernel]
> 
>   =======================
> 
>  Default Trap Handler: vector 14: Suspend RT task f9128300
> 
> 
> I need that the comedi_callback is executed in realtime.
> 
> Is there something I am missing?
> 
>  
> Thank you for your help.
> 
> 
> 
> 
> 
> 
>       
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Rtai mailing list
> Rtai at rtai.org
> https://mail.rtai.org/cgi-bin/mailman/listinfo/rtai



More information about the Rtai mailing list