これまで作ってきたメイン制御盤をバラしてコントローラ(パワーパック部)類をレイアウト台枠に移設中。レイアウト下段の周回部分用のコントローラの移設は終わったので、今回はメイン台枠天板上のメインレイアウト部分のコントローラと音響コントローラ部の移設。
PICマイコンでソフトウェアリセットをかけたい
PICマイコンを使ってNゲージレイアウト用の制御盤、ポイントマシンの制御、信号LEDの制御などの機能を作っている。
そのPICマイコンたちの親となるのは、ラズベリーパイ。
1台のラズベリーパイがマスターとなってI2C通信で複数のスレーブとなるPICマイコンを制御しようとしている。
一応ラズベリーパイとPICマイコン間での複数バイトの送受信のテストもできた。
ただ、今のところ、マスター/スレーブ間でどの程度の通信が発生し、スレーブのPICマイコンがどの程度の処理能力がでるか不明。
やはり、気になるのがマスターから送られてくる電文に応じて、そのインターバルの間でPICマイコンが処理を終わらせることができるか、ということ。
PICマイコンの処理が追いつかなければ、マスター側からの電文送信を抑止しなければならない。
そのためには、抑止を指示する電文を送信する、NACKを送信する、などの方法が考えられる。
が、たかがNゲージレイアウトの制御。
ソフトウェアばかりに手間暇かけていろんな機能を盛り込んでもきりがない。
処理が追っつかなきゃPICマイコンはリセットじゃ~~
PICマイコンのリセットには次の方法があるみたい。
- MCLR端子によるリセット
- ウォッチドッグタイマタイムアウトによるリセット
- ソフトウェアによるリセット
(1)MCLR端子によるリセット
物理的なスイッチを設けて手動でリセットする。
今回の目的には則さないのでボツ
(2)ウォッチドッグタイマタイムアウトによるリセット
ウォッチドッグタイマはプリスケーラをタイマ0と共用している。
プリスケーラはどちらか片方にしか使えないので、ウォッチドッグタイマを使えばタイマ0を使えなくなる。
今回は複数のPICマイコンで同じような仕様でリセットをかけたい。
タイマ0が使用できなくなるのはちょっと・・
(3)ソフトウェアによるリセット
これなら複数のPICマイコンで同じような仕様で作り込むことができる。
さらに、リセットをかける条件、場所などは自在に設定できる・・ハズ
よし、ソフトウェアによるリセットに決定じゃ。
ちなみに、今回使用しているコンパイラはXC8(v2.10)
RESETマクロ
ネットで調べたところ、 RESET() というマクロでリセットがかけられるらしい。
で、試してみた。
ソースのRESET()の行に到達した時点で処理は停止したみたいで次の命令は実行されなかった。
ただし、main()関数が再度実行される気配はなかった。
つまり、リセットではなく、単なる停止。
これじゃ、exit();と変わらん。
RESETマクロとは?
RESET()はコンパイラXC8(v2.10)内でどのように定義されているのか調べてみた。
xc8debug.hでは次のように定義されていた。
#define RESET() asm(“reset”)
#else
#define RESET() asm(“ljmp $”)
#endif
さらに、pic18.hでは次のように定義されていた。
今回使用しているのは、PIC16F886、PIC16F887、PIC16F1823等々。
PIC14やPIC18は使用する予定はない。
つまり、RESETマクロは次のものがコンパイルされるはず。
ljmpの$とは?
ljmp(Long Jump)はいいとしても、その後の$とは何ぞや。
ここは飛び先のアドレスだが・・
マクロを呼び出してその$にはどうやってアドレスを設定するんじゃろ?
無駄なあがきと思いつつ、いろんなヘッダをincludeする前に、
とやってみたが、まぁ、無理だわなぁ。
#define RESET(a) asm(“ljmp %a”)
RESET(1234);
とでもなってりゃ分かるんじゃが。勉強不足じゃ・・
ソフトウェアリセットマクロ
検索エンジンで5分調べてもわからなきゃ・・ 他の方法じゃ。
ということで、マクロは自作。
ちなみに、0番地にジャンプすればPICマイコン内のプログラム群の最初から実行されることになる・・ハズ
RESET()という名前はすでにXC8内のヘッダファイルで使用されているのでSYSTEM_RESET()としてみた。
#define SYSTEM_RESET() asm (“ljmp 0”) // リセット(0番地へJUMP)
SYSTEM_RESET();
これで、SYSTEM_RESET();を実行するとmain()関数の頭から実行されるようになった。
ただし、PICマイコンが持っているすべてのレジスタは電源投入時の状態に戻っているか否か不明。
「電源投入時の状態に戻っていない」と思った方がいいでしょうなぁ。
つまり、main()関数では「必要なレジスタはすべて自分で初期化する」というのが吉かと。