前回はμITRONの実装のひとつであるHOS(Hyper Operating System)をダウンロードし、
カーネルのライブラリを作成しました。
Visual Studioで実行可能なμItronの環境を構築する
今回はこのライブラリを使用して、μITRON環境下でHelloWorldを表示させるプログラムを作成します。
今回作成するプロジェクトのフォルダ構成
作業に入る前に、今回の説明の前提を説明しておきます。
まず、前回書いたカーネルのライブラリは準備が出来ているものとします。
Visual Studioで実行可能なμItronの環境を構築する
今回作成するプロジェクトは、以下のフォルダに作成します。
C:\HOS\HOSProj\HelloWorld |
また、前回使用したカーネルのソースはC:\HOS\hos-v4a以下に配置します。
HOS自体は、好きなフォルダにプロジェクトを作成する事が出来ますが、上記と異なるフォルダで作業する場合は、以降の説明を読み替えてください。
プロジェクトを作成する
まずは新規作成のプロジェクトから、新しいプロジェクトを作成します。Visual C++のWin32を選択し、コンソールアプリケーションでプロジェクトを作成します。
アプリケーションの設定画面では、以下の設定を行います。
プリコンパイル済みヘッダーからチェックを外して、完了ボタンをクリックします。
この状態でF5キーを押して、デバッグ実行が行える事を確認しておきます。
黒いコンソールの画面が一瞬表示された後、閉じればOKです。
以下のフォルダより2つのファイルを、今回作成するプロジェクトのフォルダにコピーします。前回も説明しましたが、hosv4a.libがカーネルのライブラリで、h4acfg.exeがシステム定義のコンフィグ作成プログラムです。
コピー元フォルダ C:\HOS\hos-v4a\kernel\build\win\win32\vc2010\Debug ファイル hosv4a.lib h4acfg.exe |
2012/10/21追記:
上記2ファイルに加えてvc100.pdbも一緒にコピーしてください。
vc100.pdbが無くてもコンパイル時にwarningが出るだけで動作に支障は有りませんが、.pdb(デバッグ情報ファイル)があるとデバッグ実行時に便利です。
上記2ファイルに加えてvc100.pdbも一緒にコピーしてください。
vc100.pdbが無くてもコンパイル時にwarningが出るだけで動作に支障は有りませんが、.pdb(デバッグ情報ファイル)があるとデバッグ実行時に便利です。
次に、サンプルフォルダから以下の4ファイルをコピーします。
これらのファイルはHOSが周期的にカーネル処理を行うための関数です。
コピー元フォルダ C:\HOS\hos-v4a\sample\win\win32 ファイル ostimer.c ostimer.h wintimer.c wintimer.h |
それぞれのソースで各2つの関数が定義されており、処理概要は以下の通りです。
(中身については今のところ理解する必要はありません。)
ostimer.c void OsTimer_Initialize(VP_INT exinf) -> カーネル周期実行の初期化 内部でWinTimer_Start()関数を使用し、HOSの初期処理でコールされる void OsTimer_IrqHandler(void) -> カーネル周期実行の処理 HOSの周期実行タスクとしてコールされる wintimer.c(ostimer.cの内部使用関数) void WinTimer_Start(INHNO inhno, int iInterval) -> 内部でWinTimer_Threadスレッドを起動している DWORD WINAPI WinTimer_Thread(LPVOID param) -> 一定周期毎にItronの割り込み処理をコールしている |
上記の計6つのファイルコピーが終わると、以下の状態になります。
追加した*.c/*.libをプロジェクトに追加します。
追加後、以下の様な表示になればOKです。
次にHOSカーネルのincludeフォルダをパスに追加します。
プロジェクトのプロパティを選択します。
構成プロパティ->C/C++を選択し、追加のインクルードディレクトリに以下のフォルダを追加します。
C:\HOS\hos-v4a\kernel\include |
ここで再度コンパイルしてみます。
kernel_cfg.cが有りませんというエラーが出ればOKです。
※もしここで”kernel.hが有りません”エラーになる場合は、includeディレクトリの指定を再確認してください。
システムコンフィギュレーションのファイルを作成する
次は、先ほどエラーが出たkernel_cfg.cファイルを作成します。このkernel_cifg.cとkernel_id.hというファイルは、システムコンフィグレーションファイルと呼ばれています。
システムコンフィグレーションファイル カーネル構成・初期化ファイル kernel_cfg.c ID自動割付け結果ヘッダファイル kernel_id.h |
これらのファイルの元ネタは、system.cfgというファイルです。
system.cfgからは、以下のようにPreConfigure/Configure処理を経て作成されます。
PreConfigure処理は、C言語のプリプロセッサ機能を使用します。
VisualStudioのCコンパイラはcl.exeなので、今回はこれを利用します。PreConfigureを事前に行う事で、プログラムが使用するヘッダのdefine値を使用することが可能になります。(今回はPreConfigure処理自体は行いますが、プリプロセッサ命令を書いていないので何もしません)
次にConfigure処理を行います。
これは、カーネルの初期化パラメータや初期化処理を行うC言語プログラムを生成するコードジェネレータです。ヘッダファイルはタスクID等、連番をつける必要があるID値の付番処理を行っています。別にエディタを使って手作業でkernel_cfg.c/kernel.hを作っても良いのですが、管理の手間を省くためμITRONでは上記の処理を設けています。
という訳で、まずは以下の内容で元ネタとなるsystem.cfgを作成します。
/* μITRONコンフィグ定義(HOS) */ INCLUDE("\"ostimer.h\""); INCLUDE("\"HelloWorld.h\""); /* カーネルの設定 */ KERNEL_HEP_MEM(4096, NULL); KERNEL_INT_STK(1024, NULL); KERNEL_TIM_TIC(10, 1); KERNEL_MAX_TSKID(8); KERNEL_MAX_SEMID(8); KERNEL_MAX_MBXID(8); KERNEL_MAX_MPFID(8); KERNEL_MAX_CYCID(8); /* OSタイマの設定 */ ATT_INI({TA_HLNG, 0, OsTimer_Initialize}); /* タスクの登録 */ CRE_TSK(TSK_TASK1, {TA_HLNG|TA_ACT, 1, Task1, 1, 1024, NULL}); |
中身の詳細は、まだ分からなくても良いですが、以下の3点が行われている事を気に留めておいてください。
INCLUDE -> HelloWorld.hを指定 ATT_INI -> OsTimer_Initialize()関数を定義 CRE_TSK -> Task1()関数を定義 |
システムコンフィギュレーションのファイルを処理する
system.cfgを作成したら、次は実際にPreConfigure/Configure処理を行います。スタートメニューより、Visual Studioコマンドプロンプトを実行します。
コマンドプロンプトで以下のコマンドを実行します。
cd /D C:\HOS\HOSProj\HelloWorld cl /E system.cfg > system.i h4acfg.exe |
cl.exeを/Eオプションで実行するとプリプロセッサだけを実行させることが出来ます。”cl.exe /E”の結果は標準出力に表示されるのでリダイレクトでsystem.iファイルに出力しています。
Configureプログラムのh4acfg.exeはデフォルトでsystem.iファイルを処理するためオプションは無しです。
プログラムを実行したらkernel_cfg.c/kernel_id.hファイルが出来上がることを確認します。
kernel_cfg.cを,Visual Studioのプロジェクトに追加して、再度F5キーでビルドします。
すると、次はHelloWorld.hが無いというエラーになるはずです。
これは、kernel_cfg.cで定義されている#include “HelloWorld.h”文に対するエラーです。
この文が生成されたのは、system.cfgで以下の文を記述しており、これを元にConfigureがコード生成したからです。
INCLUDE("\"HelloWorld.h\""); |
上記の作業で事前の準備は完了です。次は実際にプログラムを作成します。
プログラムを作成する
次は実際のHOSカーネルの呼び出しと、HOSで動作するタスクの定義を行います。まずはプロジェクト作成時に自動生成されたHelloWorld.cppです。
HOSでは基本的にC++ではなくC言語で開発するので、拡張子をcpp->cに変更します。
(ソリューションエクスプローラでファイルを選択後F2キーを押せば変更できます)
HelloWorld.cを以下の内容に変更します。
#include "kernel.h" #include "kernel_id.h" #include "HelloWorld.h" #include "stdafx.h" #pragma comment(lib, "winmm.lib") // winmm.libを使用する int _tmain(int argc, _TCHAR* argv[]) { // HOSの起動 vsta_knl(); return 0; } void Task1(VP_INT exinf) { // タスク1の処理 printf( "hello world\n" ); } |
#pragma命令は、wintimer.cで使用するtimeSetEvent()関数の為です。
(このpragmaが必要な理由が知りたい人はこちらを参考にしてください。)
次に、以下の内容でHelloWorld.hを作成します。
#ifndef _HELLOWORLD_H_ #define _HELLOWORLD_H_ void Task1(VP_INT exinf); #endif |
これでビルドすると、エラーがなくなるはずです。
※以下のエラーが出る場合は、HelloWorld.cppをHelloWorld.cにリネームし忘れてないか確認して下さい
LNK2001: 外部シンボル "_Task1" は未解決です。 C:\HOS\HOSProj\HelloWorld\kernel_cfg.obj |
動作を確認する
プログラムを実行し、以下のようにコンソールにHello Worldの文字が表示されれば成功です。補足:Configure作業を自動化する
今回の説明では,作業手順を確認するためPreConfigure,Configureを手作業で実行しましたが、この方法だと開発時に作業漏れが発生することがあり不便です。そこで、以下の作業をしておくとPreConfigure,Configureをビルドプロセスに組み込むことが出来ます。
プロジェクトからプロジェクトのプロパティを選択します。
構成プロパティ->ビルドイベント->ビルド前イベントから、コマンドラインの編集を選択します。
コマンドラインのウィンドウに、以下のコマンドを登録します。
pushd $(ProjectDir) echo Start PreConfigure ----------------------- cl /E system.cfg > system.i echo End PreConfigure ----------------------- echo Start Configure ----------------------- h4acfg.exe echo End Configure ----------------------- popd |
設定を行った後、ビルドを行うと自動でPreConfigure,Configureが行われます。
PreConfigure,Configureにエラーが無いかは、出力ウィンドウで確認できます。
下記は、エラーが無い場合の出力例です。
1>------ すべてのリビルド開始: プロジェクト: HelloWorld, 構成: Debug Win32 ------ 1> Start PreConfigure ----------------------- 1> Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 1> Copyright (C) Microsoft Corporation. All rights reserved. 1> 1> system.cfg 1> End PreConfigure ----------------------- 1> Start Configure ----------------------- 1> End Configure ----------------------- 1> wintimer.c 1> ostimer.c 1> kernel_cfg.c 1> HelloWorld.c 1> コードを生成中... 1> stdafx.cpp 1> HelloWorld.vcxproj -> C:\HOS\HOSProj\HelloWorld\Debug\HelloWorld.exe ========== すべてリビルド: 1 正常終了、0 失敗、0 スキップ ========== |
ここまでの作業で、非常に簡単なプログラムですが、vsta_knl()でHOSのカーネルを起動させ、カーネルからsystem.cfgで登録したタスク”Task1″がコールされるという、OS環境下でのプログラムの実行が出来ました。
次回は、μITRONにおけるタスクの考え方と、タスクの生成/終了処理を確認します。
関連記事
追加のインクルードディレクトリを設定後コンパイルで以下のようなエラーがでて先に進めません。解決策を教えていただけると助かります。
1>wintimer.obj : error LNK2019: 未解決の外部シンボル __imp__timeSetEvent@20 が関数 _WinTimer_Start で参照されました。
1>hosv4a.lib(def_inh.obj) : error LNK2001: 外部シンボル “__kernel_inh_tbl” は未解決です。
1>hosv4a.lib(isig_tim.obj) : error LNK2001: 外部シンボル “__kernel_syscb” は未解決です。
1>hosv4a.lib(dsp_tsk.obj) : error LNK2019: 未解決の外部シンボル __kernel_syscb が関数 __kernel_dsp_tsk で参照されました。
1>hosv4a.lib(dsp_wup.obj) : error LNK2001: 外部シンボル “__kernel_syscb” は未解決です。
1>hosv4a.lib(kexe_tex.obj) : error LNK2001: 外部シンボル “__kernel_syscb” は未解決です。
1>hosv4a.lib(isig_tim.obj) : error LNK2001: 外部シンボル “__kernel_syscb_ro” は未解決です。
1>hosv4a.lib(adp_que.obj) : error LNK2001: 外部シンボル “__kernel_tcb_tbl” は未解決です。
1>hosv4a.lib(sig_toq.obj) : error LNK2001: 外部シンボル “__kernel_tcb_tbl” は未解決です。
1>hosv4a.lib(dsp_tsk.obj) : error LNK2001: 外部シンボル “__kernel_tcb_tbl” は未解決です。
1>hosv4a.lib(dsp_wup.obj) : error LNK2001: 外部シンボル “__kernel_tcb_tbl” は未解決です。
1>hosv4a.lib(kexe_tex.obj) : error LNK2001: 外部シンボル “__kernel_tcb_tbl” は未解決です。
1>C:\HOS\HOSProj\HelloWorld\Debug\HelloWorld.exe : fatal error LNK1120: 外部参照 5 が未解決です。
kernel_cfg.cをソースファイルに追加してください
ありがとうございます。解決しました。
質問したのとは別の者ですが、
同じ問題を抱えていました。
「error C1083:includeファイルを開けません。’kernel_id.h’:No such file or directory」のエラーが出ます。これは以下の文面と関係してそうですが、どう訂正すればよいでしょうか?
教えて頂きますと助かります。
>これは、kernel_cfg.cで定義されている#include >“HelloWorld.h”文に対するエラーです。
>この文が生成されたのは、system.cfgで以下の文を記>述しており、これを元にConfigureがコード生成したからです。
>INCLUDE(“\”HelloWorld.h\””);
宜しくお願いします。
松井