/* ======================================================== 対SoC 新規チャンネル I2C通信 藤田@開技.nintendo '09 Apr $Id: i2c_ctr.c 418 2011-09-22 01:35:37Z n2232 $ ======================================================== */ #ifndef _WIN32 #pragma interrupt INTIICA1 int_iic_ctr RB1 #endif #include "incs.h" #include "rtc.h" #include "pedometer.h" #ifdef _MCU_BSR_ // #ifdef _MODEL_TS0_ || _MODEL_WM0_ // ワーキングモデルはI2Cが逆 // TEGは回路図でテレコ #define ACKD ACKD1 #define ACKE ACKE1 #define COI COI1 #define IICAEN IICA1EN #define IICRSV IICRSV1 #define IICA IICA1 #define IICAIF IICAIF1 #define IICAMK IICAMK1 #define IICAPR0 IICAPR11 #define IICAPR1 IICAPR01 #define IICCTL0 IICCTL10 #define IICE IICE1 #define IICF IICF1 #define IICS IICS1 #define IICWH IICWH1 #define IICWL IICWL1 #define LREL LREL1 #define SPD SPD1 #define SPIE SPIE1 #define STCEN STCEN1 #define STD STD1 #define SVA SVA1 #define WREL WREL1 #define WTIM WTIM1 #define TRC TRC1 #define SMC SMC1 #define DFC DFC1 #define IICS IICS1 #define PortMode PM20 #define Port P20 #endif // ============================================== enum en_IIC_STATE { IIC_IDLE = 0, IIC_RCV_REG_ADRS, IIC_TX_OR_RX, IIC_TX, IIC_RX }; // ============================================== extern bit irq_readed; // いずれかのIRQレジスタが読まれた u8 iic_burst_state; static enum en_IIC_STATE state = IIC_IDLE; #define bit_iics_spd (i2c_stat & (1<<0)) #define bit_iics_std (i2c_stat & (1<<1)) #define bit_iics_ackd (i2c_stat & (1<<2)) #define bit_iics_trc (i2c_stat & (1<<3)) #define bit_iics_coi (i2c_stat & (1<<4)) /********************************************//** isr ステート毎に割り込みが入り処理を進める ***********************************************/ __interrupt void int_iic_ctr( ) { static u8 reg_adrs; static u8 tx_buf; u8 rx_buf; static u8 adrs_access_from; // バーストアクセスの時に使う u8 i2c_stat = IICS; // volatileのため // 読み出し終了 if( !bit_iics_ackd // 割り込み要因はNAK(データ送信の最後) || bit_iics_spd ) // ストップコンディション(!ACKD に来たときは割り込み来ない (SPIE = 0)) { /* I2Cの反応が遅くてこのフラグを処理する前にSTDがきてしまうことがある けど、問題なく動作するつもり */ // レジスタリードで、割り込みピンをネゲート // まだ読まれてない割り込みがあれば、再度アサート if( irq_readed ) { IRQ0_neg; irq_readed = false; if( !( (( vreg_ctr[VREG_C_IRQ0] & vreg_ctr[VREG_C_IRQ_MASK0 ] ) == 0 ) && (( vreg_ctr[VREG_C_IRQ1] & vreg_ctr[VREG_C_IRQ_MASK1 ] ) == 0 ) && (( vreg_ctr[VREG_C_IRQ2] & vreg_ctr[VREG_C_IRQ_MASK2 ] ) == 0 ) && (( vreg_ctr[VREG_C_IRQ3] & vreg_ctr[VREG_C_IRQ_MASK3 ] ) == 0 ) )) { while( !IRQ0 ){;} // 時間稼ぎ不要かも IRQ0_ast; } } // I2C終了時に何かする物 // hosu_read_end( ); // 歩数計読み出し終了 rtc_unlock( ); state = IIC_IDLE; SPIE = 0; LREL = 1; EI(); return; } if( bit_iics_std ) // 割り込み要因:スタートコンディション { if( !( state == IIC_IDLE || state == IIC_TX_OR_RX )) { // sp/nack 取り損ねた // dbg_nop(); // こないはず... /* // パケットの先頭のstと見なす。 // 普通に続行 state = IIC_IDLE; /*/ // リトライしてもらう state = IIC_IDLE; SPIE = 0; LREL = 1; EI(); //*/ } // 通常 } EI(); switch ( state ) { case ( IIC_IDLE ): // 自局呼び出しに応答。 // 初期化など iic_burst_state = 0; SPIE = 1; WREL = 1; // ウェイト解除 state = IIC_RCV_REG_ADRS; return; case ( IIC_RCV_REG_ADRS ): // 2バイト目(レジスタアドレス)受信後に来る // レジスタアドレス受信 reg_adrs = IICA; WREL = 1; adrs_access_from = reg_adrs; tx_buf = vreg_ctr_read( reg_adrs ); // データの準備をしておく state = IIC_TX_OR_RX; return; case ( IIC_TX_OR_RX ): // ↑の次に来る割り込み。STなら送信準備、データが来たら書き込まれ // if( TRC ) // 送信方向フラグ で区別するのは、割り込み遅延時に不具合が起こりえる if( bit_iics_std ) { // スタートコンディション検出フラグ // リードされる if( bit_iics_coi ) { // アドレス一致フラグ state = IIC_TX; // no break, no return // } else { // リスタートで違うデバイスが呼ばれた! SPIE = 0; LREL = 1; // ウェイト解除? state = IIC_IDLE; // 終了処理 return; } } else { state = IIC_RX; // データ1バイト受信の割り込みだった // no break, no return // } /* FALLTHROUGH */ default: // バースト R/W でここが何回も呼ばれることになる if( state == IIC_TX ) { // 送信 IICA = tx_buf; vreg_ctr_after_read( reg_adrs, tx_buf ); // 読んだらクリアなどの処理 } else { // 受信 rx_buf = IICA; #ifdef _I2C_ERR_ABORT_ if( reg_adrs >= 0x80 || reg_adrs <= 1 ) { LREL = 1; // なんかデータ化けたので通信終了 nakが返るのがなぁ… return; } #endif vreg_ctr_write( reg_adrs, rx_buf ); WREL = 1; } // レジスタアドレスのインクリメント /// アクセスポインタを進めない特殊なレジスタ switch( adrs_access_from ) { case( VREG_C_ACC_HOSU_HIST ): case( VREG_C_LED_NOTIFY_DATA ): case( VREG_C_LED_POW ): case( VREG_CX_INFO ): case( VREG_CX_FREE_DATA ): break; case( VREG_CX_FREE_ADRS ): if( reg_adrs == VREG_CX_FREE_ADRS ) { reg_adrs = VREG_CX_FREE_DATA; } break; default: reg_adrs ++; } if( state == IIC_TX ) { // さらにつぎに送るデータの準備だけシテオク。SPが来て使われないかもしれない tx_buf = vreg_ctr_read( reg_adrs ); } break; } } /********************************************//**  モジュール初期化    todo twl の init と統合?    ビット操作が多いのでかえって不経済かもしれない ***********************************************/ void IIC_ctr_Init( void ) { IICAEN = 1; IICE = 0; /* IICA disable */ IICAMK = 1; /* INTIICA disable */ IICAIF = 0; /* clear INTIICA interrupt flag */ // IICAPR0 = 1; /* set INTIICA high priority */ // IICAPR1 = 0; /* set INTIICA high priority */ スタック不足 P20 &= ~0x3; SVA = IIC_C_SLAVEADDRESS; IICF = 0x01; STCEN = 1; // リスタートの許可 IICRSV = 1; // 通信予約をさせない:スレーブに徹する SPIE = 0; // ストップコンディションでの割り込みを禁止 WTIM = 1; // 自動でACKを返した後clkをLに固定する ACKE = 1; IICWH = 9; IICWL = 11; // L期間の長さ SMC = 1; // 高速モード DFC = 1; // デジタルフィルタon (@fast mode) IICAMK = 0; // 割り込みを許可 IICE = 1; PortMode &= ~0x03; Port &= ~0x03; state = IIC_IDLE; } /********************************************//** ***********************************************/ void IIC_ctr_Stop( void ) { IICE = 0; /* IICA disable */ IICAEN = 0; }