信号機のアドレスはプログラム中では二つの変数My_AdrHとMy_AdrLに分割して使います。My_AdrHはMMパケットのアドレス部分に相当し、My_AdrLはMMパケットのデータ部分のうち、k83のポート部分を”00XXXX00”の形で表します。これらの変数はプログラム中で定数と定義して、異なるアドレスを持った信号機を作る際には、一個一個、PICマイコンに書き込んでも良いのですが、場合によってはレイアウトに配置した後で、アドレスを変更したい場合がないとも限りません。その都度、PICマイコンを信号機から取り外してPICKit 3で書き直すのも面倒なので、本線上に設置したままでアドレスを書き換えられる仕組みを検討します。
アクセサリデコーダk83、m83、k84、m84では、4つ(8つ)単位ではありますが、DIPスイッチでアドレスを決定できます。また、ポイント用のデコーダもDIPスイッチでアドレスを決める仕様になっています。メルクリンのアクセサリ用デコーダでは10PのDIPスイッチがデフォルトのようです。
製作する信号機にもDIPスイッチを設置できればアドレスの変更が楽で良いと思うのですが、マイコンのピン数をもっと大きなものに変更するか、DIPスイッチ専用にマイコンを増設する必要があります。結果的に、基板が大きくなってしまいますが、これはできれば避けたいところ。表面実装にして基板の集積度を上げるなどの方法もありますが、私の技術ではなかなか難しそうです。
そこで、機関車のCV値を書き換えるようにコマンドステーションからの命令でアドレスを書き換えられれば、ハードウエア的には最小で済みますし、コストも低く抑えられます。日本におけるメルクリンのバイブル的サイト“風のおひるね”さんは、アクセサリデコーダm84のCV値の書き換え方を紹介しています。m84をDCCモードにしたうえで、CS2側でDCCの機関車を仮に設定してCV値を書き換える方法です。たしかにCS2には、どこにもアクセサリデコーダのCV値を書き換える機能は見当たらないので、DCCのサービスモードを利用するしかありません。
という訳で、CS2からDCCのサービスモードによって送られてくるアドレスを受信し、EEPROMに書き込む機能を実装しようと考えました。DCCのサービスモードでは、コマンドステーションと対象とするデコーダが、1:1の接続となっており、他のデバイス(機関車やアクセサリなど)に影響を及ぼさないように接続されていることが前提条件であることにご注意ください。メルクリンにおけるプログラムトラックをちゃんと守る、ということに準ずるものです。
アドレスさえ拾えれば良いので、必要最小限の機能で良いのですが、それにしてもDCCの通信を解析する必要があります。幸いなことにNMRAのサイトでは規格が詳細に公開されているので、かなり参考になります。言語も英語だし。(メルクリンのはドイツ語が多い…)
DCCの通信では、58μsのパルス(一周期で116μs)が”1”を表します。デコーダ側では±6μsの誤差を許容しなければならないので52 ~ 64μsの範囲を”1”と見なします。一方、100μs以上の“長い”パルスは“0”を表します。“0”の場合は、許容度が広く、パルス幅としては10, 000μsまでの間延びした”0”も認められています。
1と0を判別するには、いろいろな方法が考えられますが、Lowレベルの間隔を測定して75μs未満の長さであれば1、それ以上であれば0というざっくりとした判定で必要十分です。もちろん、間延びした0もこの条件で判定できます。しきい値(75μs)はテキトーですが、結果的にこれでうまく判別できています。
この測定にはMMプロトコルの解析に用いたタイマ1を使った状態変化割り込みのルーチンをそのまま使います。 “7. パケット取得開始タイミングの決定(タイマ1)”をご参照ください。MMパケットの解析では長い時間間隔が重要だったので、タイマ1の下位8bitを表すTMR1L(TML)は使いませんでしたが、今回はむしろ短い時間間隔の方が重要となります。ただし、間延びした0についても対応する必要があるので、TMR1H(TMH)、TMR1L(TML)両方を使って正確なLowレベルの長さを評価します。
以下に1bit分を取得する関数を示します。この関数では、割り込み関数の結果を判定します。
次に肝心の命令パケットを受信するルーチンを考えます。命令パケット本体の前に1が14個以上連続で出力されるプリアンブルが流されます。その後、スタートビット0に続いて、8bitのデータが続きます。8bitのデータの区切りは0ですが、区切りが1になるとデータ送信終了となります。流されるバイト数は3バイト以上(エラー検知1バイトを含む)から、多分6バイトぐらいまででしょうか。資料をちゃんと読んでいないのでゴメンナサイ。一般的には以下に示すパケットになります。
まず、プリアンブルを検知してパケット受信に備える必要があります。1が14個以上続けばプリアンブルですが、プリアンブル以外で1が長く続く可能性を考えると、命令パケットの最終バイト(通常はエラーチェック)が11111111の場合に、ストップビット1を加えた、9個の1の連続が最長と思われます。ストップビットの後なので、次はプリアンブルが来るはずです。したがって、少なくとも1が9個続いた状況では、必ずプリアンブルに入っているものと判定できます。
以下の関数は、プリアンブルが検出できるまで関数内で待つルーチンで、検知するまでは呼び出し先の処理はそこで止まります。
順番は前後しますが、パケット中の1バイトを取得する関数を示します。外部のルーチンで、データ区切り(またはスタートビット)を検知後、コールされることにより、1バイトを取得し戻り値として返す関数です。関数内では、1bit取得するごとにデータを変数に書込みます。DCCでは上位ビットから受信するので、左から右にデータを書き込みます。MMプロトコルの逆ですが、DCC の方が直感的でよいと思います。
以下に8bit取得用の関数を示します。
道具立てが整ったので、DCCの命令パケットを受信するルーチンを考えます。DCCにおいても、命令パケットを二つ受信して、それらが一致したとき命令を実行するよう定められています。今回、対象とするサービスモードのダイレクトモードでは4バイトのデータを使いますので、D_DCC[0..7]という配列を定義して、D_DCC[0..3]は一番目のパケット、D_DCC[4..7]は二番目のパケットのデータとして扱うことにします。パケット1つを取得する関数上では、4バイト以上のパケットを処理することもあり、最大8バイトまでの命令パケットを受信できますが、4バイト以外はコール先で無視することにします。前掲した関数によって、データ取得の機能はほぼ網羅されているのですが、以下のルーチンではそれらを組み合わせて、データを配列DCC_D[x]に代入し、データのバイト数をコール先に戻します。
実際にCS2から信号機のアドレスを書き換えるためには、仮のDCC機関車を手動で登録した後、Configuration画面からCV値の書き替え画面に移ります。
CV値書き換え画面下方にあるPOM、PRG、REGのうちPRG が反転していることを確認します。CV#1:Prim. Adr.のCV値を希望する値に変更した後、右側にある書き込みボタンを押します。
この操作により、アドレス書き換え用のパケットは、“ダイレクトモード”と呼ばれる形式でトラックに出力されます。
(画面最下段の書き込みボタンを押すと他のモードで出力されるのかもしれませんが、未確認なので不明です。)
ダイレクトモードは、ある一つのCVアドレスに対して値を設定する命令です。NMRAのサイトから引用します。
オプション:必要に応じて電源オン-サイクル |
|
3つ以上のリセットパケット |
|
5つ以上のCV1-1023のどれか一つに向けての検証パケット、確認が検知されれば、続けて1つ以上のリセットパケット | あるいは、5つ以上のCV1-1023のどれか一つに向けての書込みパケット |
6つ以上の同じ書き込みパケット、またはリセットパケット(デコーダの復帰時間のため) | |
オプション:電源オフ |
電源オン-サイクルとは、線路に電源を供給した際、サービスモードの開始前にデコーダが安定するまで待つために、コマンドステーションから少なくとも20個のパケットを送信するシーケンスです。
リセットパケットはすべてのデコーダをリセット(揮発性メモリの値を初期化、電源投入時の状態にリセット、走行中の機関車はすぐに停止など)する命令です。パケットは次の形をとります。
今回は必要最小限の機能を実現することを目標としていますので、電源オン-サイクルやリセットパケットは、すべて読み飛ばします。
ダイレクトモードの命令パケットは4バイトからなり、次の形をとります。
Aは10bitでCV値の番号を示します。番号としてはAの10bitの値に1を足したものになりますので、例えば、00 00000000はCV #1を表すことになります。製作する信号機では一般に使われているとおり、00 00000000をデコーダのアドレスに割り当てます。
2bitのCCの値により、このパケットがどんな命令かを示します。どんな命令?… 今さら?
実はこのパラメータによって、三つの異なった命令に変化します。
CC=11: 書込み
10bitのアドレスで指定されたCVの値に、DDDDDDDDを上書きする命令です。この命令では、PICマイコンのEEPROMにDDDDDDDDに書き換えた後、コマンドステーションに対して確認信号を送り返します。
CC=01: 検証
10bitのアドレスで指定されたCVの現在の値が、DDDDDDDDと一致するかを検証する命令です。この命令では、PICマイコンのEEPROMに保存されているCV値をDDDDDDDDと比較して、一致していれば、コマンドステーションに対して確認信号を送り返します。プログラム中には一応、実装しましたが、この命令が実際にCS2から出ているかどうかは未確認です。
CV=10: ビット操作による書込み
10bitのアドレスで指定されたCVの値を1bit単位で書き換えます。実装していないので、詳細は省略します。
ダイレクトモードにより、CV#1のCV値を操作するプログラムを示します。プログラム上ではmain()での処理となります。まず、命令パケットのアドレスやデータなどを収容する配列DCC_D[0..7]をすべて0xFFに初期化します。次に命令パケットを受信します。ダイレクトモードでは命令パケットが4バイトなので、バイト数が4以外は読み飛ばします。
命令パケットが4バイトの場合(受信した変数はDCC_D[0..3]に入っている)、続く命令パケットをDCC_D[4..7]に受信します。これらの各々4バイトのうち、最初の3バイトが一致すれば受信に成功していると見なします。(4バイト目はエラーチェック用)
ダイレクトモードの確認およびCVアドレスが#1であることを確認した後、書き込み命令(CC=11)であればアドレスを書込み、検証命令(CC=01)であればアドレスの検証をおこないます。
プログラムのデバッグ時に、CS2からダイレクトモードの書換え命令を出力すると、デバッガが停止してしまう、という現象がおきました。CS2から書換え命令を出したときの動画を以下に示します。(路線上には対象となるデコーダが存在しない条件です。)
分かりにくいかもしれませんが、オシログラムが一瞬平坦(0 V)になった後にDCCの命令パケットが流れます。次に、5 sほどオシログラムが平坦(0 V)になり、続いて何らかのパケットを送信しています。その後、短い給電オフをはさみ、アイドルパケットに戻り、この時点でCV値の書込みに失敗したというメッセージが出ます。
CS2側からはCV値の書換え時に、給電を一瞬切って、デコーダを立ち上げ状態にリセットしてから書換え命令を出しているようです。命令を出した後はパケットの送出を止めてデコーダからの書込み完了信号(ACK)の受信を待っているのでしょうか?? 反応がなければ、何らかのパケットを送信して給電オフによるリセット後、メッセージを出してアイドル状態に戻っていると推察されます。
デバッグができないのは困りますので、CS2の給電オフによるリセットを避けるため、ブレッドボードへはCS2からではなく、別電源により給電することにしました。これでデバッガ起動中も停止することなく命令パケットを受信できるようになりました。
DCCのACK信号はデコーダ側で消費電流をパルス的に増加させることでコマンドステーションに伝える仕様となっています。(Advanced Acknowledgementというデコーダ側からパケットを送信する規格もあるようですがここでは省略します。)規定では60mA、6 ms±1 msの電流増加をデコーダ側で実施することにより、ACK信号とします。製作する信号機の場合、電流消費の大きい負荷がリレーぐらいしかないので、最大でも52 mA程度と、ちょっと足りないのですが、規定値にはかなり近い値なので、検討には値します。
疑問なのは、CS2が命令パケットを出した後の5 sにも及ぶ電源オフの意味です。この期間にデコーダ側からのACKを待ち受けるのだと最初は思ったのですが、考えてみれば、そもそも線路からの給電を断たれたら、電源を内蔵しているデコーダ以外は、どんな形であれACKを送ることはできません。したがって、この長い給電オフの前に、CS2にACK信号を届ける必要があります。NMRAの規定によれば、ダイレクトモードの書込み命令は6つ以上を出力することになっているので、最初の二つで命令を実行できれば、給電が断たれる前にACK信号を送る時間的余裕はありそうです。
という訳で、以下のACK送信関数をテストしました。デバッガは使わず、CS2の反応だけで挙動を評価しました。
案ずるより産むが易し。無事、ACKを受け取ってもらえたようです。以下の動画に示すように、CS2の反応は前掲したデコーダが無い場合とは、明らかに異なり、エラーメッセージも出ることなく通常画面に戻り、その後すぐにアイドリングシーケンスに入っています。(動画では2回、書込みをおこなっています。生活感が漂っていてすいません)もちろん、EEPROMにも新しいアドレスが書き換えられています。
書込みモードの場合は、変換したアドレスをEEPROMに保存し、書込みが終了したら、ACK信号を送信して戻ります。
検証の場合も8bitのアドレスをMMフォーマットに変換し、それをEEPROMに保存されているアドレスと比較します。一致していればACK信号を送信します。
8.パケット取得(タイマ2) | TOP pageへ | 10. ブレーキモジュール回路 |
---|