/* ======================================================== TWL 互換I2C $Id: i2c_twl.c 418 2011-09-22 01:35:37Z n2232 $ ======================================================== */ #ifndef _WIN32 #pragma sfr /* 特殊機能レジスタ使用 */ #endif /*============================================================================*/ #ifndef _WIN32 # pragma interrupt INTIICA0 int_iic_twl RB2 #endif #include "incs_loader.h" #include "i2c_twl_defs.h" #include "i2c_twl.h" #include "vreg_twl.h" #include "WDT.h" #ifdef _MCU_BSR_ //#ifdef _MODEL_TS0_ || _MODEL_WM0_ // ワーキングモデルはI2Cが逆 #define ACKD ACKD0 #define ACKE ACKE0 #define COI COI0 #define IICAEN IICA0EN #define IICRSV IICRSV0 #define IICA IICA0 #define IICAIF IICAIF0 #define IICAMK IICAMK0 #define IICAPR0 IICAPR00 #define IICAPR1 IICAPR10 #define IICCTL0 IICCTL00 #define IICE IICE0 #define IICF IICF0 #define IICS IICS0 #define IICWH IICWH0 #define IICWL IICWL0 #define LREL LREL0 #define SPD SPD0 #define SPIE SPIE0 #define STCEN STCEN0 #define STD STD0 #define SVA SVA0 #define WREL WREL0 #define WTIM WTIM0 #define SMC SMC0 #define TRC TRC0 #define DFC DFC0 #define PortMode PM6 #define Port P6 #endif // _MCU_BSR_ #ifndef _MCU_BSR_ // ke3の時はダミー関数 void IIC_twl_Stop( void ) { } void IIC_twl_Init( void ) { } #else // _MCU_BSR_ enum IIC_TWL_STATE{ WAIT_ADRS = 0, WAIT_DATA, DATA_READED }; /*============================================================================*/ // 注! ↓はマクロなので、returnはメインループに戻ります。 #define wait_next { \ tot = 0; \ while( IICAIF != 1 ){ \ tot ++; \ if( tot == 0 ){ \ LREL = 1; \ return; \ } \ } \ } /********************************************//** isr TWLはウェイトを理解してくれず、また、バーストR/W は しないでもらっているので、ストップコンディションまで一気にやってしまう。 ***********************************************/ __interrupt void int_iic_twl( ) { u8 vreg_adrs; u8 state; // @ WREL = 1; // ウェイト解除して次のバイトを待つ WDT_Restart(); state = WAIT_ADRS; while( 1 ) { u8 my_iics; { u16 tot; wait_next; // 1バイト受信完了を待つ } my_iics = IICS; IICAIF = 0; if( my_iics & 0x02 ) // ( STD && !SPD ) { // スタートコンディションがきた if( ( my_iics & 0x08 ) == 0 ) // ( TRC ) 送信方向フラグ 0:マイコンが受信 { // @’マイコンが応答できず、TWLがリトライしたときとか // ここに来るのはスレーブ呼び出しの時 // WREL = 1; state = WAIT_ADRS; /// レジスタアドレスが書かれるのを待つ } else { // BR Rでのスレーブ呼び出し(リスタートコンディション) // IICA = vreg_twl_read( vreg_adrs ); // データ送信 // ストップ待ち後、LREL = 1 にしないと、送信バッファが破壊されることがある state = DATA_READED; } } else if( ( my_iics & 0x03 ) == 0 ) // ( !STD && !SPD ) { u8 rcvd; // 何らか受信 rcvd = IICA; WREL = 1; if( state == WAIT_ADRS ) { // A vreg_adrs = adrs_table_twl_ext2int( rcvd ); /// データが書かれるか、リスタートで読み出されるのを待つ state = WAIT_DATA; } else if( state == DATA_READED ) { // データ1バイト送信後発生する LREL = 1; return; } else { // BW // データ書き込まれ SVA = 0x5A; // ダミー LREL = 1; // スタートコンディション待ちへ(連続書き込み未対応のため) vreg_twl_write( vreg_adrs, rcvd ); SVA = IIC_T_SLAVEADDRESS; return; // 受信おしまい // } } else if( my_iics & 0x01 ) // SPD { // 終了 LREL = 1; return; } else { // NOP(); } } } /********************************************//** モジュール初期化 ***********************************************/ void IIC_twl_Init( void ) { IICAEN = 1; IICE = 0; /* IICA disable */ IICAMK = 1; /* INTIICA disable */ IICAIF = 0; /* clear INTIICA interrupt flag */ IICAPR0 = 0; /* set INTIICA high priority */ IICAPR1 = 0; /* set INTIICA high priority */ Port &= ~0x03; SVA = IIC_T_SLAVEADDRESS; IICF = 0x01; STCEN = 1; // リスタートの許可 IICRSV = 1; // 通信予約をさせない:スレーブに徹する SPIE = 0; // ストップコンディションでの割り込みを禁止 WTIM = 1; // 自動でACKを返した後clkをLに固定する ACKE = 1; // ダメCPUは無視して次の通信をはじめるかもしれないんで早くclkを開放しないといけない IICWH = 9; IICWL = 11; // L期間の長さ(?) SMC = 1; DFC = 1; // デジタルフィルタon (@fast mode) IICAMK = 0; // 割り込みを許可 IICE = 1; PortMode &= ~0x03; LREL = 1; } /********************************************//** モジュール停止 ***********************************************/ void IIC_twl_Stop( void ) { IICE = 0; /* IICA disable */ IICAEN = 0; } #endif