今回の速度計で一番問題となるのはTM1637のI2Cモドキの2線インターフェイスだ(以降「TM-I2C」インターフェイスとする)。最初はPICのI2Cインターフェイスが流用できるかもしれないと考えたが仕様を検討して諦めた。TM-I2CもI2Cのようにクロックとデータの2線構成だが転送する最初のバイトがI2Cのアドレス+R/WではなくTM-I2Cはコマンドだ。またビットの並びも逆になっている(これはソフト的に解決可能だが)。従ってTM-I2Cはソフト的に実装する事とした。TM-I2Cの通信速度に下限規定は無いので実装は楽だろう。
TM-I2Cでデータ線は双方向通信を行う必要があるが、これはWired-OR接続で解決できる(注1)。Wired-OR接続の設定は例えばC1ポートでは次の様に設定する。
// 15: RC1 - DSPDAT
LATCbits.LATC1 = 1; // normal H
TRISCbits.TRISC1 = 0; // Output Enable
ANSELCbits.ANSC1 = 0; // Digital
ODCONCbits.ODCC1 = 1; // Open Drain
WPUCbits.WPUC1 = 1; // Weak Pull-Up
プログラム中ではデータ線、クロック線については次の様にマクロ定義している。また適当に遅延を入れてタイミングを調整している。
#define CLK_OUT LATCbits.LATC0
#define CLK_IN PORTCbits.RC0
#define DAT_OUT LATCbits.LATC1
#define DAT_IN PORTCbits.RC1
#define DLY_4US __delay_us(4)
#define DLY_10US __delay_us(10)
#define DLY_50US __delay_us(50)
クロックが1の間データ線は変化してはならない(スタート時を除く)から、1ビットの送信は、
static void tm_send_bit(boolean d){
DAT_OUT = d;
DLY_10US;
CLK_OUT = 1;
DLY_50US;
CLK_OUT = 0;
DLY_50US;
}
で良いだろう。逆に1ビットの受信は、
static boolean tm_rcv_bit(){
boolean dat;
DAT_OUT = 1;
DLY_50US;
CLK_OUT = 1;
dat = DAT_IN;
DLY_50US;
return dat;
}
スタートビット、ストップビットについては、
static void tm_start_bit(){
DAT_OUT = 0;
DLY_50US;
CLK_OUT = 0;
DLY_50US;
}
static void tm_stop_bit(){
DAT_OUT = 0;
DLY_10US;
CLK_OUT = 1;
DLY_50US;
DAT_OUT = 1;
DLY_50US;
DLY_50US;
}
としている。そして出来上がったTM-I2Cの波形は例えば次の様になった。ちなみにデコーダにはI2Cの物を使っているので結果は不正確だがデバッグには十分である。
(続く)
〔注1〕この接続法はWikipediaを見るとWired-AND接続と書かれているが、初期の8ビットのコンピュータ時代、カードエッジコネクタを通して負論理バスで接続していた頃はWired-OR接続と呼んでいた。今回は信号は正論理だが動作はOR的なのでどちらの呼称が適切だろうか?これはIC-R6のCI-Vバスでも同じ事が言えるのだが。


0 件のコメント:
コメントを投稿