体験!マイコンボードで組込みLinux

第11回最新カーネル事情と組込みボードでのLua言語-C言語連携

最新LinuxカーネルとSH7706ボード

組込みボードにおけるLinuxカーネル更新

SH7706ボードで標準で提供されたのはLinux2.6.12で、長い間安定版として公開していました。特にLinux2.6.12で現状の運用に問題がなければ、わざわざカーネルのバージョンを更新する必要はありません。

詳細な部分は別として、Linux-2.6.12でも2011年初旬時点の最新カーネルであるLinux-2.6.36.3でも、アプリケーションプログラムから見たLinuxカーネルへのAPIはほとんど同じなので、SH7706LSRボードでアプリケーションプログラムを追加して運用する分には、特にカーネルバージョンは影響ないと思われます。

PCの場合はCPUやマザーボード内蔵周辺機能、外付け周辺機器の変化が速く、次々と新製品が出てきているので、それらに追随するために最新Linuxカーネルを追っていかなければいけないケースもあります。その点、SH7706ボードは基本的にハードウェアの変動はないので、PCのように最新カーネルを追随しなければいけないことはあまりないと思います。

ただし、Linuxカーネルの内側では細かいリビジョンが上がるたびにカーネルコードの内容が激変しており、それどころか、Linuxカーネル内部における仕組みや内部ルールそのものが変動しています。こうしたLinuxカーネル内部における仕組みや内部ルールの変動で大きな影響を受けるのが個別のデバイスドライバです。

あるリビジョン用に開発したデバイスドライバが、リビジョンが上がると使えないというケースがあります。それでもキャラクタデバイスは古典的なデバイスドライバなので比較的Linuxカーネルの更新の影響を受けにくい傾向にはあります。ところが、ブロックデバイスやネットワークデバイス、USBデバイスなどは、リビジョンが上がるとLinuxカーネルと不適合を起こして組み込めなくなることが珍しくありません。

もし、SH7706LSRボードで個別にデバイスドライバを開発をする場合は、開発時に最新のLinuxカーネルに更新して、その最新カーネルをターゲットにデバイスドライバを開発すれば、デバイスドライバの寿命そのものが長くすることが可能であり、仮にリビジョンが上がったりしても、少ない変更で新Linuxカーネルに対応することができます。

SH7706LSRボードではDebian/GNU LinuxやFedora Linuxを載せることにより、全てオンボード上で開発することも可能ですが、基本的にはPC上でSH7706LSRボードの開発を行い、開発結果であるコードやデータをSH7706LSRボードにコピーをしてSH7706LSRボード上で実行することになります。

PC上でSH7706LSRボードの開発を行う場合、PC Linux上のソフトウェア等を頻繁にSH7706LSRボードに移植したりデバイスドライバを移植する場合は、PCのLinuxカーネルリビジョンとSH7706LSRのLinuxカーネルリビジョンがなるべく近いほうが、移植がスムーズになります。基本はLinux2.6.12で良いですが、場合によっては、新しいLinuxカーネルのほうが良い場合もあります。

Linux-2.6.28.10

実はLinux2.6.12ではSH7706プロセッサはサポートしておらず、SH7706ボード向けパッチを使うことでSH7706プロセッサをサポートしていました。Linux-2.6.20以降、SH7706プロセッサとSH7706LAN/LSRがオリジナルカーネルでサポートされるようになりました。

ただ、Linux-2.6.20以降ではしばらくの間は、SHプロセッサとの相性も良いとはいえず、また、ブロックデバイスやネットワークデバイスにおける仕組みそのものや内部ルールの変更もあり、それらがひととおり落ち着いたバージョンがLinux-2.6.28.10といえます。

Linux-2.6.28.10では新しいSH3プロセッサであるSH7721や新しいアーキテクチャーのSH4Aなどに対応もしていますので、SH7706LSRとそれらの新しいプロセッサで共有可能なソフトウェア資産も開発し蓄積することもできます。

Linux-2.6.28の大きなトピックとしては、次世代ファイルシステムであるext4が安定版としてはじめてサポートされたことです。ext4の特徴としてはより大容量のメディアに対応したことですが、組込みではこのことはあまり関係はありません。組込み分野でext4に関係するメリットとしては、パフォーマンスの向上、ジャーナリング機能強化やオンラインデフラグなど信頼性の強化などがあります。

Linux-2.6.36.3

Linux-2.6.28.10も新しいLinuxカーネルなので劇的な変化はないですが、SH7706LSRは2011年初旬時点の最新カーネルであるLinux-2.6.36.3にも対応しています。

Linux-2.6.36.3は将来を考えるとデバイスドライバの長寿命化などのメリットもありますが、まだ、できたてほやほやで実績も多くはないので、本格採用する場合はじゅうぶんに応用用途での評価は必要となります。SH706LSR本体に内蔵はしていないですが、SH7706LSRにUSBホストコントローラ増設する場合、Linux-2.6.36.3のUSB機能はかなり充実しているので、そのような場合は最新カーネルの採用のメリットがおおいにあります。

Linux-2.8の正式リリースの見込みはなさそうですが、当初のLinux-2.6と比較すると現在の最新Linuxカーネルは事実上Linux-2.8といっていいくらい劇的に進化しているといえるでしょう。

Lua言語とC言語の連携

Lua言語でC言語の関数を使う

Lua言語とC言語の連携では、C言語からLua言語のスクリプトを呼び出すこともでき、反対にLua言語からC言語の関数を呼び出すこともできます。今回は、Lua言語からC言語の関数を呼び出す方法について解説します。

Lua言語は高水準のインタープリタなので柔軟にプログラム開発や試作などを手軽にオンボードで行うことができます。一方、C言語では低水準プログラミングに対応しており、かつ、ライブラリも完備しているので、Linuxの全ての機能を使ったり、ハードウェアの直接アクセスを行ったりすることができます。

組込みボードでは低水準のハードウェアアクセスの部分のみをC言語の関数にまとめて、それ以外の高水準のプログラミングをLua言語で行うのが最適だと思われます。最初は入門としてC言語で簡単な演算を行う関数を作成し、それを共有ライブラリへとこコンパイルをし、Lua言語のスクリプトからC言語で書かれた自作共有ライブラリを呼び出すことをやってみます。

Lua言語から呼び出すC言語関数

全ての引数の数と累積加算と累積積算の3つの戻り値を返すC言語側の関数はリスト1となります。

リスト1 引数の数、累積加算、累積積算を返す処理(C)
01: #include <lua.h>
02 #include <lualib.h>
03 #include <lauxlib.h>
04 
05 int    calc(lua_State *List) {
06     int        i, n;
07     lua_Number    sum, mul;
08 
09     n = lua_gettop(List);            // argc
10     sum = 0;
11     mul = 1;
12     for(i = 1;i <= n; i++) {
13         if(!lua_isnumber(List, i)) {
14             lua_pushstring(List, "Argument is not number.");
15             lua_error(List);
16         }
17         sum += lua_tonumber(List, i);    // argv[i]
18         mul *= lua_tonumber(List, i);    // argv[i]
19      }
20      lua_pushnumber(List, n);        // 1st
21      lua_pushnumber(List, sum);        // 2nd
22      lua_pushnumber(List, mul);        // 3rd
23      return 3;
24 }

Lua言語から呼び出されるC言語の関数を記述する場合は、Lua言語インターフェースのためのヘッダが必要になり、リスト1の1~3行目となります。

C言語側での関数名はLua言語から呼び出す関数名である必要はないので、適当なわかりやすい関数名にしておきます。Lua言語処理系からC言語へのインターフェースは、C言語においてはlua_State型のリスト構造のデータを介して行います。

Lua言語からC言語の関数へ渡す引数やLua言語がC言語の関数から受け取る戻り値は、lua_State型のリスト構造のデータに格納して行います。

C言語側の関数の引数は、lua_State型のリストのポインタとなり、リスト1の5行目のように指定します。

Lua言語からC言語の関数へ渡す引数の数は、リストのポインタを引数に指定したlua_gettop関数で得られます(リスト1の9行目⁠⁠。

Lua言語からC言語の関数へ渡す引数が数値かどうかをチェックする関数は、リストのポインタとインデックスを引数に指定したlua_isnumber関数で判定をします(リスト1の13行目⁠⁠。

Lua言語からC言語の関数へ渡す引数を数値として受け取る関数は、リストのポインタとインデックスを引数に指定したlua_tonumber関数でlua_Number型というLua処理系独特の数値型変数で得ます(リスト1の17~18行目⁠⁠。

C言語などの典型的な関数の言語仕様では引数は複数で戻り値は1つとなっていますが、Lua言語での関数の言語仕様では引数は複数で戻り値も複数となっていて、関数としての使い勝手が良くなっています。ただ、Lua言語で呼び出すC言語の関数はC言語の仕様で戻り値は1つなので、Lua言語で呼び出すC言語の関数で複数の戻り値を戻す場合は、Lua言語とのインターフェースとなるリストに対して順次、戻り値を格納し、最後にLua言語への戻り値の数をC言語関数の戻り値としています(リスト1の20~23行目⁠⁠。

Lua言語で呼び出すC言語の関数で複数の戻り値を戻す関数は、リストのポインタと戻り値を引数に指定したlua_pushnumber関数で格納し、lua_pushnumber関数を実行した順番がそのままLua言語への戻り値のインデックスとなります(リスト1の20~22行目⁠⁠。

Lua言語からC言語関数を呼び出す

Lua言語からC言語関数を呼び出すためにはC言語関数を共有ライブラリのかたちでコンパイルしなければなりません。

リスト1のソースファイル名をcalc.c、共有ライブラリ名と共有ライブラリのファイル名をcalc.soとすると以下のようにコンパイルします。

# sh3-linux-gcc -shared -Wl,-soname,calc.so -o calc.so calc.c

Lua言語からC言語関数を呼び出すスクリプト例はリスト2となります。

リスト2 Lua言語からC言語関数を呼び出すスクリプト例
01: func = package.loadlib("./calc.so", "calc")
02: num,sum,mul = func(3,4,7,2)
03: print("num="..num, "sum="..sum, "mul="..mul)

Lua言語からC言語関数を呼び出す場合は、package.loadlib関数で共有ライブラリのパスと共有ライブラリ内のC言語での関数名を引数として指定し、Lua言語側での関数名へ戻り値を代入します(リスト2の1行目⁠⁠。前述でC言語側での関数名はLua言語から呼び出す関数名と異なると述べましたが、このようにC言語側での関数名はLua言語から呼び出す関数名をリンクさせています。

リスト2の2行目ではC言語で書かれた関数を呼び出して複数の戻り値を格納し、リスト2の3行目でC言語で書かれた関数の処理結果をそれぞれ出力をしています。

次回は

次回はtcl言語とC言語の連携についてと、組込みボード上ではそのままでハードウェアアクセスが不可能なスクリプト言語からハードウェアアクセスを行う実例について解説します。

おすすめ記事

記事・ニュース一覧