uchikawa-yです 今回は前回に引き続く形で、DS2480Bを使う場合のメリットの一つ、1-Wireデバイスのアドレス検索(ROMコードの検索)について書きます。 DS2480B(現在は鉛フリーパッケージのDS2480B+に置き換えられています)は5mm角程度の大きさの8pinの表面実装パッケージでとても小さなものですが、中々使いでのあるICです。 なお具体的なコマンドのシーケンスについてはここには書きませんでした。こちらについてはDS2480Bのデータシートを参照してください。

DS2480Bについて

DS2480Bは入出力をRS-232シリアルインターフェース(TTLレベル)で行うように設計された1-Wireバスドライバです。 1-Wireはビット単位のデータ入出力は実時間に強く依存した非同期バスですが、このレベルについてはDS2480Bに完全に任せることができます。電気的特性上の要求から設定可能な部分はありますが、少数のデバイスを数m程度の配線で使う分にはデフォルト値のままで全く問題ありません。 DS2480Bには各種初期設定、ビット単位のデータ送受信を行うコマンドモードと、バイト単位のWriteがそのまま1バイト分の1-WireバスへのWriteとなるデータモードがあります。 1-Wireデバイスに対するコマンド(たとえば温度測定開始、測定データの転送などのコマンド)およびデータの送受信はほとんどバイト単位で行うようになっていますから、初期設定的など一部の処理をコマンドモードで行い、大部分の処理はデータモードを使う形になります。後述する検索アクセラレータや単一bitの読み書きを行う場合はコマンドモードを使います。 詳細な状態遷移図はDS2480Bのデータシート上で公開されていますが、大まかな状態遷移は以下のようになっています。
DS2480の大まかな状態遷移


  • コマンドモード: 各種のコマンドを受け付けるモード
  • データモード: "E3"を除いて受け取った1バイトをそのまま1-Wireに出力するモード
  • チェックモード: データモードからコマンドモードへ遷移する途中の一時的なモードで、"E3"を受け取ると1-Wireに"E3"を送ってデータモードに戻る以外はコマンドモードと同じ
チェックモードはデータモードからコマンドモードへ遷移するためのコマンド"E3"のエスケープ処理上発生する一時的な状態です。"E3"を出力する場合は"E3,E3"と2回続けて同じデータを送ることを表現したものです。 なお、チェックモードから電源offの遷移がありませんが、これは元の詳細の状態遷移図に従いました。

ROMコードのSearch と検索アクセラレータ

1-Wireのデバイス(スレーブデバイス)には工場出荷時に64bitのユニークな「ROMコード」が書き込まれており、デバイスを指定するアドレスとして利用されます。64bitのうち8bitはエラーチェック用のCRCコードなので実質56bitのアドレスになります。また56bitのうち8bitは製品の種別を示すファミリコード(温度センサの場合は28h)として使われています。 ROMコードはソフトウェア的に読み取り可能で、複数のデバイスが一つの1-Wireに接続されていてもROM Searchコマンドを使って全てのスレーブのROMコードを読み出すことができるようになっています。 このコマンドは特殊なコマンドで同時に複数のスレーブデバイスが出力行い1-Wire上では複数のデバイスの出力が合成されます。一般のCMOS回路の出力では通常出力端子同士を接続しては使えませんが、1-Wireではオープンドレイン出力なのでこの形は通常の動作です。以前にも書いたとおり出力動作をしているデバイス全ての出力をAND接続した結果が1-Wireの出力になります。 ROM Searchの詳細についてはMAXIM社の公開している資料を読んでいただきたいのですが、要点は以下のようなものです。

ソフトウェアによるROMコードの検索

DS2480Bを使わない場合1-Wireに用意されているSearch ROMコマンドとソフトウェアによる処理の組み合わせでROMコードの値を取得します。 Search ROMコマンドを使うと初期状態では1-Wire上のスレーブデバイス全てが応答します。スレーブはLSBから順番にROMコードの各ビットの値、値を反転したものを出力していきます。 (0bit目の値),(0bit目の値を反転), (1bit目の値),(1bit目の値の反転)…… 1-Wireでは全ての出力がAND接続されていますから、スレーブの中で一つでも0を出力しているものがあれば結果は0になります。たとえば[n bit目の値]と[n bit目の値を反転]の組み合わせについては以下のことが言えます。

  1. [n bit目の値]と[n bit目の値の反転]の値が異なる値であれば全てのデバイスのROMコードのn bit目は[n bit目の値]と同じである
  2. [n bit目の値]と[n bit目の値の反転]が両方とも0なら0bit目が1のデバイスと0のデバイス両方がある(値の衝突がある)
  3. [n bit目の値]と(n bit目の値の反転)が両方とも1なら、正常な動作をしていない。バス、デバイスの異常、シーケンス中にデバイスが取り外された、等が考えられる
この3種類の状態を表にすると以下のようになります
n bit目の値
0 1
n bit目の値の反転 0 出力には0,1両方ある (2) 全ての出力が1 (1)
1 全ての出力が0 (1) 正常動作ならこの状態にはならない (3)



3つめの状態の場合は中断するなり、最初からやり直しですね。1.の場合はそのまま次のbitについて同じ操作を続行します。2.のデバイスによりどちらもあり、の場合は0か1を選んで検索を続行します。この場合、選ばなかった「枝」に属するデバイスはそのまま動作していると、そこより葉に近いノードでは偽の「衝突」の原因になります。 ホストデバイスは「直前に調べたbitのROMコードの値が0(あるいは1)のデバイスは次にバスリセットを行うまで動作を停止する」という指示を行い、検索の対象とならない枝のデバイスはその後の検索に影響を与えないようにします。 これを64bit目まで繰り返すと最終的には1-Wire上で動作しているデバイスは1つだけになり、64bitの値が1つ決定します。1-Wire上のデバイスのROMコードが1つ求められたことになります。 簡単な例を示しましょう。ROMコードを64bitではなく仮に4bitとして、1-Wire上に0101, 0110, 1001(LSB first表記)のROMコードを持つデバイス3台が存在するとします。

  bit位置
デバイス 0123
0101
B0110
C1001

ここで0bit目から値0の枝を優先して検索を行うと以下のようになります
0bit目
初期状態で全てのデバイスが動作している。 A,B:0 C:1と値が不一致で衝突しているので0側の枝を選択、1の側(1xxx)に属するデバイス(ここではCのみ)を停止させる--(1)
1bit目
デバイスA,Bが動作している。 A,Bの値は1で一致しているので1の枝を選び検索を続行
2bit目
デバイスA,Bが動作している。 A:0, B:1と値が不一致。 0側の枝を選択、1側(011x)に属するデバイス(B)を停止させる--(2)
3bit目
デバイスAが動作している A:1で4bit分全てが確定、これが得られたROMコード(0101:4bit)になる

ROMコード検索木



全ての1-Wire上のデバイスのROMコードを求めるには、各デバイスのROMコードが見つかったら、バックトラックを行い64bitのROMコード全体の木検索を行えばいいことになります。ROMコードの値の衝突が起きていないbitでは一意に値が決まりますので実際に検索しなければならない範囲は64bitの木全体から見れば小さい範囲になります。 これはbit演算主体のプログラムになり、結構面倒ですね。MAXIMはサンプルプログラムも公開していますので興味があったら参照してみてください。

DS2480BによるROMコードの検索

DS2480Bを使う場合は上記のROMコードの検索処理のかなりの部分をハードウェアが半自動で行ってくれます。 DS2480Bの「検索アクセラレータ」をOnにして必要なパラメータを送ると、そのパラメータに適合したデバイスのROMコードが戻り値に返されます。上の4bitの例であればデバイスAのROMコード:0101と値の衝突が発生した位置(0bitと2bitで発生):1010の2つの情報がいきなり得られます。値の衝突が発生した位置のデータは「不一致フラグ」と呼ばれます。 入力で使用するパラメータは「値の衝突があった場合どちらの枝を検索するか」を示すデータです。これはインデックス値と呼ばれ、ROMコードの各bitに対応する64bit分ですがフォーマットの関係で128bit(=16byte)のデータをホストは送ります。条件に合致するデバイスのROMコード(64bit)と検索中に値の衝突が発生したビット位置(=検索木の分岐がある位置)のデータ(64bit)の128bit(=16byte)の情報を返してくれます。 たとえば値の衝突を検出した場合に、全ての場合で'0'の側の枝をたどる検索を行うのであればパラメータ64bit分に全て0をセットして検索を行います。 得られた不一致フラグとROMコードから次の検索を行う場合のインデックス値を作り出し、新しいデバイスが見つからなくなるまで検索を繰り返せば1-Wire上の全てのデバイスのROMコードが得られます。

インデックス値の作成と不一致フラグ

ここではDS2480Bで検索アクセラレータを使う場合でもれなく全てのデバイスを検索するためのインデックス値を決める方法について説明します。初期状態ではインデックス値には全bit0の値を与えることにします。 いくつかの1-Wireデバイスが接続され、正常に動作しているならそのうちの一つのデバイスのROMコードと不一致フラグが得られます。2回目以降の検索では今得られたROMコードと、不一致フラグから「未検索の枝」を見つけてそちらを検索するようにインデックス値で指定してやります。 最初の検索では不一致を検出した場合に0を選ぶように指定していますので不一致を検出し、かつ対応するROMコードのbit位置の値が0のものは「未検索の枝」が残っていることになります。ここでは「未検索の枝」のうちMSBに近い側から1の側の枝を選んで検索するよう指定していきます。 インデックス値のフォーマット、作成方法はデータシートを丹念に読めばわかるようになっていますが、一見わかりにくいところもあるので図示します。
  • 検索アクセラレータの出力  128bit(=16byte)の出力は奇数ビットにROMコード、偶数ビットに不一致フラグとビット毎交互に情報が収められています
  • 検索アクセラレータ出力


  • インデックス値の作成
    1. 前回の検索アクセラレータ出力の最大不一致ビットに対応するROMコードのビットを1にする
    2. インデックス値作成1


    3. 今1.の手順で1にしたROMコードのビットよりMSBに近いビットを全て0にする
    4. インデックス値作成2


    5. 作成した64bitのデータを奇数ビットにして128bitに拡張する。偶数ビットの値は任意でよい
    6. インデックス値作成3


ここで得られた値を次の検索で使うインデックス値として使うと先の検索で見つかったデバイスとは別のデバイスのROMコードが得られます。これをLSBまで行うと全てのデバイスが見つかります。ただし最初の検索で無効にした枝の中に複数のデバイスが含まれる場合もありますので、最初に見つかった「不一致フラグ」の1の数より多くのデバイスが1-Wire上にあることもあります。 インデックス値、ROMコードの出力、不一致フラグのフォーマットはハードウェアの都合が極めて強く出たもののようでソフトウェアを作成する立場からすれば無駄に複雑な構造に見えるかもしれません。ホスト側からはシリアルインターフェースからbyte単位でデータの送受信をしますが、DS2480BはROMコード検索のbit単位処理をシリアル送受信の合間にやっているんですよねぇ…… あくまで印象ですが、DS2480Bは比較的小規模な回路追加で可能なシーケンス処理に絞って実現したように思います。その分いくらかはソフトウェア側にしわ寄せが行っているというような点もあるかもしれません。データシートの記述はもう少しわかりやすいものであれば良かったとは思いますが、実行例などが記載されているのでかなり助けられました。 今回は主に1-WireデバイスのROMコード(1-Wireのアドレス情報)の検索について書きました。 次回は今回書けなかったDS2480Bを使う場合の注意点、そのほかの機能について書くつもりです。