カーネルをハックする必要はありません。スケジューラキューからプロセスを移動するだけです。
#include<sched.h>
struct sched_param param;
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
if( sched_setscheduler( 0, SCHED_FIFO, ¶m ) == -1 )
{
perror("sched_setscheduler");
return -1;
}
これ以降、プロセスはcat /proc/sys/kernel/sched_rt_runtime_us
各cat /proc/sys/kernel/sched_rt_period_us
ミリ秒のタイムセグメントからミリ秒を受信し、その時間中にプリエンプションされるリスクなしに実行が中断されません(実際には、BerryBootのデフォルトでは毎秒0.95秒)。これらの値を使用しますが、ここでの目的にはこれ以上必要ありません。
私はclock_gettime()
遅延を計るのに基づいて、ミリ秒単位のタイマー機能を使用しています(これは必要な精度です)。
呼び出しはtimer(1)
それをリセットし、呼び出しtimer(0)
はリセットからの時間を返します。
#include<time.h>
typedef unsigned long long ulong64;
ulong64 timer(unsigned char reset)
{
struct timespec t;
static struct timespec lt={0,0};
clock_gettime(CLOCK_REALTIME, &t);
if(reset)
{
lt.tv_sec = t.tv_sec;
lt.tv_nsec = t.tv_nsec;
}
int r = ((ulong64)(t.tv_sec - lt.tv_sec))*1000 + (t.tv_nsec - lt.tv_nsec)/1000000;
return r;
}
rt
これをコンパイルする-lrt
には、ライブラリに対してリンクする必要があります-gccコマンドに追加します。
次に、メインループについて説明します。「ユーザーリクエスト」にスイッチ入力を使用していますが、ネットワーク、タイマーなど何でも使用できます。必要なのは、ブール値をに取得することだけですin
。
while(1)
{
//when idle, return a lot of CPU time back to the system.
//A call every 100ms is perfectly sufficient for responsive reaction.
usleep(100000);
in = bcm2835_gpio_lev(SWITCH_PIN);
out = bcm2835_gpio_lev(TRIAC_PIN);
if(in==out) continue; //nothing to do; wait user input, return control to system.
//The output needs to be changed.
//First, let's wait for zero-crossing event.
timer(TIMER_RESET);
zx = bcm2835_gpio_lev(ZEROXING_PIN);
//We don't want to freeze the system if the zero-xing input is broken.
//If we don't get the event within reasonable time,
// (like three half-sines of the power; ZEROXING_TIMEOUT = 70)
// we're going to bail.
while(timer(TIMER_READ) < ZEROXING_TIMEOUT)
{
if(zx != bcm2835_gpio_lev(ZEROXING_PIN))
{
//Event detected.
timer(TIMER_RESET);
break;
}
}
if(timer(TIMER_READ) >= ZEROXING_TIMEOUT) continue; //Zero-crossing detection is broken, try again soon.
//Now we are mere milliseconds after zero-crossing event arrived
// (but it could have taken some time to arrive) so let's wait for the next one, making adjustments for the system delay.
// This is to be worked out using an oscilloscope and trial and error.
// In my case BIASED_DELAY = 19.
while(timer(TIMER_READ)<BIASED_DELAY) ;
//We can reasonably expect if we perform this right now:
bcm2835_gpio_set_pud(TRIAC_PIN, in);
//the signal will reach the output right on time.
// The 100ms delay on return to start of the loop should be enough
// for the signals to stabilize, so no need for extra debouncing.
}