開発プロセスとクロス開発環境、そしてOSのことH8で学ぶマイコン開発入門(3)(3/3 ページ)

» 2006年11月14日 00時00分 公開
前のページへ 1|2|3       

ネイティブ(PC)環境とクロス(組み込み)環境の違い

パソコン用OSと組み込みOS

 ネイティブ環境は、パソコンの環境です。以下のプログラムをネイティブ環境でコンパイルして実行します。


#include <stdio.h>
int main(void)
{
  puts("Hello");
  return 0;
} 

 すると、ディスプレイ上に「Hello」の文字列が表示されます。これは当たり前のように見えますが、少し考えてみると不思議なことです。何が不思議かというと、誰がディスプレイに文字列を出力したのでしょうか。「putsがディスプレイに出力した」は、正確な解答ではありません。

 ライブラリ関数putsの標準出力(stdout)は通常、ディスプレイですので、このプログラムでは結果としてディスプレイに文字列が出力されます。しかしC言語はディスプレイが標準出力であると規定しているわけではありません。前回のコラムにも書いたように、C言語はデータの入出力処理を言語仕様として実装していません。このためC言語でデータの入出力を行うためには、ライブラリとOS、両方の助けが必要です。

 Windowsパソコンで上記のプログラムを実行すると、ライブラリ関数putsがOS、この場合はWindowsに対してファンクションコールを発行します。ファンクションコールを受けたWindowsは、putsが規定しているI/O、この場合はディスプレイに対して出力を行います。

 このようにネイティブ環境ではOSの存在が大前提となって、プログラムが開発されます。ネイティブ環境ではOSが存在しないと何もできませんが、逆に考えるとOSのおかげでプログラミングは非常に楽になります。例えばDVDやハードディスクなどの外部記憶装置にアクセスする場合も、適切なライブラリ(デバイスドライバが実装されていることが前提となりますが)を呼び出せば、誰でも簡単に外部記憶装置を利用するアプリケーションプログラムが作成できます。

 これに対してクロス環境(組み込み環境)、特に組み込みOSが実装されていない環境では、様相が一変します。組み込みOSが実装されていない環境では、たとえターゲットシステムにディスプレイが物理的に接続されていても、便利な標準ライブラリputsは使えません。

 ではどうするかというと、必要な関数はプログラマが自分で開発します。外部記憶装置へのアクセスやI/O処理なども、すべてプログラマ側で用意する必要があります。さらに、OSが行う処理と同様の機能をプログラマ側で準備しなければなりません。システムに電源を投入した直後のシステムチェックや実行環境の構築など、プログラマ側ですべて用意するのはかなり大変な作業です。

 このため最近の組み込み機器では、組み込みOSの使用が一般的になってきました。経済産業省の「2006年版組込みソフトウェア産業実態調査 報告書」によると、小規模のシステム開発の場合でも全体の70%近くは組み込みOSを利用しています(図6)。

組み込みOSの利用状況 図6 組み込みOSの利用状況(出典:経済産業省2006年版組込みソフトウェア産業実態調査 報告書)

 さらに通信プロトコルや文字フォント、音声認識・合成などのミドルウェアの利用も多くなっています。特に市販の組み込みボードでは、BSP(Board Support Package)という形で、OSやデバイスドライバ、一部のミドルウェアも一括して提供されます。ユーザーはBSPを利用することで、組み込みシステムの開発を効率よく進めることが可能となります。

メモリ配置

 基本的にプログラムが使用するメモリ領域は、以下の3種類に分類されます。

  • コード領域
  • データ領域
  • スタック領域

 コード領域には、プログラムコードや定数データが配置されます。この領域の内容は、特別な事情がない限り、プログラム実行中に書き換えられることはありません。データ領域には、静的変数が配置されます。またスタック領域には、自動変数や割り込みコンテキストが配置されます。データ領域とスタック領域の内容は、プログラム実行中に書き換わります。

 ネイティブ環境ではOSがメモリの空き領域を探し、コード/データ/スタックすべての領域をRAM上の適切なアドレスに配置します。これに対してクロス環境では、プログラマが責任を持ってROMとRAMに配置しなければなりません。コード領域はROMへ、またデータ領域とスタック領域はRAMへ配置するよう、リンク時に指定します。

メモリ配置の違い 図7 メモリ配置の違い

スタートアップルーチン

 先ほどのputsでディスプレイに文字列を表示するプログラムを再び考えてみます。

#include <stdio.h>
int main(void)
{
  puts("Hello");
  return 0;
} 

 C言語の教科書を見ると、Cプログラムの最初はmain関数から始まり、戻り値はint型を返すと書かれています。また、main関数を終了する場合は、return文で0を返すと書かれています。

コラム:main関数について
本文中に、教科書には「main関数を終了する場合は、return文で0を返すと書かれています」と書きましたが、そこまで書いている教科書は希です。void main(void)と書いている入門書もあります。実は筆者も以前は平気でvoid main(void)と書いていましたが、ある本に太字で「そういう本は間違っています」と書かれているのを見て、初めてmainの意味を理解しました。組み込みの場合は極端な話、main関数が存在する必然性はありません。組み込みプログラミングは自由度が高い反面、基本をきっちりと押さえておかないと恥をかくことがありますので注意が必要です。


 では、mainの前には何があり、returnの後には何があるのでしょうか。ネイティブ環境(パソコン環境)に慣れたプログラマは、これらを意識することはあまりありません。なぜなら、mainの前後は、WindowsやLinuxなどのOSが面倒を見てくれるからです。しかし組み込みOSを搭載していない組み込みシステムの場合は、mainの前後の処理もプログラマが責任を持って実装する必要があります。そこで登場するのが、スタートアップルーチンです。



 次回はスタートアップルーチンを中心に、組み込みシステムプログラミングについてさらに詳細に考察していきます。(次回に続く)

⇒ 連載バックナンバーはこちら

前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.