HRTを使うとより精度の高い周期処理ができそうなことはわかったのですが、優先順位自体は触っていないので、他の処理に左右されそうな気がします。そこで調べてみると、スケジューラの設定を変更するとリアルタイムポリシーが設定できることがわかったので試してみました。
説明は何だかんだ言ってもmanページが詳しいようです。
早速いろいろ調べてプログラムを作ってみました。ベースは前回のHRTでgpioを制御するものです。
これをちょっとだけ修正して、スケジューリングの設定をするとともに、50us周期でgpioをトグルさせてみました。
// // SCHEDULER & HRTを使ったLED点滅 // // #include <sched.h> static struct timespec hrt_now; static struct timespec hrt_next; void test(long tick) { int v; int MinPriority; int MaxPriority; struct sched_param prio; setup_io(); INP_GPIO(7); // must use INP_GPIO before we can use OUT_GPIO OUT_GPIO(7); v = 1; // SCHED_FIFOポリシーの優先度の最大値/最小値を得る MinPriority=sched_get_priority_min(SCHED_FIFO); printf("Min priority for FIFO policy is %d\n",MinPriority); MaxPriority=sched_get_priority_max(SCHED_FIFO); printf("Max priority for FIFO policy is %d\n",MaxPriority); // スケジューリングポリシーと優先度最大を設定する prio.sched_priority = MaxPriority; if(sched_setscheduler(0,SCHED_FIFO,&prio)<0){ perror("Schedule set error\n"); exit(0); } clock_gettime(CLOCK_MONOTONIC, &hrt_now); while(1){ hrt_next.tv_nsec = hrt_now.tv_nsec + tick; if(hrt_next.tv_nsec >= 1000000000){ hrt_next.tv_nsec -= 1000000000; hrt_next.tv_sec = hrt_now.tv_sec + 1; } else { hrt_next.tv_sec = hrt_now.tv_sec; } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &hrt_next, NULL); hrt_now = hrt_next; gpio_write(7,v); v = 1 - v; } } int main(int argc, char *argv[]) { test(50000); return EXIT_SUCCESS; }
28行目でsetschedulerの第一パラメータ(pid)に0を指定していますが、ここで0を指定すると自分自身のスケジュールポリシーが設定できるようです。
早速、コンパイルして実行してみました。
pi@raspberrypi ~/HRT $ gcc prio_hrt_gpio.c -o prio_hrt_gpio -lrt pi@raspberrypi ~/HRT $ sudo ./prio_hrt_gpio Min priority for FIFO policy is 1 Max priority for FIFO policy is 99
オシロスコープでポートを観測してみると、
となり、概ね50us周期でトグルしていることが確認できました。ただ、20us程度の範囲で結構ブレることがあるようで、この辺が機能盛りだくさんのLinuxの限界ということなのでしょうか。