Xenomai Timer Task Example
Here we have two simple Xenomai hard real time user-space timer examples. They actually do the
same, but with different approaches. Both examples are for Xenomai 2.1 - everything is compiled
into the kernel, so we don't need to load kernel modules before starting the examples.
UPDATE:
Example #2 works only if the periodic timer support is enabled (it is disabled by default). Enable it
when configuring the kernel:
Real-time sub-system --->
Machine --->
[ ] Enable periodic timer support
As a sidenote, make sure ipipe is enabled:
General setup --->
[*] Interrupt pipeline
From the Xenomai-core maillist:
Hannes Mayer: What's the reason why the periodic mode is disabled by default ?
Philippe Gerum: Because AFAICT, most people would rather use the aperiodic timing mode in usual configurations
for a much better accuracy. Since the periodic mode uses the available hw PIT and programs it
once (or even some decrementer but without handling the time drift when reprogramming it after
each shot), it suffers from cumulated rounding errors of the period. If you look at the jitter
results of a trivial periodic loop over a broad timescale, you will see the wakeup time irremediably
drift, whilst the average interval between shots remains stable and reasonably accurate. The
periodic timer should be used for configurations that only need to enforce delays or timeouts,
and not, well, precise timings."
Compile the program "timer.c" with "make" (Makefile below).
Run "timer" (press CTRL-C to end it).
Example #1 - timer.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <native/task.h>
#include <native/queue.h>
#include <native/intr.h>
#define STACK_SIZE 8192
#define STD_PRIO 1
RT_TASK test_task_ptr;
int int_count = 0;
int end = 0;
// --s-ms-us-ns
RTIME task_period_ns = 1000000000llu;
void testtask(void *cookie){
int count = 0;
int ret;
unsigned long overrun;
ret = rt_task_set_periodic(NULL, TM_NOW, rt_timer_ns2ticks(task_period_ns));
if (ret) {
printf("error while set periodic, code %d\n",ret);
return;
}
while(!end){
ret = rt_task_set_mode(0, T_PRIMARY, NULL);
if (ret) {
printf("error while rt_task_set_mode, code %d\n",ret);
return;
}
ret = rt_task_wait_period(&overrun);
if (ret) {
printf("error while rt_task_wait_period, code %d\n",ret);
return;
}
count++;
printf("message from testtask: count=%d\n", count);
fflush(NULL);
}
}
// signal-handler, to ensure clean exit on Ctrl-C
void clean_exit(int dummy) {
printf("cleanup\n");
end = 1;
rt_task_delete(&test_task_ptr);
printf("end\n");
}
int main(int argc, char *argv[]) {
int err, ret;
printf("start\n");
// install signal handler
signal(SIGTERM, clean_exit);
signal(SIGINT, clean_exit);
// start timer -> depricated in Xeno 2.2
/* ret = rt_timer_start(TM_ONESHOT);
switch (ret) {
case 0: printf("timer started\n");
break;
case -EBUSY: printf("timer is running\n");
break;
case -ENOSYS: printf("can't start timer\n");
return ret;
}
*/
mlockall(MCL_CURRENT | MCL_FUTURE);
err = rt_task_spawn(&test_task_ptr, "Timer", STACK_SIZE, STD_PRIO, 0, &testtask, NULL);
if (err) {
printf("error rt_task_spawn\n");
return 0;
}
// wait for signal & return of signal handler
pause();
fflush(NULL);
return 0;
}
Example #2 - timer.c
Remember: This works only if periodic timer support is enabled (see above).
Usually you should use aperiodic mode (example #1) to have better accuracy.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <native/task.h>
#include <native/queue.h>
#include <native/intr.h>
#define STACK_SIZE 8192
#define STD_PRIO 1
RT_TASK test_task_ptr;
int int_count = 0;
int end = 0;
void testtask(void *cookie){
int count = 0;
while(!end){
rt_task_sleep(1000); // sleep 1 sec (1000 ticks, 1ms each)
count++;
printf("message from testtask: count=%d\n", count);
fflush(NULL);
}
}
// signal-handler, to ensure clean exit on Ctrl-C
void clean_exit(int dummy) {
printf("cleanup\n");
end = 1;
rt_task_delete(&test_task_ptr);
printf("end\n");
}
int main(int argc, char *argv[]) {
int err;
printf("start\n");
// install signal handler
signal(SIGTERM, clean_exit);
signal(SIGINT, clean_exit);
// start timer -> depricated in 2.2
/* err = rt_timer_start(1000000); // 1ms ticks
if (err) {
printf("error rt_timer_start - did you 'Enable periodic timer support' ?\n");
return 0;
}
*/
mlockall(MCL_CURRENT | MCL_FUTURE);
err = rt_task_spawn(&test_task_ptr, "Timer", STACK_SIZE, STD_PRIO, 0, &testtask, NULL);
if (err) {
printf("error rt_task_spawn\n");
return 0;
}
// wait for signal & return of signal handler
pause();
fflush(NULL);
return 0;
}
Makefile
prefix := $(shell xeno-config --prefix)
ifeq ($(prefix),)
$(error Please add <xeno-install>/bin to your PATH variable)
endif
CC = $(shell xeno-config --cc)
LXRT_CFLAGS = $(shell xeno-config --xeno-cflags)
LXRT_LDFLAGS = $(shell xeno-config --xeno-ldflags)
all: timer
timer: timer.c
$(CC) $(LXRT_CFLAGS) $(LXRT_LDFLAGS) -lnative -o $@ $<
clean:
rm -f *.o timer
.PHONY: clean
Last-Modified: Sun, 23 Jul 2006 19:36:57 GMT