■ユーザアプリケーション
機器ごとに異なる、機能そのものを実現するプログラムのことを、ここでは「ユーザアプリケーション」と呼びます。これだけは外部から調達するわけにはいきません。自ら実装するか、外部の開発会社に要求仕様を提示して有償で実装してもらうことになります。ところで、ファームウエア開発の場合はハードウエアが完成する前から着手せざるを得ないことも多いです。デバイスドライバは本当のハードウエアで動かさないと意味がないので、自作する場合はとりあえず書くだけ書いておいてビルドが通るまで進めておきましょう。外部から調達する場合もプロジェクトに組み込んでビルドが通るところまでは進められます。これはミドルウエアも一緒です。 しかし、ユーザアプリケーションは粗動作確認まで先行開発することが可能で、弊社エンジニアを見ると以下の2パターンに分かれるように思います。A パソコン上で開発・動作確認
パソコン上で先行開発・動作確認します。ネットワーク機能は使えるし、便利なデバッグツールもたくさんあります。本物のデバイスはないので、そこはデバイスドライバの外側だけ書いて(stub)、何もせず正常終了するなど決まった動きをさせます。「なんちゃってドライバ」です。デメリットとしては、やはり本番基板とはかなり環境が異なるため、本番基板へのポーティング時に、それまで意識していなかった差異が問題になるかもしれません。動作パフォーマンスも違うでしょう。効率の悪いプログラムだと、パソコンでは気にならなかったパフォーマンスが実機で問題になるレベルになるかもしれません。
B 過去の組込機器環境上で開発・動作確認
ミドルウエアやデバイスなどほぼ条件が同じ過去の資産があれば、それで先行開発すると本番基板へのポーティングのハードルがぐんと下がります。そういう「組込機器の標準環境」が手元に用意できれば、その後似たような組込機器の開発が発生してもユーザアプリケーションの開発がどんどん進められます。私はこちらのパターンで、手元の標準環境が便利すぎて、組込機器が全く関係ないただの計算プログラムもFWにして流し込んで実行させるのが普通になってしまいました。
・C? C++? 組込機器プログラムにおける言語の問題
組込機器のプログラムは、基本的に単一または少数の機能を実現するものなのでパソコンのアプリケーションに比べると相当規模は小さいです。それであれば言語仕様もシンプルな方が扱いやすく、「オブジェクト指向」という考え方は不要なように思います。また、デバイスへのI/Oはいわゆる「メモリマップドI/O」と呼ばれ、メモリ空間のどこかでデバイスアクセスを行う構成が主流です。ですからデバイスドライバは「どこどこアドレスの何ビット目に1を立てる」ような、直アドレスアクセスがプログラムの主要な処理になります。高級言語の抽象化とは真逆なアプローチなので、いまだにデバイスドライバはC言語で書かれることが多いように思います。ただ、C++で書かれたミドルウエアを導入した経験もあり、一概に「組込機器だからC言語だ」とも言い切れません。デバイスドライバの例のように、「こういう理由だからこの言語で書く」を決めた方が良いでしょう。・パソコン向けソフトウエア開発から組込機器向けファームウエア開発に入ったときに陥りがちな罠
前回の「今日の閑話」とも重複する話題ですが、パソコン向けソフトウエア開発に慣れている人が組込機器向けのファームウエアを開発しようとしたときに陥りがちな罠があります。ユーザアプリケーションだから結局普通のCプログラムでしょ?と侮るなかれ、こういった点に注意しましょう。-CPUのエンディアン
パソコン向けCPUの場合はリトルエンディアンですが、マイコンではビッグエンディアンのものもあります。例えばマイコンからパソコンへ4byte長の変数をネットワークで送信する際、何も意識せずにビッグエンディアンのマイコンで変数を送信バッファにmemcpy、リトルエンディアンのパソコンで受信バッファから変数にmemcpyすると、見事に上下byteが逆転した別の値になります。エンディアンによらずに正しく動作するプログラムを書くには、変数と配列間はmemcpyではなく1byteづつ配置する変換関数を自分で書いて使いましょう。
-オート変数の最大サイズ
パソコン向けソフトウエアの場合、「unsigned char buffer[2048]」くらいなら関数内で宣言して使用することがあるかと思います。ところがファームウエアの場合、オート変数は通常スタック上で確保され、その最大スタックサイズもそれほど大きくありません。別途静的な領域として確保するなど、スタックオーバーフローとならないよう注意が必要です。私は1つのオート変数が100byteを超えると途端にstatic変数に切り替えたくなります。
-変数のサイズ
intやlongなど変数で表現できる最大値の前提がパソコンと組込機器で異なる可能性があります。組込機器ではintが8bit変数や16bit変数である可能性があります。どんな環境でも動作するプログラムにするため、できれば一般的な変数を使わず、u_int8_tなどどの環境でも最大値が変わらない変数を使った方が安全です。ただ、さすがにintでも127まではどの環境でも使えるだろうから最大が100程度の値しか入らない変数に限りintを使うのは良いように思います。
-メモリ確保関数、時刻取得関数、算術関数、文字列操作関数...
パソコン向けソフトウエアでは普通に呼んでいた各種便利関数も、ファームウエアでは入手先を考える必要があります。OSが持っている、ミドルウエアに含まれる、自力で実装するなどが考えられますが、既存のソースコードを移植する場合は、もちろん移植元ソースコードのライセンスにご注意ください。
-プログラム効率
パソコンはマイコンに比べて相当速いので、効率の悪いプログラムを書いても気になりませんが、マイコンで動かしてみたら処理に時間がかかってしまったというケースがあります。効率の良い/悪いがわからない方は、是非先輩エンジニアにコードを見てもらってください。ただ、近年、マイコンの性能とコンパイラの最適化性能が上がってきたので、それほど気にしなくてもマイコンでの運用に十分なパフォーマンスが出せるようになってきました。そのため、昔は可読性より効率が求められた組込機器向けのプログラムも最近は効率よりも可読性が求められるようになってきたように思います。その背景には、プログラムの品質を個人が担保した時代から組織(複数人数)が担保する時代になったことも大きいでしょう。
★Centeでは...
Centeでも要求仕様をご提示いただいてユーザアプリケーション全体or一部を実装することも承っております。上記のような罠を熟知したエンジニアが組込機器向けに最適なユーザアプリケーションを実装します。■今日の閑話
皆さん、ユーザアプリケーションって組込エンジニアとしてはどう思いますか? いくらデバイスドライバやミドルウエアを組み込んでも、ユーザアプリケーションという一番上のピースが入っていなければ個々のデバイスの試験環境のようなものです。ユーザアプリを書いて動かして初めて組込機器がある意図に従い、全デバイスを統一的に制御し始めます。ユーザアプリ書きは組込機器に命が宿る瞬間を目の当たりにすることができるのです!(大げさ) つくづく、ユーザアプリケーション開発って組込機器ファームウエア開発の醍醐味の一つだよな、と感じています。Cente:
https://www.cente.jp/