2011年5月26日木曜日

H8/3069F writer for KOZOS - kz_h8write 「h8writeリベンジ解決編」

概要


先日の記事で勢いよく「改良しました!」と宣言したh8writeですが、やっぱり書き込みに失敗するという事がわかりました。
そもそも真の原因を掴めないまま改良したと言っても、何を改良したのか意味がわかりません。
自分でもそんな突っ込みを入れたくなるのですが、その日はグングン快調に書けていた上、オリジナルで実行するとやっぱり書けないという状態で、完全に勘違いモードに突入していました。


既に行く先の見えているH8/3069Fに肩入れするつもりはなかったのですが、KOZOS本(と著者!)が楽しくて仕方がないのと、宣言して出来なかった悔しさから本格的に問題を追及すべく、データーシートを片手にh8writeのソースコードを本格レビューしていくことにしました。

判明した事実


データーシートのプログラミングシーケンスを数分眺めていて、すぐに気付いたことがあります。

先日までは、プログラミングシーケンスなど気にも留めていなかったのです。
なぜなら10年もの間、皆さんが使い倒していて、正常に動いていたからです。
そこにあえて突っ込みを入れる必要はないだろうと思っていたのですが、ここが肝心な部分でした。

問題となっているのはホスト側のボーレートをマイコンが自動検出するメカニズムの部分です。

まずはデーターシートを見てみましょう。


このシーケンスで重要なのはホストからブートプログラムに送られる0x00です。

図にもあるように「MAX30回」です。
この意味が重要です。
決して、「いつも30回」ではありません。

それでは、h8write.cを見てみます。


関連する定義は以下のようになっています。


上記でお分かりのとおり、「最大30回」ではなく、「常に30回」送信しています。
これの何がいけないのでしょう?

答えはデーターシートに書いてあります。


要するにブートローダが合わせ込み完了を通知したら、次の状態に遷移しているのです。
では、遷移した先の問い合わせ選択コマンドとは何なのか?見てみましょう。


デバイスに関する様々な情報をホストが問い合わせするためのコマンドを受け付ける状態のようです。

要するに既にブートプログラム側は「ビットレート合わせ込みシーケンス完了」を宣言し、全く異なるシーケンスを持つ次の状態に遷移しようとているのに、ホスト側がだらだらとビットレート合わせ込み用データをまだまだ垂れ流しているというわけです。

これはいけません。

本来は、ブートプログラムから「ビットレート合わせ込み完了」が来た時点で、以下の図の赤で囲ったシーケンスを実行しなくてはならないからです。
だらだら0x00を送っているということは、本来確認用コード0x55を送るべきところで、0x00を送っている事を意味します。


オリジナルのh8writeの出力をもう一度確認してみます。


当然ながら実装の通り、ブートローダから「合わせ込み完了」が返ってきているにも関わらず、どんどん0x00を送出しています。


上記例は”たまたま”うまく動作している時の例です。
”たまたま”の根拠は先ほど挙げたデータシートの通りです。
明らかにデータシートで示唆されたシーケンスとは異なる事がわかります。

次に示すのは互いのシーケンスが一致していない事による失敗の例です。
失敗する時と明らかなタイミングの違いがあるかと思ったのですが、そのようには見えないのが不思議です。紙一重で動いていると言う事なのでしょうか?


ここで、ふと疑問に思われる事でしょう。
「なぜ皆はうまくいっているんだ?」
システムではよくある話ですが、おそらく偶然動いているだけです。

これにはいくつものタイミングが絡んでいます。
  • ソフトウェアが処理を行うまでの時間。
  • シリアルポートドライバが処理を開始するまでの時間。
  • カーネルが処理を開始するまでの時間。
  • H8側のブートプログラムが合わせ込みを完了するまでの時間。
  • H8側のブートプログラムが次の状態へ遷移するまでの時間。
特に、近年はレガシーポートが姿を消しています。
USBの先にシリアルポートデバイスが接続されるような場合には更にタイミングが従来より異なるでしょう。

まさに今回のh8writeの問題はここに原因がありました。
従来は偶然書けていたのです。

h8writer for KOZOS - kz_h8write


h8writeは長年沢山の方々がお使いになっていて実績という意味では申し分ないのですが、実装が美しくありません。
車輪の再開発をするつもりはないのですが、頭の整理も兼ねて綺麗に実装しなおすことにしました。

プログラムは「KOZOS本と一緒に使う」という意味でkz_h8writeと名付けました。

kz_h8writeは以下の要素から構成されています。
  • motモジュール(motファイルを読み込むモジュールです。)
  • serialモジュール(シリアルポートを制御するモジュールです。)
  • kz_h8write(全体の制御を行うモジュールです。)
オリジナルh8writeの実装は各機能が癒着気味で修正の影響が見えにくくなっていました。
また、失敗した時に何の処理で失敗したのか見当がつきにくかった問題もあります。

問題のビットレート合わせ込みは以下のように実装しました。
データーシートにあるように計測用マーカーを送信して、ブートプログラムからの返答を確認した時点でこちらも応答を返すという手順にしてあります。


実際のやりとりもロジックアナライザで観察してみました。
ホストからのビットレート合わせ込み用コード(0x00)に対して3回目には応答が返ってきています。


kz_h8writeは応答があった時点でデータシート通り、確認用のコード(0x55)を送出しH8から返答(0xE6)を受けています。


これでホストとH8は合わせ込まれたビットレートで正しく通信できるわけです。

kz_h8writeコマンドツールにはmotファイル名、クロック周波数[MHz]、シリアルポート名を与えて使用します。

kz_h8write kzload.mot 20 /dev/ttyUSB0

各シーケンスが実行されていく様子を確認する事ができます。

=======================================
 KOZOS H8/3069F Flash Writer.          
 Copyright(C) 2011 Shinichiro Nakamura 
=======================================
Bitrate sequence: Done.
Inquiry device: Done.
Select device: Done.
Inquiry clock mode: Done.
Select clock mode: Done.
Select bitrate: Done.
Write erase: Done.
Complete.

全ての作業が完了した時には「Complete.」と表示が行われます。

今回の実装で複数の環境で昨日今日と試していますが、期待通りに動いています。
※まれに電源投入後1回目は失敗するのですが、もう一度実行するとうまくいきます。

前回と異なるのは明らかにおかしい箇所を修正したバージョンだということです。
原因(の1つ)を解明して修正していますので、先日の「何だかわからないけど動くようになりました!」とは意味が違います。

このkz_h8writeを暫く使ってみようと思っています。

ソースコード


LinuxとWindows上で動作させることができます。
ソースコード:ここからダウンロードして下さい。

(2011/05/28追記)
http://sourceforge.jp/projects/kz-h8write/で管理することにしました。
最新版は上記サイトからダウンロードして下さい。

ライセンス


MITライセンスを適用します。
商用、非商用を問わず自由にお使い頂けます。

関連リンク


0 件のコメント:

コメントを投稿