組み込みソフト開発に必要な知識
(「組み込みシステムとは?」の続き記事)
前回の記事で組み込みシステムは様々であり、 組み込みソフト開発の必要な知識を定義するためには対象を限定しないと難しい、ということで終了しました。 ただ、絞り込むにしても経験のないシステムを対象とすることはできないため、 私自身の経験から必要な知識だと思える最小限の項目を挙げてみたいと思います。
これから組み込み技術者になろうという方であれば、 最初から持っているわけはないので今後必要な知識として学習項目に加えてもらえればと思います。
プロセッサ(MPU)
※ここでの説明ではMCUを対象としていません
- 動作モード
- 特権モードやスーパーバイザーモード等と呼ばれている特別なモードがあり、汎用OSのようなOSを採用しない組み込みソフトは常時このモードで動作させる場合が多いです。
- メモリアクセスのアライメント
- 命令やデータのアライメント制約を理解しておく必要があります(x86系の仕様は特殊と思いますので)
キャッシュ
命令キャッシュとデータキャッシュを理解しておく必要があります。
データキャッシュが問題になることがあります。
例えば、ブートローダーでプログラムの本体をメモリに展開する際に、 データキャッシュを介して転送し、展開先にジャンプすると暴走してしまう等。
データキャッシュから実メモリに書き出されていないために起こる問題ですが、 キャッシュを理解できていないと解決ができません。
割り込み(例外)
- 発生タイミング
- 通常処理に戻る仕組み
- 排他制御
周辺回路
昨今ではMPU、MCUチップに集積されていることがほとんどです。
- バスコントローラ(メモリデバイス等のデータシートを見ながら設定します)
- 割り込みコントローラ(レベル/エッジ方式、割り込み信号の経路)
- Timer(待ちやタイムアウト、計測等で必要になります)
- UART(プロセッサ間通信やデバッグ等)
- GPIO/PIO(LED、 DIPSW、リセット信号、I2CやSPI等をソフトウェア制御する際に使用, etc.)
通信
チップ間等の近距離通信やプロセッサ間通信、コンピュータ間通信等、通信の種類もたくさんあります。
UART
デバッグや機器間通信、基板間通信等、様々な用途で採用されています。 個人的にもリアルタイムデバッグのトレースや、対話型デバッグ等で今でもよく使用します。 (ホストコンピュータとの接続はRS-232CではなくUSBになっていますが)
近距離通信
小容量ROM、センサ、RTC、クロックシンセサイザ、DA/AD等、多種多様のデバイス制御に採用されています。
- I2C(SMBus)
- SPI
※上記の周辺回路を搭載していない場合は、GPIO/PIOを駆使してソフトウェアで制御することも多いです。
メモリデバイス
ROM、RAMの大枠だけでなく、多種多様のメモリから用途に応じて選定する必要がありますので、 各メモリデバイスの特徴を幅広く理解しているとよいと思います。
ROM
容量に応じてパラレル、SPI、I2C等のインターフェイスが採用される傾向にありますが、 SPIにはデータ線の数を増やして高速化したQuadSPI等もあります。
- 大容量(パラレル、SPI接続が主流と思います)
- NOR-FlashROM
- 小容量(SPI、I2C接続が主流と思います。パラレルもあるにはありますがピン数が多い等の理由から使用経験は少ないです。)
- EEPROM
- nvSRAM / FRAM / MRAM
※FlashROMやEEPROMのような不揮発性メモリへの書き込みは、プログラムと呼んだりします。
NOR-FlashROMのパラレルインターフェイス
ブートプログラムを配置する場合にはパラレル接続を採用する場合が多いと思います。 最近では物理的な接続はSPIでも、CPUコアからはリニアなアドレス空間に見せる回路を搭載している事もありますので、 その場合はSPI等でもブート可能になります。
RAM
それぞれについて、1bitを保持する仕組みや、アクセスの単位(バースト等)、 DRAMリフレッシュやキャッシュとの関係を理解しているとよいと思います。
DualPort SRAM
DualPortのSRAMはプロセッサ間通信等で利用することが多いです。 個人的にもCPU<=>FPGA、CPU<=>CPU等の経験があります。
起動シーケンス
プロセッサがリセット解除されてからmain関数までの道のり
- スタックポインタの設定
- 変数領域の初期化等
- 必要に応じてハードウェアの初期化(メモリコントローラ等は必須となる場合が多い、他の周辺回路は必要に応じて対応)
- staticオブジェクトのコンストラクタ実行(C++)
- main関数へ
プログラミング言語
アセンブリ言語
インストラクションマニュアルを見ながらでかまいませんが、 例外、割り込み処理をトレースする際に読めないと困ります。 スタックポインタの設定やキャッシュ制御等、アセンブリでしか記述できない処理があります。
新しく設計されたCPUを採用する場合には、コンパイラのバグにあたってしまうこともあります。 例えばC言語としては正しくとも、アセンブリを確認すると意図したコードになっていないこともあるのです。 そのような場合はC記述を変更して回避することもありますが、 回避困難な場合は移植性を捨ててアセンブリで記述しなければなりません。
RISCであれば命令も少ないため、慣れてくるとニーモニックで概ねわかるようになると思います。
C言語
思ったことを実現できるレベルであればよいと思います(道具として正しく扱えるということ)。 経験年数ではなく、本当に理解できているかが重要です。 他にはヒープ領域やスタック領域、メモリの使われ方も正しく理解していることが求められます。
個人的な理解では以下のように思っています。
- OSレスで動作するプログラムを作成できること
- アドレスを指定してIOアクセスができること(メモリマップドIO)
- アセンブリではプログラム規模や移植性から現実的ではないこと
実時間
- 実時間動作に対する意識
まとめ
ソフトウェア側の知識よりもハードウェア側の知識の方が求められるのではないかと思います。 例えばC言語の修得は言語仕様をおぼえるよりもプロセッサを理解する方が早く習得でき、 理解していれば憶えることも少なく、応用もできるようになると思います。 原理や仕組みに近い部分を深く理解していることは非常に有益なことです。
最後に
私の新人時代はほとんど知識がなく、1年目は研修で営業をしていましたので、 ドメイン知識はもちろんですが、きちんとC言語を勉強し始めたのは社会人2年目からでした。 また、組み込みソフトウェアがわかる先輩等もいなかったため、 自らの失敗や書籍より学んで身に着けるしかなく沢山の苦労がありましたが、 知らなかった知識を得ることで成長を実感でき、車輪の発明等、様々なことを経験することができました。 技術者として一番楽しい時代であったと思っています。
当時の上司や先輩、多くの方々が暖かく見守ってくれていたことには大変感謝しています。