HOME > 技術談話 > PIC® microcontroller > 今までの流儀と異なる点
はじめに メモリ スタック 割り込み ローカル変数 関数の二重化 初期化済み定数
バンク切り替え ROMチェック 日本語 クロック補正
マイコン開発においてC言語を利用したことがあればPICマイコン開発への移行は容易であると思われますが、PICマイコンならではの注意点があります。これを意識せずに作業を進めるとプログラムの作り直し、もしくは仕様の再検討が必要になる場合があります。 本項ではPIC10/12/16系のPICマイコンを取り扱う上での代表的な留意点について記述します。 課題となる項目はPIC18/24等の上位PICマイコンでは異なるアプローチにより回避している場合があります。 コンパイラはHI-TECH C®を想定しています。一部の項目はコンパイラにより挙動が異なる可能性があります。 いずれにせよ、ターゲットデバイスのデータシートを熟読すること。これ大切です。 |
▲ |
PICマイコンで取扱可能なメモリを以下に示します。 |
種別 | データ保持 | 格納される内容 | |
プログラムメモリ | 不揮発性 | プログラム命令、初期化済み定数データ | |
データメモリ | 揮発性 | 変数、初期化済み変数 | |
EEPROMメモリ | 不揮発性 | 変数(アクセスに時間を要する) ※一部デバイスでは未実装 |
複数ビットによる外部バスアクセス機能は有りません。プログラムメモリを外部拡張することはできませんが、外部に接続されたメモリやコントローラをポートアクセス、もしくは専用インタフェースを用いて読み書きすることはできます。 フラッシュメモリで構成されるプログラムメモリの一部を運用中に書き換えることはできません。通常はPICマイコンを運用していない状態で書き込み機による書き換え操作になります。オンボード書き換えは専用の治具を使用することで排他的に実現できますが、運用中に使用する入出力ピンと共存させる場合は注意が必要です。 データメモリの物理アドレスは連続していますが論理アドレスが重複しているためバンク切り替えによるアクセスが必要です。デバイスによりますが大容量の連続した領域の確保はできません。 C言語においてポインタ宣言を行う場合、プログラムメモリを指すのか、データメモリを指すのかを意識して宣言する必要があります(宣言方法でポインタ型のバイトサイズが異なる)。 プログラムメモリを書き換えるタイミングでEEPROMメモリの内容を書き換えることができます。このEEPROMメモリのデータはプログラミング時に定数として指定できるので、アクセス速度が遅いという点に目をつぶれば初期化済み変数の代わりに利用することができます。 上位のPICマイコンでは運用中のプログラムメモリ書き換えをサポートする場合があります。 |
▲ |
スタック領域はプログラムカウンタが格納される専用の領域です。デバイスによりますが2個、もしくは8個の容量を持ちます。プログラムからの明示的なアクセスはできずPush/Popに相当する命令もありません。サブルーチンの呼び出しや割り込み発生時にのみ利用されます。 スタックポインタ変数を持つマイコンはデータメモリにスタック領域を割り付け、プログラムカウンタだけでなくローカル変数を割り付けることでメモリを高効率で使い回すことができます。が、PICマイコンではできません。 上位PICマイコンではスタック領域が32個の容量を持ち、Push/Pop命令をサポートする場合があります。 |
▲ |
割り込みをサポートしないデバイスがあるので注意が必要です。 割り込みをサポートするデバイスでは複数種の割り込み要求を処理することができますが、割り込み自体は唯一のベクタからの分岐になります(ベクタアドレスはリセットと割り込みの2種類だけという意味)。このため割り込み処理の中で割り込み要求源を検索する必要があります。プロセッサ型マイコンにおける割り込み処理に似ています。 割り込み発生によりこれまでのプログラムカウンタはスタック領域に保持されますが、フラグレジスタ、汎用レジスタはプログラムにて退避させる必要があります。 多重割り込みは可能ですが、割り込みベクタが1つであること、汎用レジスタの退避を考慮しなければならないこと、そしてスタック領域の大きさを考慮すると多重割り込みを利用したプログラム構造は避けた方が無難です。 上位PICマイコンでは高優先度、低優先の2つの割り込みベクタをサポートする場合があります。 |
▲ |
C言語は関数内にローカル変数を定義することができますが、PICマイコンではグローバル変数と同様の手法でデータメモリへ割り付けを行います。関数毎に宣言されたローカル変数はその都度割り付けを行いますが、関数が多くなるとデータメモリを使いきってしまう恐れが…。 コンパイラの機能になりますが、ローカル変数の割り付けに対して最適化を施します。同階層の関数が互いを呼び出さないことを確認し、双方のローカル変数を同じアドレスに割り付けます。この機能により関数の数やローカル変数の数の割に実際に使用されるデータメモリは少なくて済みます。 |
▲ |
ローカル変数と割り込みの関係で関数のプログラムサイズが倍増します。 関数内のローカル変数はグローバル変数と同様にデータメモリに割り付けることを前述しましたが、その関数がメイン処理と割り込み処理で利用される汎用的な関数の場合にどうなるでしょうか?何も考えなければ変数のつぶし合いが発生します(割り込み処理が勝利)。 コンパイラは任意の関数がメイン処理と割り込み処理で兼用されるかをチェックしています。もし兼用の関数であるならばローカル変数の実体、そして関数そのものを分けて取り扱います。 プログラム作成時に関数の共用を行うケースは多々あります。その共用関数のステップ数が大きい場合、プログラム容量が一気に増大するので注意が必要です。 |
▲ |
プログラムメモリ内に初期化済み定数を配置することができますが、汎用インデックスによる間接アクセスで値を取得することができません。PICマイコンでは汎用インデックスはデータメモリへのアクセス専用になっているからです。 PICマイコンには「RETLW」という命令があります。1バイトの定数を返すリターン命令ですが、プログラムカウンタを演算操作することにより「RETLW」命令に直接ジャンプして定数値を引用します。アセンブラでも複数命令記述しないと定数参照できないので注意してください。 C言語でサブルーチンへポインタを渡すケースがあります。この時、ポインタの指す対象がデータメモリなのか、プログラムメモリなのか、それとも双方なのかで展開される命令が変化します。コンパイラがポインタ変数に情報を付加する場合があり宣言手法により型に対するバイトサイズが変化します。 |
▲ |
データメモリアクセス時にバンク切り替えが必須ですが、C言語でプログラミングする場合は意識不要です。コンパイラが必要に応じて変数参照前にバンク切り替えを実施します。 データメモリ上に配列を構築する時はバンク0以外の場所に配置した方が良い結果が得られる場合があります。 コンパイラの展開手法によりますが、配列をアクセスする時に汎用インデックスを用いたアクセスを行います。汎用インデックスが物理アドレスを利用するため、変数としてバンク0、配列としてバンク0以外を指定すると変数側の操作に伴うバンク切り替え命令が抑制されます(次数によりケースバイケース)。 |
▲ |
プログラムメモリに書き込まれているデータを汎用インデックスを用いて読み出しを行うことができません。 マイコンを利用した組み込み機器では電源投入時に自己診断機能の一環としてROMチェックを行うことが多いと思いますが、PICマイコンでは利用できません。書き込まれているデータは正常であるという前提になります。 ROMチェックはプログラムメモリの書き込みを行うタイミングで読み出し照合操作により代用することになりますが、プログラムメモリの外部からの読み出し禁止設定を行った場合は照合操作ができなくなります。書き込み禁止設定は照合操作の後で行ってください。 |
▲ |
日本人が扱う場合に日本語表記は便利なのですが、開発環境が海外で作られていることもあり、日本語が通用しないケースがあります(厳密には漢字コードの利用)。 フォルダ名、ファイル名に英数字が期待されます。日本語表記が含まれた場合は対象ファイルが見つからない旨のエラーメッセージが表示されます。 ログイン名の基本は英数字です。ほとんどのアプリケーションは問題ありませんが、日本語ログイン名を使用している場合は開発環境インストール時にエラーが発生する場合があります。 コメントの基本は英数字です。ですが日本語が利用できないというわけではありません。 「/* */」コメントは問題ありませんが、「//」コメントの場合、行末が「¥」と同じコードを利用する漢字で終了する場合は次の行を巻き込んでエラー、もしくは命令未展開になります(例えば「可能」という文字で終了する場合)。 |
▲ |
内蔵クロックをサポートするPICマイコンに特有な機能ですが、内蔵クロックのばらつきを抑えるための補正量をデバイスにセットすることができます。 補正量はデバイス毎に異なりデバイス工場出荷時に補正量が書き込まれますが、この格納場所がデバイスによりプログラムメモリに格納される場合とプログラムでアクセスできない場所に格納される場合の二通りがあります。前者の場合はデバイスを書き換える際に消去されないように注意してください。後者の場合は気にする必要がありません。 プログラムメモリに格納された補正量をデバイスにセットする専用のアセンブラ命令列があります。通常はコンパイラが用意するスタートアップルーチンでセットします(開発環境により有無を指定)。 |
▲ |