ともに夢の実現を目指して

本家サイトです。最新版ダウンロードがあります。
Xenomaiを利用する色々なサンプルがあります。
リアルタイム・ネットワークプロトコル・スタック
リアルタイム・イーサネットプロトコル
ロボット制御ライブラリ、フレームワーク
Xenomai » テスト
xenomai共有ライブラリを使うようにするために、/etc/ld.so.conf.d/xenomai.confファイルを新規作成して、その中に"/usr/xenomia/lib"を追加して保存します。その後、ldconfig。
/etc/manpath.configを修正して、"MANDATORY_MANPATH /usr/xenomai/share/man"の1行を追加します。
DIOボードとGPIBボードをPCIスロットに入れてUbuntu-9.04を立ち上げます。
lspci -v で、ボードのIOアドレスを調べると、表示の最後が以下のようになります。
03:01.0 Multimedia controller: Contec Co., Ltd Device a1f2
Subsystem: Contec Co., Ltd Device a1f2
Flags: medium devsel, IRQ 5
I/O ports at df00 [size=32]
03:02.0 Multimedia controller: Contec Co., Ltd Device c104
Subsystem: Contec Co., Ltd Device c104
Flags: bus master, slow devsel, latency 32, IRQ 10
I/O ports at de00 [size=128]
I/O ports at dd00 [size=64]
03:01.0がDIOボード(CONTEC PIO-32/32F(PCI)H)。
Device ID : 0xa1f2
IRQ : 5
IOアドレス : 0xdf00
03:02.0がGPIBボード(CONTEC GP-IB(PCI)F)。
Device ID : 0xc104
IRQ : 10
IOアドレス : 0xde00
ベンダーIDは、
cat /sys/bus/pci/devices/0000:03:01.0/vendor
または
cat /sys/bus/pci/devices/0000:03:02.0/vendor
で判明する。結果は、0x1221。
ちなみに、以下のようにvendor_id,device_idが判れば、pci_get_device関数、pci_resource_start関数、pci_read_config_byte関数から、IRQ番号とIOアドレスが取得できます。(以下はエラーチェック省略)
unsigned int vendor_id;
unsigned int device_id;
struct pci_dev* dev_dio;
unsigned long ioadr;
char irq;
vendor_id = 0x1221;
device_id = 0xa1f2;
dev_dio = pci_get_device(vendor_id,device_id,NULL);
ioadr = pci_resource_start(dev_dio,0);
pci_read_config_byte(dev_dio,PCI_INTERRUPT_LINE,&irq);
modprobe xeno_timerbench
/usr/xenomai/bin/latency -t 1 -h -s -p 100
-p オプションは100u周期を指定している。
RTDの1行はサンプリング1000個らしい。
大体20行になる時に「CTRL+C」で表示を終了させると、以下のような結果となります。
== Sampling period: 100 us
== Test mode: in-kernel periodic task
== All results in microseconds
warming up...
RTT| 00:00:01 (in-kernel periodic task, 100 us period, priority 99)
RTH|-----lat min|-----lat avg|-----lat max|-overrun|----lat best|---lat worst
RTD| -2.403| -2.014| 4.728| 0| -2.403| 4.728
RTD| -2.607| -1.993| 4.210| 0| -2.607| 4.728
RTD| -2.785| -1.981| 4.815| 0| -2.785| 4.815
RTD| -2.751| -1.998| 6.774| 0| -2.785| 6.774
RTD| -2.623| -1.992| 7.161| 0| -2.785| 7.161
RTD| -2.759| -1.999| 7.304| 0| -2.785| 7.304
RTD| -2.842| -1.987| 5.779| 0| -2.842| 7.304
RTD| -2.733| -2.019| 5.907| 0| -2.842| 7.304
RTD| -2.775| -1.991| 7.336| 0| -2.842| 7.336
RTD| -2.612| -1.985| 3.661| 0| -2.842| 7.336
RTD| -2.756| -1.999| 6.926| 0| -2.842| 7.336
RTD| -2.797| -1.999| 4.517| 0| -2.842| 7.336
RTD| -2.908| -1.987| 5.414| 0| -2.908| 7.336
RTD| -2.717| -2.004| 4.897| 0| -2.908| 7.336
RTD| -2.731| -1.993| 9.447| 0| -2.908| 9.447
RTD| -2.732| -2.003| 4.657| 0| -2.908| 9.447
RTD| -2.726| -1.994| 8.440| 0| -2.908| 9.447
RTD| -2.761| -1.999| 4.724| 0| -2.908| 9.447
RTD| -2.741| -1.999| 5.091| 0| -2.908| 9.447
RTD| -2.714| -2.009| 5.505| 0| -2.908| 9.447
---|--param|----range-|--samples
HSD| min| 2 - 3 | 20
---|--param|----range-|--samples
HSD| avg| 0 - 1 | 22982
HSD| avg| 1 - 2 | 12173
HSD| avg| 2 - 3 | 171933
HSD| avg| 3 - 4 | 16
HSD| avg| 4 - 5 | 35
HSD| avg| 5 - 6 | 6
HSD| avg| 6 - 7 | 4
HSD| avg| 7 - 8 | 5
HSD| avg| 8 - 9 | 1
HSD| avg| 9 - 10 | 1
---|--param|----range-|--samples
HSD| max| 3 - 4 | 1
HSD| max| 4 - 5 | 7
HSD| max| 5 - 6 | 5
HSD| max| 6 - 7 | 2
HSD| max| 7 - 8 | 3
HSD| max| 8 - 9 | 1
HSD| max| 9 - 10 | 1
HSH|--param|--samples-|--average--|---stddev--
HSS| min| 20| 2.000| 0.000
HSS| avg| 207156| 1.720| 0.653
HSS| max| 20| 5.300| 1.593
---|------------|------------|------------|--------|-------------------------
RTS| -2.908| -1.997| 9.447| 0| 00:00:21/00:00:21
Xenomai周期テスト用のプログラムを作り、実際の動作を見てみます。以下がテスト用のサンプルプログラムとMakefile。(※これらは、こちらからダウンロードできます。)
PIO-32/32F(PCI)HというPCIボードは5µsの性能があると書かれているので大変性能のよいボードのようです。以下のプログラムでは、outb_p()ではなくoutb()を使用しています。IOポートへのアクセスはoutb_p()を使用するのが一般的だと思いますが5µs周期では、このDIOボードの性能を生かせないようなのでoutb()を使っています。ただ、10µs以上の周期では、通常のoutb_p()を使用して問題は無いと思われます。
(使い方)
insmod rt_test_dio.ko port=<IOアドレス> irq=<割込み番号> interval=<設定周期(µs)>
rt_test_dio.c
//$$---------------------------------------------------
//$$ rt_test_dio.c
//$$ insmod rt_test_dio.ko port=0xdf00 irq=5 interval=100
//$$---------------------------------------------------
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <native/task.h>
#include <native/timer.h>
#include <native/intr.h>
//$$-----
//$$ task
//$$------
#define TASK_PRIO 2 // Highest RT priority
#define TASK_MODE T_FPU|T_CPU(0) // Uses FPU, bound to CPU #0
#define TASK_STKSZ 4096 // Stack size (in bytes)
static unsigned int port = 0xdf00;
static unsigned int irq = 5;
static unsigned int interval= 50; // µsec
module_param(port ,uint,S_IRUGO);
module_param(irq ,uint,S_IRUGO);
module_param(interval,uint,S_IRUGO);
static RT_TASK task_desc;
static void
task_dio(void* t)
{ RTIME rtInterval = rt_timer_ns2ticks((RTIME)interval*1000);
unsigned long overrun = 0L;
unsigned long count_overrun = 0L;
unsigned int count = 0;
int ret ;
printk("RUN Dio task.\n");
ret = rt_task_set_periodic(NULL, TM_NOW, rtInterval);
if(ret) printk("ERROR: cannot set periodic\n");
while(1)
{ ret = rt_task_wait_period(&overrun);
if(ret == -ETIMEDOUT) count_overrun += overrun ;
if(count == 0)
{ outb(0x1, port+0x4); // O-40
count++;
}
else
{ outb(0x0, port+0x4); // O-40
count--;
}
}
}
int
xinit_module(void)
{ int err;
err = rt_task_create(&task_desc,
"MyTaskName",
TASK_STKSZ,
TASK_PRIO,
TASK_MODE);
if(err)
{ printk("ERROR: cannot create task.\n");
return 0;
}
printk("Loading DIO test module.\n");
rt_task_start(&task_desc, &task_dio, NULL);
return 0;
}
void
xcleanup_module(void)
{ printk("Unloading DIO test module.\n");
rt_task_suspend (&task_desc);
rt_task_delete (&task_desc);
outb_p(0x0, port+0x4); // O-40
}
module_init(xinit_module);
module_exit(xcleanup_module);
MODULE_LICENSE("GPL");
Makefile
obj-m := rt_test_dio.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
EXTRA_CFLAGS := -I/usr/xenomai/include -I/usr/include/
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
古いFluke192スコープメータでの観察です。周期は、5µs、6µs、10µs、50µs、100µs、1msです。このプログラムを動作させながら、FirefoxでYoutubeを見たり、ファイルブラウザ等でディスクアクセスをしても、全く変動はありませんので、WindowsやLinuxで動作するプログラムとは違う挙動を示しています。
ここでの「周期」とは、このプログラムで設定した"interval"ですので、以下のようなスコープメータで観察した場合の、1周期は2倍の長さになります。例えば、以下の"10µs周期"の表示では10µsのON状態+10µsのOFF状態ですので1周期は20µsになります。
(※ 12V電源からLEDと抵抗をつないで、抵抗の両端を測定したものです。)
(※10µs周期以下の波形では、ON時間とOFF時間は非対称になっています。DIOをONにしてから3µs程度遅れてから電圧が鋭く立ち上がり、OFFにした場合は電圧波形がなだらかに下がる特徴があります。LEDの特性が現れているのでしょう。)
(1) 5µs周期
(2) 6µs周期

(3) 10µs周期


(4) 50µs周期

(5) 100µs周期

(6) 1ms周期
