SVX日記
2005-04-02(Sat) コードを書きつつ、PICのUSART機能の翻訳(受信の巻)
えー、今日明日とカミさんがお出かけなので、丸二日ねっとりとプロッタを改造するのである。実は昨日、ウソネタをシコシコと書きつつも、めでたくPIC単体でのパラレル通信および印字には成功し「イ号作戦」を完遂していたのであった。ちなみに、一昨日の時点でハマっていた原因は「オイラSTROBEは正論理だもんね」という理由であった。実はシャープはMZ-1500の時代あたりまで神をも恐れぬ「MZ仕様」というプリンタを生産し続けていて、単純に言うとコレは「セントロニクス仕様」とSTROBEの意味が逆の通信仕様なのである。セントロでは「STROBEをH→Lと変化したらD0〜D7読んでね」という意味なのだが「MZ仕様ではL→Hと変化したらD0〜D7読んでね」なのである。このX1C用のプロッタは、MZ-700時代から生産されているプロッタの兄弟なのであるから、ちょっと考えればスグ気づきそうなものであるが、オイラはこの事実を知りつつも、接続先がX1だからという理由でしばらくタコっていたのであった。X1Cのプリンタポートは清く正しくセントロ仕様であるが、きっとプロッタの接続ポートには専用に論理反転回路が組まれていたのであろう。まーそれはともかく、PICが発するSTOROBEの論理を反転したらあっさり動いたというコトである。
で、次はシリアル通信を実装するという「ロ号作戦」に突入するのであるが、ついでにかなり前に予告しつつもすっぽかしていたPICのUSARTの機能の受信部の翻訳を進めながらコードを書くコトにするのである。オイラが先日苦心の末にあみだしたバルーンヘルプ法(訳文中の「。」にマウスカーソルを当てると原文が表示される)は翻訳中や開発中に自分が参照するぶんにも便利なので、今日は更新しながらの作業である。ひとつライブ感覚でヨロシクシェケナベィベェ。
12.2.2 USART非同期通信受信ポート_
USART受信ポートのブロックダイアグラムを図12-8に示します。RB1/RX/DTピンで受信された信号は、データ復号器にかけられます。データ復号器は実質的にはボーレートの16倍の高速シフト演算器で、実際にはメインの受信シリアルシフト演算はビットレートかFOSCで稼動します。
非同期モードの場合、受信動作を行うにはCRENビット(RCSTA<4>)をセットする必要があります。
受信ポートの主役は受信(シリアル)シフトレジスタ(RSR)です。ストップビットが検出されると、RSR内の受信データはRCREGレジスタに移動(RCREGに空きがある場合)され、移動が完了すると、RCIFビット(PIR1<5>)がセットされます。この時に割り込みを発生させるか否かは、ビットRCIE(PIE1<5>)で設定できます。なお、RCIFビットは読み出し専用ですが、RCREGレジスタが読み出されて空になると自動的にクリアされます。いうなればRCREGレジスタはダブルバッファリングされたレジスタです(深さ2のFIFOバッファと言えます)。2バイトのデータをRCREGバッファに転送、溜めておくことができ、3バイト目のデータもRSRレジスタで受信開始することができます。ただし、3バイト目のデータのストップビットを検出した時点でRCREGレジスタがデータで一杯だった場合、オーバランエラーが発生しOERRビット(RCSTA<1>)がセット、RSR内のデータは失われてしまいます。RCREGレジスタは、FIFOバッファ内の2バイトを取り出すため、連続2回読み出すことができます。
オーバランエラーのOERRビットはユーザがクリアする必要があり、これは受信回路をリセット(CRENをクリアしセット)することで実行できます。OERRビットが一旦セットされると、RSRレジスタからRCREGレジスタへの移動は停止してしまうので、OERRビットをクリアすることは重要です。
一方で、ストップビットがクリア(LOW)で検出された場合、フレーミングエラーのFERRビット(RCSTA(<2>)がセットされます。FERRビットとパリティビットは受信データと同じようにバファリングされるので、RCREGを読み出すとRX9DとFRRは次の値に更新されます。したがって、直前のRX9DとFRRの情報を失わないよう、RCREGレジスタ読み出す前に、RCSTAレジスタの内容を確認することが重要です。
非同期通信モードに設定する場合は、以下の順序で行います。
1. RB2/TX/CKピンとRB1/RX/DTピンを同期/非同期通信用の送受信ピンとして設定するため、TRISB<1>ビットをセット、TRISB<2>ビットをクリアします。
2. 望むボーレートが得られるようにSPBRGレジスタを設定します。高速ボーレートモードを利用する場合は、BRGHビットもセットします(12.1節 USARTボーレートジェネレータ(BRG)参照)。
3. SYNCビットをクリアし、SPENビットをセットすることで、非同期通信モードに設定します。
4. 割り込みを利用する場合は、RCIEビットをセットします。
5. パリティ付き9ビット送信を利用する場合、RX9ビットをセットします。
6. CRENビットをセットし受信許可の状態にします。
7. 受信が完了するとRCIFビットがセットされます。RCIEビットをセットしていたなら割り込みも発生します。
8. RCSTAビットを読んでパリティビットを取得し(有効にした場合)、受信中のエラーの有無を判定します。
9. RCREGレジスタから、8ビットの受信データを取得します。
10. 何らかのエラーが発生した場合、CRENビットをクリアしてエラーをクリアします。
……などと、マニュアルはガシガシと訳せても、コードはサッパリ動いてくれないのが世の常である。翻訳は質が低くてもある程度は役立つが、コードは動かなければまったく役に立たない。翻訳の質には上には上があるが、コードは動けばその上はあまりない。このあたり、文系と理系のソリが合わない理由なのかもしれない。
散々、悩みに悩んだのでアッサリと原因を書いてしまうのはもったいない気もするのだが、もったいぶっていても仕方ないのでアッサリ書く。ひとつの原因はメモリバンクの切り替え忘れであった。SPBRGとTXSTAにアクセスするにはバンク1に切り替える必要があるのだ。概ねPICに実装された特殊機能というのは、一度コードが書きあがってしまえば流用が利くのだが、一発目が動くまでが大変なのだ。ガッチリとマニュアルを訳し、その機能について深く知れば知るほど、うっかりタコまでの距離は離れてゆくのである……と、これくらいいーわけすれば、ダサミスをごまかせるだろ。ふぅ。
あまりにもコードでハマってたので、気分転換にハンダ付け(?)だ。先日サボッて接続してなかった、RX/TXの配線を済ませて……コテが温まったついでに、USB変換基板の抵抗なんかも付けておくか……って、ご本尊のFT232BMのみ付けないのも不自然だな……付けちゃうか!? 今度は細いコテを温めて0.8mmピッチの足をハンダ付け。作業が2度目のせいか、非常にアッサリと付いてしまった。意外とお上手じゃんオイラ。こんなにアッサリ付くなら配布中の変換基板にサービスでFT232BMのみ実装コースを設けようかしらん。
とかなんとかで、ようやくオシロレベルながら、PICのRB2/TX/CKポートからシリアル信号が出るようになりましたゼ!! で、USB変換基板経由でPCに接続し、Rubyで簡易通信スクリプト組んだら、画面に'A'がゾロゾロと出てきましたわ。FT232BMバンザイ!! USB変換基板バンザイ!!
つーわけで、なりゆきでPIC→PCへのUSB通信が成功してしまったので「ロ号作戦」を完了せずして、一気に「ハ号作戦」に差し掛かってしまったコトになるのだが、PC→PIC側の通信ができないったら、できないったら、できないったらない。目標は単なるエコーバック(PCからPICへ送ったデータを送り返す動作)なのだが、受信してるのかしてないのか、まったくの沈黙なのである。