Using Xenomai on PortuxG20/Stamp9G20

Introduction

Some tasks have real time requirements. Xenomai is one way to make Linux real time capable. This guide shows you how to enable the Xenomai extensions on the Stamp9G20 and PortuxG20.

Requirements

  • Linux v2.6.35.9 sources: Download
  • Xenomai 2.5.6 sources: Download
  • Installed toolchain
  • Installed fakeroot if you don't want to use root rights during xenomai install procedure

Compiling the Kernel

Create a directory called xenomai and extract the Linux sources and the Xenomai sources to this directory. It should now contain the directories linux-2.6.35.9 and xenomai-2.5.6. Enter the directory xenomai-2.5.6 and issue the following command:

scripts/prepare-kernel.sh --linux=../linux-2.6.35.9 --adeos=ksrc/arch/arm/patches/adeos-ipipe-2.6.35.9-arm-1.18-01.patch --arch=arm

Now enter the kernel source directory and issue the command:

make ARCH=arm stamp9g20_defconfig

Maybe you want to tune the config a bit. After that compile the kernel as usual and put it in the flash of your device.

Installing the userspace components

Go back to the xenomai-2.5.6 directory and enter the command:

./configure CC=/usr/local/angstrom/arm/bin/arm-angstrom-linux-gnueabi-gcc --host=arm-linux-gnueabi --enable-arm-eabi --enable-arm-mach=at91sam9 --disable-arm-tsc

Now compile the sources with make and install the compiled xenomai files to a directory from where you can copy it to your target device. For this step you have to use an absolute path:

fakeroot make install DESTDIR=$path

If you don't have fakeroot installed, you can also use

su -c "make install DESTDIR=$path"

or

sudo make install DESTDIR=$path

You can now copy the contents of $path to the root filesystem of your device. Do not copy the contents of $path/dev if you used the fakeroot method.

Testing

To test if everything worked, try one of the test programs. It should look like that:

root@portuxg20:~# /usr/xenomai/bin/latency 
== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|     55.232|     64.922|     67.829|       0|     0|     55.232|     67.829
RTD|     -1.938|     -0.969|     26.162|       0|     0|     -1.938|     67.829
RTD|     -1.938|     -0.969|     21.317|       0|     0|     -1.938|     67.829

If everything worked you can now start developing your real time applications.

A sample application

In most cases you do not need your whole application to be capable of real time. The following example consists of two programs - a real time daemon that can be used to gather data or to do other critical tasks and a normal user space program, called client, that might do some processing on the data before it uses Ethernet (or another communication device that normally conflicts with real time efforts) to transmit the results.

Both programs are connected by a real time pipe provided by Xenomai. While the real time daemon uses the Xenomai native API, the pipe seamlessly integrates into the client program as file.

The real time daemon

/*
	Xenomai demo - real time daemon
	Author    : M.Langer
	Copyright : taskit GmbH
	www.taskit.de

	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

		1. Redistributions of source code must retain the above copyright
		   notice, this list of conditions and the following disclaimer.
		2. Redistributions in binary form must reproduce the above copyright
		   notice, this list of conditions and the following disclaimer in the
		   documentation and/or other materials provided with the distribution.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT OWNER AND CONTRIBUTORS “AS IS”
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/mman.h>

/* xenomai headers */
#include <native/task.h>
#include <native/timer.h>
#include <native/pipe.h>

#define ALLOC(p, n)  p = malloc(n); while(p == NULL) {sleep(1); p = malloc(n);};

/* global structures */
RT_TASK demo_task;
RT_PIPE msg_pipe;

/* default settings */
uint16_t freq = 10;

void demo_task_func(void* args)
{
	RTIME t;
	RTIME period;
	char* str_buf;
	uint16_t h, m, s, milli, micro;

	/* allocate string buffer */
	ALLOC(str_buf, 256);

	/* setup periodic timer */
	period = 1000000000 / freq;
	rt_task_set_periodic(NULL, TM_NOW, period);

	/* real-time application loop */
	while(1)
	{
		/* get time */
		t = rt_timer_read();

		/* do something - e.g. print time to pipe */
		micro = (t / 1000) % 1000;
		milli = (t / 1000000) % 1000;
		s = (t / 1000000000) % 60;
		m = (t / 1000000000 / 60) % 60;
		h = (t / 1000000000 / 60 / 60) % 24;
		sprintf(str_buf, "%02d:%02d:%02d.%03d.%03d\n", h, m, s, milli, micro);
		rt_pipe_write(&msg_pipe, str_buf, strlen(str_buf), P_NORMAL);

		/* sleep till next step */
		rt_task_wait_period(NULL);
	}

	/* clean up */
	free(str_buf);
}

void catch_signal(int sig)
{
	/* nothing to handle, yet */
}

/* main loop */
int main(int argc, char** argv)
{
	/* catch signals */
	signal(SIGTERM, catch_signal);
	signal(SIGINT, catch_signal);

	/* disable paging */
	mlockall(MCL_CURRENT | MCL_FUTURE);

	/* create real time pipe */
	rt_pipe_create(&msg_pipe, "msg_pipe", P_MINOR_AUTO, 0);

	/* launch real time task */
	rt_task_create(&demo_task, "demo", 0, 99, 0);
	rt_task_start(&demo_task, &demo_task_func, NULL);

	/* wait for terminating signal */
	pause();

	/* clean up */
	rt_task_delete(&demo_task);
	rt_pipe_delete(&msg_pipe);

	return(0);
}

The client program

/*
	Xenomai demo - client application (no real time)
	Author    : M.Langer
	Copyright : taskit GmbH
	www.taskit.de

	All rights reserved.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

		1. Redistributions of source code must retain the above copyright
		   notice, this list of conditions and the following disclaimer.
		2. Redistributions in binary form must reproduce the above copyright
		   notice, this list of conditions and the following disclaimer in the
		   documentation and/or other materials provided with the distribution.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT OWNER AND CONTRIBUTORS “AS IS”
	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
	POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ALLOC(p, n)  p = malloc(n); while(p == NULL) {sleep(1); p = malloc(n);};

/* main loop */
int main(int argc, char **argv)
{
	int rt_pipe_fd;
	char* str_buf;
	ssize_t n;

	/* ignore broken pipes */
	signal(SIGPIPE, SIG_IGN);

	/* open rt pipe */
	rt_pipe_fd = open("/proc/xenomai/registry/native/pipes/msg_pipe", O_RDONLY);

	/* allocate string buffer */
	ALLOC(str_buf, 256);

	/* loop while pipe is open */
	do
	{
		/* print string received through rt pipe */
		n = read(rt_pipe_fd, str_buf, sizeof(str_buf));
		if(n > 0)
			write(STDOUT_FILENO, str_buf, n);
	} while(n > 0);

	/* clean up */
	free(str_buf);
	close(rt_pipe_fd);

	return(0);
}
AttachmentSize
xenomai-test.zip3.49 KB