SIRCS,Propeller流 状態:この文書の翻訳作業は完了しています 原文:nvp4.pdf 翻訳者:caskaz 対象読者:SIRCSしたい人 By Jon Williams 僕にはカメラのpan/tilt制御をする周辺機器の設計をしているLouという友人がいる。 SIRCSプロトコル †SIRCS(Sony IR Control System)プロトコルを知らない人の為に説明しよう。 SIRCSシステムの受信側の復変調素子はFigure1の様にactive-Lの信号を出力する。 違う機器には違う長さのコードが使われている。 PropellerでSIRCSをデコード †Propellerを使って良い点は1個のCogでSIRCSをデコードできることだ。 DMX512プロジェクトでコードを簡単にする為に各Cog内で多目的タイマーを利用したことを覚えているだろう。 rxsircs mov ctra, NEG_DETECT mov frqa, #1 mov ctrb, FREE_RUN mov frqb, #1 waitok rdlong tmp1, okpntr wz if_nz jmp #waitok waitstart waitpeq irmask, irmask mov phsa, #0 waitpne irmask, irmask mov phsb, #0 waitpeq irmask, irmask cmp START_BIT, phsa wc if_nc jmp #waitstart 上記は2個のカウンターを使用している。CounterAは入力パルス巾を測定するためにnegative detectモードで、counterBはフレームタイミングを追跡する為にfree-runモードでセットアップしている。プログラムはラベルwaitokの箇所でHubからokpntr を読んで、このokpntr でSIRCSデコーダを必要な時に使用できるようにしている。 この部分の最初でwaitpeqを使って入力ピンをマスクしてIR入力ピンがhighになるのを待つ。全部のビット巾測定が確実にできるように入力ピンのラインがhighの時にこの処理をスタートする必要がある。(不正確な測定をしない為に) ラインがlowになった時PHSBをクリアするのはなぜか? スタートビットを検出したら次のステップはdevice/keyコードを構成する全ビットを収集することだ。 mov irwork, #0 mov bits,#0 checkframe cmp MS_044, phsb wc if_c jmp #irdone waitbit test irmask, ina wz if_nz jmp #checkframe measurebit mov phsa, #0 waitpeq irmask, irmask cmp ONE_BIT, phsa wc rcr irwork, #1 add bits, #1 cmp bits, #20 wc if_b jmp #checkframe irdone mov tmp1, #32 sub tmp1, bits shr irwork, tmp1 report wrlong irwork, codepntr wrlong bits, bitspntr wrlong DONE, okpntr jmp #waitok デコーダプログラムはそれが何番目のデータかわからないので、受信ビット数と同様に受信コード列(irwork)も保持する。 妙な配置の様に思えるが、ビット受信ループのトップ(checkframe)のフレームタイマー(PHSB)でフレームが終了したかどうかをテストしている。 もしフレームがまだアクティブなら新しいビット(入力ラインはlow)をテストする。入力ラインがhighなら正しく処理を終了させる為にcheckframeへ戻らなければならない。 20ビット受信するかフレームタイマーが44msecondsになったらプログラムはirdoneへと進み、結果を得る。ビット列はLSBから始まるがそれをirdoneに左から右の方にシフトするので結果としてirdoneにはMSBが左となるように整頓されている。 最後にirworkにある値と受信ビット数はHubに書き戻され、フラグをイネーブルにする。 SIRCS”Sniffer” †1年前SXベースのSIRCS"Sniffer”プログラムを作成して、僕の家中の色々なSonyリモートのコードを片っ端から測定した。−今度はこれをPropellerで作成してみた。 PUB main | code, bc ir.init(0) term.init(30, 115_200) waitcnt(clkfreq / 1_000 + cnt) term.str(string(CLS, “SIRCS Sniffer”, CR, CR)) repeat code := ir.getir bc := ir.bitcount case bc 12: term.str(string(“12 :: “)) term.bin(code >> 7, 5) term.tx(“.”) Term.bin(code, 7) 20: term.str(string(“20 :: “)) term.bin(code >> 12, 8) term.tx(“.”) Term.bin(code, 12) other: if bc < 10 term.tx(“0”) term.dec(bc) term.bin(string(“ :: “)) Term.bin(code, 32) term.tx(CR) waitcnt(clkfreq / 4 + cnt) 上記のメインループでIRオブジェクトの.getirメソッドを呼び出している。このメソッドはSIRCS受信をイネーブルにして入力ビット列を待って結果を戻す。 ビット列は画面で見えるようにしたいので出力部はビット数とそれからデバイスコードとキーコードを分けて表示している。 このプログラムのハードウェアは簡単だ 君も色々実験したら、SIRCSを使っている同じブランドの製品だとしても多種多様なのでキーコードが同じでも固有のデバイスコードを持っているのがわかるだろう。 PropellerでSIRCSを送信 †Sony DSLRを制御するにはSIRCSの送信をするプログラム必要だ。 Figur5はPropellerとIR LEDの接続図だ。アノードを3.3Vに繋いでカソード側でコントロールと変調を行うことに注目してほしい。SXでは2本のピンを使ってたことを覚えているかもしれない。 カソードピンに対してカウンターをNCOモードにセットすることでLEDに変調信号を出力でき、そのカソードピンに”1”を書き込むことによっていつでも信号をディセーブルできる。こうするとカソードをhighにするとLEDもオフし、カソードをlowにするとカウンターからの変調信号はLEDをドライブする。 コード解析の前に一仕事あるんだ。カウンターをNCOモードで使う時、希望する出力周波数を出力するためにFRQxレジスタに値をセットしておかなければいけない。 僕はPropellerプロジェクトを80MHzで作っているのでIRリモートで使う変調周波数をごく一般的な値にした場合の定数を求めた。 txsircs or outa, ircath or dira, ircath mov frqa, modfreq mov ctra, modctrl waitcmd rdlong frcount, fcpntr wz if_z jmp #waitcmd rdlong bitcount, bcpntr rdlong code, irpntr 送信はフレーム数、ビット数、コードを持つHub変数を読み出してから始める。 startframe mov bcount, txbitcount mov testmask, #1 mov frametimer, MS_45 add frametimer, cnt txstart mov bittimer, BIT_START call #txbit 普通1フレーム以上を送信するのでbitcountをコピーしてビット0をセットアップするmask(testmask)を作っておく。 SIRCSフレームの最初の要素は2.4msのスタートビットだ。これを処理する為にスタートビットのタイミングで変数bittimerをロードしてサブルーチンtxbitをコールする。 txbit add bittimer, cnt andn outa, ircath waitcnt bittimer, #0 or outa, ircath txpad mov bittimer, BIT_PRO add bittimer, cnt waitcnt bittimer, #0 txbit_ret ret bittimerをシステムカウンタ(cnt)に同期させてカソードピンをlowにすることでLEDをイネーブルにする。そして、タイマが停止するのを待つ。タイマが停止した時LEDがオフしtxpadでビットの間に0.6msのpadを挿入する。 最後に重要な事をひとつ話そう。サブルーチンの最後の行でtxbit_retがあるのに気がついてると思う。これは特別なラベルだ。 name1_ret name2_ret ret ret文は最後の行のみに置けることに注意してくれ。 txcmd test txcode, mask wz if_z mov bittimer, BIT_0 if_nz mov bittimer, BIT_1 call #txbit shl mask, #1 checkdone djnz bcount, #txcmd PASMで好きなところは色々あるけれどその中の一つが条件文だ。最初のtxcmdはtestを使って現在のbitの状態を調べている。testはandと同じ動作だけれど変数自身は変化させない(ここではtxcode) 次の2行は条件文でbittimerを特定の値に設定している。if_zならbittimerに”bit 0”の時のタイミングをコピーする。 Txbitをコールする場所のタイミングで、次のビットの為にmaskを1ビット左にシフトし、そして最後にbit countをアップデートする。 waitframe waitcnt frametimer, #0 djnz frames, #startframe txdone wrlong ZERO, fcpntr jmp #waitcmd 最後のステップはフレーム数を保存しているHub変数にゼロを書くことだ。これで送信が終了したことを呼出し側に伝える。Hub変数をアップデートしてwaitcmdに戻って別のSIRCS device/keyコードフレームの送信リクエストがあるまでそこで待つ。 ちょっと楽しいかい? Jon Williams Parallax,Inc |