Xenomai: Hard Real Time Driver Example Tutorial with MMAP using the RTDM (Real Time Driver Model)

Xenomai: Hard Real Time Driver Example Tutorial with MMAP using the RTDM (Real Time Driver Model)

Here we have a template/skeleton of a hard real time driver with MMAP, utilizing the RTDM (Real Time Driver Model) on Xenomai 2.1.

UPDATE: With the help of Jan Kiszka I'm working on version 2.0 of the standard driver template. Basically the changes from V1.0 to V2.0 will be in regard of generalizing the driver, but also issues regarding RT/non-RT and calling the driver from another kernel module will be addressed.

The user space demo application writes a string to the driver, then tries to read from it. The driver read operation is blocking until the interrupt service routine in the driver is signalling to unblock the read operation. This can be used to signal when data is ready. Then the user space app is doing some MMAP stuff (if #define USEMMAP is enabled in the include file inc.h) and finally some ioctl operation.

All this user space stuff is done in a hard real time task created with rt_task_create and started with rt_task_start. If your read operation does not block, you can use rt_task_wait_period() in the task. But if you use a blocking read (e.g. read unblocks only when data is ready), you can't use rt_task_wait_period(), otherwise you get ETIMEDOUT 110 = Connection timed out after the next rt_task_wait_period (see comments in user.c).

If you use the parallel port interrupt by commenting #define TIMERINT, you need to make a "null-modem" for the parallel port - connect any output pin (pin 2-9) with the IRQ pin (pin 10 = ACK). If #define TIMERINT is present, the linux timer interrupt is used - only every 100th interrupt is used to unblock the driver read operation. The timer interrupt is the default setting.

So far so good. That was the user space demo application. Now lets dive into the hard real time driver.

The driver is a kernel module, so it has some init and cleanup functions:

/**********************************************************/
/*            INIT DRIVER                                 */
/**********************************************************/
int init_module(void)
{
    return rtdm_dev_register(&demo_device);
}

/**********************************************************/
/*            CLEANUP DRIVER                              */
/**********************************************************/
void cleanup_module(void)
{
    rtdm_dev_unregister(&demo_device, 1000);
}

Next we need to define some operations which are supported by the driver (e.g. read, write, ioctl...). The important thing with RTDM is that you can define RT (real time) and NRT (non real time) operations, so it's possible to use the RT driver for NRT stuff aswell.

/**********************************************************/
/*            DRIVER OPERATIONS                           */
/**********************************************************/
static struct rtdm_device demo_device = {
    struct_version:     RTDM_DEVICE_STRUCT_VER,

    device_flags:       RTDM_NAMED_DEVICE,
    context_size:       sizeof(struct demodrv_context),
    device_name:        DEV_FILE,

    open_rt:            demo_open_rt,
    open_nrt:           demo_open_rt,

    ops: {
        close_rt:       demo_close_rt,
        close_nrt:      demo_close_rt,

        ioctl_rt:       demo_ioctl_rt,
        ioctl_nrt:      demo_ioctl_rt,

        read_rt:        demo_read_rt,
        read_nrt:       NULL,

        write_rt:       demo_write_rt,
        write_nrt:      NULL,

        recvmsg_rt:     NULL,
        recvmsg_nrt:    NULL,

        sendmsg_rt:     NULL,
        sendmsg_nrt:    NULL,
    },

    device_class:       RTDM_CLASS_EXPERIMENTAL,
    device_sub_class:   222,
    driver_name:        DRV_NAME,
    peripheral_name:    DEV_FILE_NAME,
    provider_name:      "-",
    proc_name:          demo_device.device_name,
};

Well, what else is important:
There is the driver context struct:

struct demodrv_context {
[...]
};

It is used for storing various information about the driver and it's status.
It is accessible via dev_private from the driver functions:

int demo_ioctl_rt(struct rtdm_dev_context   *context,
                  rtdm_user_info_t          *user_info,
                  int                       request,
                  void                      *arg)
{
    struct demodrv_context  *my_context;
[...]
    my_context = (struct demodrv_context *)context->dev_private;

I guess now we're at a stage where the source code tells more than 1000 words ;-)
So here we go:

  • unavailable Real Time Driver Source Code realtimedriver.c
  • unavailable Real Time Driver User Space Application user.c
  • unavailable Real Time Driver extra files: include file inc.h and Makefile

Compile everything with the new standard Makefile for kernel and userspace applications for Xenomai.

Insert the kernel module with either

# insmod ./realtimedriver.o

-or-

# insmod ./realtimedriver.ko

depending on your kernel version.

Start the user-space application with

./user

and you'll see an output like this:

# ./user
PRESS CTRL-C to EXIT
timer started
demodev0 opened
my_task created
starting my_task
ioctl = 0
*p = 1234, p = 0xb7df1000
WRITE: written=17 sz=17
READ: read=CAPTAIN 0
MMAP: *((int *)mmappointer + 10) = 1001
IOCTL: readbackcounter=1
WRITE: written=17 sz=17
READ: read=CAPTAIN 1
MMAP: *((int *)mmappointer + 10) = 1002
IOCTL: readbackcounter=2
WRITE: written=17 sz=17
READ: read=CAPTAIN 2
demodev0 (write) -> invalid fd or context
exit
demodev0 (user) -> closed
delete my_task
stop timer
exit

You see that the timer is started, the real time driver is opened (don't try to find "demodev0" in /dev/ - it's not there - this is an RTDM internal identifier). The hard real time task is created, started and off the fun goes.

At the beginning of the real time task, the pointer for the MMAP'ed region is fetched via ioctl. Then the task starts to write to the driver - the string is read back from the driver as soon as the interrupt service routine (ISR) unblocks the read operation when an interrupt (IRQ) occurs. Furthermore some MMAP operation is performed and some ioctl write and read.

Press CTRL-C to end the userspace application.
Remove the module with:

# rmmod realtimedriver

I've put unusually many comments in the source code this time, so figuring out the rest should be easy :-)

Developed and tested on Xenomai 2.1-rc3 with kernel 2.4.32 and 2.6.15 with the ADEOS IPIPE patches adeos-ipipe-2.4.32-i386-1.1-03.patch and adeos-ipipe-2.6.15-i386-1.2-01.patch.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值