[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