バックナンバーはこちら。
https://www.simulationroom999.com/blog/model-based-of-minimum-2-backnumber/
はじめに
前回はDAQパケット送信周期の精度が悪い理由を確認した。
イベントチャンネルがそもそも15[ms]駆動になっており、
それの原因がSleep(10)。
Sleep(10)は「少なくとも10[ms]以上待つことを保証」であり、実際は15[ms]で返ってくることが多い。
これがDAQパケットの15[ms]送信周期の大本の原因となる。
これに対して小手先の修正ではどうにもならないが、
ある程度の対策も考えているのでそれを確認していく。
登場人物
博識フクロウのフクさん
イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1
エンジニア歴8年の太郎くん
イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1
DAQパケット送信周期精度改善の方針
で、改善方針はどうなるの?
まぁ時間精度に関わるところだし、
実は今までもやって来た手法ではあるのだが、
マルチメディアタイマを使用する。
あー、何回か使ったねー。
実績としては1[ms]周期ってのも作れたはず。
そうそう。
その実績があるんで、今回も採用って感じだ。
修正コード
で、具体的な修正コードは?
一応私の方で用意して見た。
マルチメディアタイマから1[ms]周期で呼び出されるコールバック関数はこんな感じだ。
// Task Sheduler
void main_handler() {
WORD i = 0;
WORD j = 0;
gTimer += 1;
/* 10ms Task ECU Simulation */
if ((gTimer % 10) == 0) {
ecuCyclic();
}
/* Event Channel 1 is cyclic 1 ms */
#ifdef XCP_ENABLE_DAQ
XcpEvent(3);
#endif
/* Event Channel 1 is cyclic 10 ms */
if ((gTimer % 10)==0) {
#ifdef XCP_ENABLE_DAQ
#ifdef XCP_DPRAM_SERVER
dpramServerTriggerTask(1);
#else
XcpEvent(1);
#endif
#endif
}
if (gTimer % 100 == 0) {
/* Event Channel 2 is cyclic 100 ms */
#ifdef XCP_ENABLE_DAQ
XcpEvent(2);
#endif
/* Flush every 100ms */
ApplXcpSendFlush();
}
/* XCP driver background processing */
#ifdef XCP_ENABLE_CHECKSUM
XcpBackground();
#endif
return 0;
}
そして、マルチメディアタイマ起動側のコードはこれ。
xcpsim.cのmain関数に差し込むコードになるな。
// MarutimediaTimer Start
_timeBeginPeriod(1);
setcallback(main_handler);
ちなみに、
Windows依存のヘッダとの衝突が心配だったので、stub.cというソースコードを作ってその中でWindowsAPIを呼ぶようにしている。
void (*_pcallback)();
void _timeBeginPeriod(DWORD ms)
{
timeBeginPeriod(ms);
}
// タイムイベントとして呼び出されるコールバック関数
static void CALLBACK
callback(unsigned int timerID, unsigned int msg, unsigned int usrParam, unsigned int dw1, unsigned int dw2)
{
_pcallback();
}
void setcallback( void (*pcallback)())
{
unsigned int timer;
_pcallback = pcallback;
// タイムイベントの開始
timer = timeSetEvent(1, 0, (LPTIMECALLBACK) callback, (DWORD) NULL, TIME_PERIODIC);
if(timer == 0) { printf("タイムイベントの生成に失敗\n"); exit(0); }
}
修正コードについてあれこれ
whileループだったものがコールバックになった感じだね。
思ったほどのガラチェンって感じもしないね。
あと、イベントチャンネル3に紐づいているXcpEvent(3)が本当の意味で1[ms]で呼ばれることになるから、1[ms]周期のDAQパケットも送ろうと思えば送れるってとこか。
そうだね。
元々の実装だとSleep(10)毎に10回のXcpEvent(3)の呼び出しで仮の実装だったけど、
今回は1[ms]のコールバック毎に必ず呼び出されるので1[ms]は保証されると思って良いだろう。
次回は実際に動かしてみるってところかな。
まとめ
まとめだよ。
- DAQパケット送信周期精度改善の方針を決めた。
- 時間精度を引き上げるためマルチメディアタイマを使用。
- 1[ms]精度の過去実績あり。
- 時間精度を引き上げるためマルチメディアタイマを使用。
- Sleep(10)を挟んだWhileループをマルチメディアタイマによる1[ms]コールバックに変更。
- これに伴い10[ms]周期だけでなく、イベントチャンネル3も1[ms]保証ができる。
バックナンバーはこちら。
コメント