組み込みまするβ

組み込みソフトウェア初学者向けブログ

組み込みソフト技術者への質問箱

何かしら役に立つ内容があればよいのですが、私個人の経験から回答したものなので一般的でない内容を含んでいることを理解した上で読んでみてください。

プログラミングを始めたのはいつからですか?

大学は理工学部情報工学科ということもあり、FORTRANLispPascalC言語を書いたことはありましたが、残念ながら”プログラムを作れる”というレベルではありませんでした。 C言語の標準ライブラリの知識もなく、ポインタはもちろんprintf系書式や文字列の扱い等もまったく理解できていなかったので、 C言語の書式を少々知っているだけという状態で社会人になりました。

社会人1年目は営業研修だったので実際にプログラムを書き始めたのは開発部に正式配属された社会人2年目からです。 某特化技術の開発部に所属して間もなく、開発予定だった組み込みシステムのファームウェア担当者となったのですが、 同部署にはファームウェアを担当している人はいなかったので技術研修も無ければ質問できる先輩もいませんでした。

これには時代的な理由があって、当時の私がいた部署ではPCベースのシステム開発がほとんどで、 PCIボードを開発し、FAPC(Factory Automation PC)に収めて販売していました(PCIボード単体販売や複数台のFAPCで組んだシステムの受託開発もしていました)。 そのPCベースの開発から、専用装置の開発への移行期に入社してきた新人が私だったということです。

このため、誰かに頼ることができず自分で考えて行動していくしかなかったのですが、 何でも自由にできて遣り甲斐もあり、私の場合はかえって良かったのかもしれません。 但し、このような経験の積み方、積ませ方が良いとは思ってなく、 プレッシャーに押しつぶされ挫折する可能性が非常に高いと感じるため、仮に私が直属の上司なら同じ経験はさせられません。

アセンブリC言語C++をどのように使い分けていますか?

アセンブリはスタックポインタの設定や、ウェイトのためのサイクル数調整、割り込みの入口と出口の処理、 割り込み禁止/許可やキャッシュ制御のためにマシンステータスレジスタ(MSR)の読み書き等が主です。 なお、高速化を目的にアセンブリで記述した経験はありません。

アセンブリでの高速化について

私が経験してきた組み込みシステムの多くはシステムレベルのデータフローやアーキテクチャの方が速度に対する影響が大きく、 ボトルネックになっていないソフトウェアを高速化しても組み込みシステムとしては意味がなかったのでアセンブリ化の必要がありませんでした。 このようなリアルタイムシステムで高速化の必要性が後から判明するようなら重大な設計ミスですからね。

ソフトウェアの処理速度を上げることでユーザの待ち時間が減る等の意味がある機能ブロックやシステムであれば、 速度という1つの観点でアセンブリ化も有効だとは思います。 しかしながら移植性を捨ててまで対応する意味があるか等、当該システムにおけるトレードオフを考えなけれなりません。 結果的に"労多くして功少なし"となる可能性が非常に高いのではないでしょうか。

なお、担当技術者が対象CPUのアーキテクチャに習熟しているなら別ですが、 チューニングされたコンパイラで最適化されたマシン語より高速なコードを書くのは非常に難しいものです。 何より開発に時間がかかることやデバッグの難しさ、属人化の問題にもなります。

アセンブリでしか記述できない処理以外はC言語C++で記述していますが、 選択可能な場合はOSレス時にC++、組み込みOS採用時はC言語で記述していました。 それよりも社内事情によりC言語C++を使い分けなければならない場合が多いと思います。 私の場合は言語選択可能な自社製品開発が主だったので、C言語C++の割合は50%ずつくらいだったでしょうか。

C++を学習すればC言語の学習は不要ですか?

C++を学習すればC言語の学習は不要かと聞かれることがあり、C++ができればC言語もできると考えている人が多いようです。 仮にC++を習得していてもC言語にはSTLやスマートポインタはありませんので、C言語で設計する際に文字列やポインタの扱いが苦手では困ることになりますし、 便利なコンテナはもちろん、classさえもありませんのでオブジェクト指向で設計するにはclass相当の機能も自分で実現しなければなりません。 これらのことだけを考えてもC言語を道具として正しく扱える事は必要となるでしょう。

組み込みソフト技術者の場合は社内事情(C言語でコーディングされた過去のプログラム資産)や顧客要望、 限られたハードウェアリソース(主にメモリサイズ)等でC言語は必須です。 C言語のみという会社もあるかもしれませんが、時代の流れとしてはC言語だけの状況は続かないと感じていますので、 現状の判断としてはプロジェクトに応じてC言語C++のどちらでも扱えると良いと思います。 他社の状況などはわかりませんが、Rustを使い始めている会社もあるのでしょうかね。

さて、組み込みソフト技術者にはC言語C++の両方必要という前提で学習順序を考えると、 コンピュータの仕組みに関する知識が無いのなら先にC++を学習することは非常にハードルが高いと思います。 コンピュータの仕組みを理解し、C言語を使いこなせるようになった後でC++を始めても遅くありませんし無駄にもなりません。 むしろC言語でclassの仕組みや仮想関数・継承の実現方法や実装を学習した方がC++への理解が深まり、 C++の「べからず集」を理由もわからずに沢山憶えることも減るので、 C言語を先に学習してきちんと使いこなせるようになった方が段階を追う意味でも良いと思います。

CPUはどんなものを使っていましたか?、またROM/RAMはどのくらいのサイズでしたか?

最初の開発で使用したCPUは、ルネサスが日立だった頃のSH-4(SH7750)です。 その後もSH-3系(SH7709、SH7709A、SH7709S)のプロセッサタイプをメインに使用していました。 転職後はM16C、H8系、SH-2系、Nios2、MicroBlaze等ですね。 長く勤めていた会社ではALTERAのFPGAが採用されるケースが多かったので必然的にNios2の経験が一番長くなりました。

CPUの動作周波数は10MHz~200MHz程度のデバイスをよく使っていましたね。 メモリについてはROMサイズ不足で困るような開発はありませんでしたが、 最小のROMサイズはUV-EPROMの128kBytes~256kBytes程度だったと思います(ブートローダ用にはROM/RAM含めて4kBytes程度のサイズ)。 RAMサイズに関しては切り詰めなければ実現が難しい開発もありましたが、 SH7045を採用したシステムが外部メモリなしで、CPU内蔵RAMの4kBytes(ROMは内蔵128kBytes)が最小だったと思います。 内蔵RAMとしては128kBytes~256kBytes程度が一番多く、外部メモリ(SDRAM)を採用したシステムでは4MBytes~32MBytes程度です。

日立系はマニュアル類が非常にしっかりしていた事と痒い所に手が届くといった多機能な印象を持っています。 とはいえ、便利であっても移植性を考慮すると特殊な固有機能は結局使えないのですけどね(汎用的な使用方法に制限してしまう)。

  • H8系
  • M16C系
  • SuperH MCU系(SH7045、SH7080)
  • SuperH MPU系(SH7709、SH7709A、SH7709S、SH7710、SH7750)
  • ソフトマクロ系(Nios2、MicroBlaze

昨今ではアセンブリ言語で記述するのはごくわずかですし、C言語C++でmain関数から記述できる場合がほとんどなので、 CPUに対する知識は必要ですが特定のCPU経験の有無によって有利・不利というのはほとんどありません。

組み込みOSはどんなものを使っていましたか?

最初の開発は研究開発目的のシステムで所謂OSレス、 以降は製品の全体制御を担当することになり、前任者(外注さん)が使用していたWindowsCE2.11を引き継ぐことになりました(同時期に別のファームで実装されていた独自OSも引き継いでいます)。 次の後継製品ではEthernetを搭載するのでTCP/IPが必要になり互換性を重視してWindowsCE3.0を採用したのですが、 ドライバ修正時の対応が煩雑であったこと、開発対象の用途としては多機能過ぎてオーバースペック、 ライセンス費用も高額でしたので以降の製品ではuITRON4.0仕様OSへ切り替えました。

転職後はコア内部寄りの開発が多かったのでOSレスの割合は増えましたが、 組み込みOSを採用する規模の場合はuITRON4.0仕様OSをよく使っていましたね。 メモリサイズが小さく済み、リアルタイム性を求められる製品開発が主だったというのが理由です。

  • OSレス(OSの種類ではないですが)
  • 独自OS(使いたい機能だけ実装してあるような小規模カーネル
  • WindowsCE2.11~3.0(ウィンドウシステムも備えた組み込み向けOS)
  • uITRON4.0仕様OS(リアルタイムカーネル

引き継いだWindowsCE2.11で使用されていたデバイスドライバはベンダ提供の出来合いのものでした。 これは8bit幅のread/writeアクセスしかできませんが、DeviceOpen時にIO空間(物理アドレス)を設定することで、どのようなデバイスでも利用することができます。 しかしながら8bit幅のread/writeアクセスの度にDeviceIoControlを呼び出す仕様であったため、非常に低速で時間効率の悪いものでした。 このためWindowsCE3.0の採用時は専用のデバイスドライバを新規作成することとなり、 短期間にOSやデバイスドライバ開発を学習しなければならなかったので苦労した記憶があります。 当時はデバイスドライバのひな型を生成するツールが販売されていましたが、 非常に高価だったこともあり、結局はDLLの学習から始めて全部自分で書きました。 なお、当時のシステムではカーネルイメージをFlashROMに書き込んで動作させるしかなかったので、 ドライバの修正はカーネルイメージの書き換えとなり、デバッグには多くの時間・作業コストがかかりました。

開発規模や体制はどんなものがありますか?

最も小規模なものはH8の評価基板を利用したシステムですね。 その基板のIO端子を別の装置に接続して回転系のメカ制御をした経験があります(試験装置)。

逆に最も規模の大きなシステムは1Uハーフサイズに基板2段重ねで、制御CPU、DSP、特定用途専用CPU等合わせて15個程度、その他多数のFPGAを使用したシステムでしょうか。 当初、私の担当は制御CPU2個(全体制御含む)だったのですが、最終的には外注さん担当だったCPUも追加されて3個担当するようになりました。 今考えると物理サイズが大きいなぁと思うのですが、当時のFPGAは容量もあまりなかったので複数のFPGAやCPUを使用せざるをえなかったですね。 大容量で高速IOを備えた昨今のFPGAなら1個または2個程度に収まってしまうシステム規模かもしれません。

私の経験では制御CPU1個につき担当者が1人という場合が9割以上でしたが、 組み込みソフトウェア開発の人員体制としては1つのCPUに5人程度までの経験があります(DSPや特殊CPUは除外しています)。 複数人で開発する場合は独立性の高い「サブシステム」や「階層」で担当者(一人~数人)を割り当てるのが一般的かと思います。 もちろん複数人でチームを組む場合にはサブシステムや階層の垣根なしに中心的な役割を果たす技術者が必要になります。

組み込みソフトウェア技術者としてどのように学習してきたのですか?

20代前半の頃はネットに情報はほとんどありませんでしたので書籍、雑誌のみで勉強しました。 会社ではベンダから提供されたCPUのハードウェアマニュアル、プログラミングマニュアル(インストラクションマニュアル)を読み、 帰り道はいつも横浜ダイヤモンド地下街の有隣堂に寄り、C言語や組み込みソフト関係の書籍や雑誌を探していました。 雑誌はCQ出版のInteface誌(Tech Iシリーズ、増刊号等含む)が主で、興味のある内容のときは必ず購入し通勤電車内の往復や自宅で読んでいました。 所謂コンピュータの仕組みに関する知識に分類される内容だと思います(組み込みソフトの知識とも言えると思います)。

それとは別にドメイン知識を得るため、会社で購入しているドメインに関する規格書や書籍を読み勉強していました。 ドメイン知識については社内に詳しい人がたくさんいたので教わることが多かったですね(通常はドメイン知識なく組み込みソフトウェアを作ることはできないので並行して学習していく必要があります)。

上記のコンピュータの仕組みとドメイン知識の2点だけでも組み込みソフトウェアを開発できるようになりますが、 ソフトウェア設計に関して学習していないと設計品質はひどいもので、メンテナンスや後継製品への流用は非常に困難となる場合が多いです。 私の場合はコンピュータの仕組みに関する知識に重点を置いて学習していたため、 思い通りに動作することはもちろんですが、無駄なく高速に動かすことに特化していました(20代後半まで)。 それによって製品としての不具合は非常に少なく製品品質が高いと評価されていたのですが、 ソフトウェアとしての設計品質に関しては今思えばひどいものだったと思います。 非ソフトウェア技術者から見れば優秀な技術者に見え、設計能力の高いソフトウェア技術者から見ればモジュールの粒度が大きくダメな設計という評価でしょう。

その後(30代前半以降)、ものすごく遠回りになりましたが、 設計の重要性に気が付いてからは設計品質、C++オブジェクト指向関連、大規模開発、アジャイル等の書籍を読むようになりました。 組み込みシステムのCPUや周辺回路の性能向上、外部チップだった回路の取り込み等でシステム規模が大きくなってきているというのも理由の1つです。

また、独自に勉強してきた技術者の学習バランスは様々です。 逆のパターンで例えばコンピュータの仕組みに関しての知識が疎かだと、 製品がたまにハングアップする、コンパイラの最適化をかけると思った通りに動作しない、たまにおかしな動作をする等。 ソフトウェアとしての設計品質は良くてもハードウェア制御の実装が不味く、 組み込みシステムとしての不具合が多い(製品品質が悪い)ということになる場合もあります。 もちろん不具合の原因がソフトウェアでなく、ハードウェアや開発ツールの不具合、システム連携の不具合等、開発によって様々です。

  • 製品品質(製品ユーザ、社内から判断される)
  • 設計品質(社内のソフトウェア技術者のみから判断される)

社内の人間であってもソフトウェア技術者でなければ設計知識を持っていないため、 社内においては製品品質が重視される傾向となるのが一般的だと思います。 だからこそ設計品質については意識的に取り組んでいかなければなりません。

このようにバランスの悪い状態が長く継続すると(私と同じで)非常に苦労しますので、 若い技術者の方々はドメイン知識、コンピュータの仕組み、ソフトウェアの設計・品質の3点でバランスをとりながら学習するのがよいと考えています。 なお、大規模開発で分業体制を採用している組織では、ドメイン知識に特化するのか、汎用知識に特化するのかという選択があるかもしれません。

  • ドメイン知識
  • コンピュータの仕組み
  • ソフトウェアの設計・品質

私が学習を始めた当時、組み込みCPUボードは高額で開発環境(コンパイラやデバッガ等)も何十万円だったので、 自宅で実機を使った開発やデバッグの経験を積むことは困難でした。 このため、実機を使っての経験はすべて会社内で行うしかなく、 自宅や電車内での読書によって知識を吸収し、新たな知識を社内の実機環境で試してみるというサイクルで進めていました。

現在では組み込みCPUボードが数千円から購入でき、開発環境を無償や少額のライセンス費用で使えますし、 ネットの情報も検索すればいくらでも出てくるので勉強する環境としては非常に恵まれた状況だと思います。 とはいえ情報過多な分、間違った情報やプログラミングスクールへの誘導記事等も溢れかえっており、 初学者のほとんどはネットの情報を正誤判断できないため、良質で正確な情報を得るのは返って難しい時代かもしれませんね。