課題が一つ解決した
今手掛けているProjectの目指す所は『PICの学習環境であり、プログラムの開発環境であり、アプリケーションの実行環境』です。<==大風呂敷 (^_^;)
『PICの学習環境』として提供するのは、レジスタやメモリをREAD/WRITEしたり、小さなテスト・プログラムを走らせてその結果をモニタする機能です。
『プログラムを1行も書かずに、TRISAレジスタとLATAレジスタをコンソール画面から操作するだけで、Lチカが出来る』というのが一番の売りです。
『プログラムの開発環境』として提供するのは、関数を呼び出して処理結果を確認したり、プログラムの実行にBreakを掛けたりする機能です。プログラム実行中にもGlobal変数をモニタしたり、書き換えたり出来るのが自慢です。
(PICkit3では出来ません。<==やらないだけ?)
最後の『アプリケーションの実行環境』として、PIC側でユーザ・プログラムのcinitを呼び出す機能の提供は当然のこととして、ホスト側のユーザ・アプリケーションをどうやって起動するか?その方針が決まっていませんでした。
構想としては、ユーザが作成したjarファイルをライブラリ登録して、コンソール・プログラムからそれを呼び出すというものなのですが、果たして上手くいくものか?
試してみました・・・
中央水色がユーザが定義したウィンドウで、User_Frame.jarをライブラリ・フォルダに配置して、呼び出すことが出来ました。ここまでならライブラリを組み込んでそれを呼び出しただけなので、出来て当然です。
気になっていたのは、コンソール・プログラムをコンパイルした時と異なるUser_Frame.jarでも問題なく呼び出せるのか?という点です。パネルを表示するだけのUser_Frame.jarでコンパイルした後、1秒ごとにボタンを貼り替える動作を組み込んだUser_Frame.jarに置き換えても、問題なく動きました。
どうやら、コンソール・プログラムとのインターフェース部分に変更がなければ、ユーザ・アプリケーションをUser_Fram.jarとして呼び出すことが出来そうです。
ホスト側のユーザ・アプリケーションの起動方針が固まりました。
(パチパチパチ~)
放置していた不具合に対処した
通信ポートは、現在の環境に合わせてWindowsなら”COM4”、Linux(Raspi)なら”/dev/ttyUSB0”を設定しています。これを利用者の環境に合わせて設定できるようにする計画なんですが・・・
何らかの事情でPICと通信できない場合、今までのプログラムは受信待ちループから抜けられませんでした。ユーザが利用する通信ポートを設定しようとしても、メニュー操作では設定出来なかったのです。(起動パラメータで指定するという方法はあります)
そこで、先ずは受信待ちの無限ループにエラー終了する機能を追加しました。
<以前のコード>
if( receive_ringbuff.rest() < len )return false;
<書き換えたコード>
if( receive_ringbuff.rest() < len )
{
receive_loop_count++;
if( receive_loop_count < 100 )return false;
Main_Frame.main_control.target_pane_panel.show_message("Receive fail");
}
100ms待っても必要なデータが受信できなければ、"Receive fail"というメッセージを表示して抜けるようにしました。(送信は通信不良でもプログラムは正常終了するのでこの処置は入れていません)
さらに
try{
CommPortIdentifier comID = CommPortIdentifier.getPortIdentifier( port_name );
---一部省略-----
port_open = true;
}
catch( Exception e )
{
Main_Frame.main_control.target_pane_panel.show_message("Comm port fail");
port_open = false;
}
通信ポートが開けなかった場合に、"Comm port fail"というメッセージを表示して
port_openフラグをfalseにしました。
port_openフラグがfalseのときは通信処理をスキップして、メニュー操作が出来るようになりました。
目出度し、目出度し
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
後の方の処置だけだと、シリアル・ラインの断線に対処できません。実は前の方の処置だけで動くのですが・・・
何というか、まぁ、気分の問題ですね。
以上、ご参考まで
readelfの問題が解決した
Raspi上の動作確認で、関数リストを作成できないという不具合が発覚しました。
実は、WindowsとRaspiでreadelfの出力に違いがあることは分かっていて、解析内容は同じなのですが、Raspiの方はコメントが日本語になっています。
<Windows上のxc32-readelfの出力>
ーーーーーーーーーーーーーーーーーーーーーーーーーー
2017-08-22T14:31:25.412
Contents of the .debug_abbrev section:
Number TAG (0x0)
1 DW_TAG_compile_unit [has children]
DW_AT_stmt_list DW_FORM_data4
DW_AT_producer DW_FORM_string
<Raspi上のreadelfの出力>
ーーーーーーーーーーーーーーーーーーーーーーーーーー
2017-08-22T05:43:36.536
.debug_abbrev セクションの内容:
Number TAG (0x0)
1 DW_TAG_compile_unit [子あり]
DW_AT_stmt_list DW_FORM_data4
DW_AT_producer DW_FORM_string
ロケールをUKにするとコメントが英語になり、関数リストも期待通りに作成されました。メカニズムは分かっていませんが日本語のコメントが関数名の解析を妨げているようです。
対策として、Raspiの場合は”env LANG=en_us.UTF-8 ”を頭につけてreadelfを呼び出すことにしました。
こんな感じです
ーーーーーーーーーーーーーーーーーーーー
if( !isLinux() ){
analyze_elf = readelf;
}
else{
analyze_elf = "env LANG=en_US.UTF-8 "+readelf;
}
OSの種類をこんな風に取得し、
String OS_NAME = System.getProperty("os.name").toLowerCase();
判定はこんな感じです
boolean isLinux() {
return OS_NAME.startsWith("linux");
}
この修正によりRaspiでも関数を指定できるようになりました。
(パチパチパチ~)
Raspi上で動かしてみた
当初はRaspiとPIC間の通信にI2Cを使う計画でした。しかし、USBシリアルを利用すればPCでも同じアプリが動くことに気付き、UART通信でやることにしました。
それ以来、開発はPC上で進めてきましたが、粗方動き始めたので久しぶりにRaspi上で動かしてみることにしました。PCで動いたアプリがそのままRaspiでも動くというのがJAVAの有難いところです。
とは言ってもNetBeansが全てやってくれるPCとは違い、jarファイルを配置したり、classpathを通したり、Raspi上で動きだすまでにはひとしきりジタバタさせられましたが、漸く動きました。(パチパチパチ~)
殆どPCと同じように動くのですが、何故か関数リストが作成されていません。orz
まだまだ、完成にはほど遠いようです。
タイミング依存のバグが見つかった
不具合に気付いたのはPICのTMR0レジスタを読み出したときです。TMR0は常にカウントUPしているので、読み出す度に異なる値が表示される筈なのですが、0を示したままです。はて?
調べてみると、ホストとPIC間のコマンド送受が正しく機能していません。あれこれコードを弄っているうちに、間違いをやらかしたのでしょうか?節目ごとに取っておいたbackupコードと今のコードの差分を調べたのですが、ホストとPIC間のコマンド送受に影響しそうな変更は見つかりません。orz
最初に機能を組み込んだときの不具合(<==覚悟している)はそれ程応えませんが、あともう少しという所まで進んで、コマンド送受という重要な機能の不具合に見舞われるとかなり気落ちします。
気を取り直してデバッグを始めました。eusartRxBufferには受信データが正しく格納されています。それを読み取るコマンド処理に何か問題がある筈です。
先頭の1バイトをコマンドとして読み取り、残り3バイトをパラメータとして読み取るというのが正しいシーケンスです。Ringbufferを使ったデバッグ・ログで処理の様子を調べてみると・・・
ん!
先頭の1バイトを読み取ったあと、もう1バイト読み取ってから3バイトのパラメータ読み出しを始めています!
何故、余分に1バイト読み取っているのか・・・
フラグを判定した後、直ぐにリセットするのが流儀なので、ほとんど無意識に下のようなコードを書いたのですが・・・
if( receive_complete )
{
receive_complete = false; <==これが原因だった
read_command();
}
receive_completeフラグがfalseということは『受信待ち』を意味します。パラメータ受信を開始してから次のデータを受信していれば問題無いのですが、先に次の受信データが届くと、そのまま読み出してしまいます。
パラメータ受信の開始と次のデータ受信のタイミングが変わり、パラメータを正しく受信できなくなっていました。パラメータ受信を開始するまで、receive_completeフラグはtrueを保っていなければならなかったのです。これまでは、たまたま上手く動いていただけだったようです。
タイミング依存のバグが、リリース後に発覚するとなかなか原因が掴めず往生しがちです。この段階で見つかって良かった!(<==なんて気楽に喜んで良いのでしょうか)
break_conditionとbreak_statusの操作は混乱気味
PIC側に設定されているbreak_conditionとbreak_statusをホスト側で読み取り、break_statusをクリアして書き戻したり、break_conditionに”THRU”または”BREAK”を設定して書き戻したりする操作を組み込もうとしています。
break_conditionとbreak_statusを反復して読み取り、それをホストのウィンドウに表示する機能は動きました。読み取ったbreak_conditionやbreak_statusをTextFieldに設定して、クリアしたり”THRU”または”BREAK”を設定する機能も動いています。試してはいませんが、Sendボタンの操作でPIC側に書き戻す操作も(多分)動く筈です。
TextFieldの編集中はPIC側からの読み取りを停止して、Sendボタンの操作で読み取りを再開しようと考えていたのですが・・・
Sendボタンを操作しないで別の操作に移ると、ホスト側の表示が混乱してしまいます。
問題点
(1)操作中を表すハイライト表示が複数個所に出てしまう。
(2)書き換えていないのに編集中の値が画面に表示されてしまう。
フラグを追加して状況を改善しようとしたのですが、フラグ操作が混乱しています。orz
ここは、一旦引き下がって取り組みの見直しが必要です。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
目指す姿は・・・
(1)ホストのウィンドウにPIC側の現在値が表示される
(2)選択項目がハイライト表示され、現在値がTextFieldに読み取られる
(3)TextFieldを編集したり、ボタン操作でクリア(または設定)する
(4)TextFieldの値をSendボタン操作でPIC側に書き戻す
(5)書き戻した値(現在値)が読み取られてホストの表示が更新される
多分、PIC側から読み取った値を格納する場所と編集中の値を格納する場所が両方とも同じ配列であることが混乱の原因で、それを分ければ問題は解決するのではないか?と考えています。
あと、もう少し・・・(多分)
秋月電子からPIC32を実装した基板が売り出された
秋月電子からPIC32を実装した変換基板二種(PIC32MX370F512HとPIC32MZ2048EFH144)が売り出されました。
PIC32MX370はMCCが使えるので気軽に開発を始められるものと思いますが、PIC32MZはHARMONYで開発することになるので、腹を決めて取り掛からなければなりません。<==英文のマニュアル2000~3000ページを斜め読みすることになります(^_^;)
(Ver1.0では8300ページあったHelp ファイルが、Ver2.0では分割されて少しスリムになったような・・・)
Microchip Directに注文しても1個6ドルするPIC32MX370F512Hが変換基板に実装されて¥700というのは破格の値段です。
PIC32が電子工作のデバイスとして、広く利用されるようになると良いなぁ~
(<==参考になる邦文の情報が増えることを期待している)
-------------------------------------------------------------------------
追記(2017.10.02)
ysaito様からPIC32MZを使った開発ボードをご紹介いただきました。
PIC32MZの能力を存分に引き出すことが出来そうな開発ボードです。
こちら(↓)
http://ys-labo.shop-pro.jp/?pid=100420541