#pragma interrupt INTIIC0 MD_INTIIC0 #define ignore_NAK 0 #include "macrodriver.h" #include "I2C.h" #include "user_define.h" #include "jhl_defs.h" #include "vreg.h" #include "I2C_selfprog.h" #include "wdt.h" extern u8 vregs[]; #include "PMIC_TWL2.h" extern bit self_prog_mode; /***************************************************************************** 低レベル向け? *****************************************************************************/ volatile UCHAR gIic0SlaveStatusFlag; /***************************************************************************** プロトコル層?向け *****************************************************************************/ extern UCHAR vregs[]; UCHAR i2c_Send_start_addr; UCHAR i2c_accessRegAdr; u8 vreg_adrs; u8 rcvd_buff; u8 pre_dat; // 注! ↓はマクロなので、returnはメインループに戻ります。 #define wait_next { \ while( IICIF0 != 1 ){ \ if( SPD0 ){ \ LREL0 = 1; \ return; \ } \ } \ } __interrupt void MD_INTIIC0( void ){ WREL0 = 1; // ウェイト解除して次のバイトを待つ // フラグ1回目 スレーブアドレス,R/W if( COI0 != 1 ){ // 被呼び出し? LREL0 = 1; // 呼ばれたのは他のID return; }else{ // ACKE0 = 1; // 自動でackを返すようにする // WREL0 = 1; // ウェイト解除して次のバイトを待つ } wait_next; // 1バイト受信完了を待つ // 2回目 R/W レジスタアドレス WREL0 = 1; IICIF0 = 0; vreg_adrs = adrs_table_ext2int( IIC0 ); // 3回目 // スタートコンディションか、データ受信完了フラグ待ち while( 1 ){ if( IICIF0 == 1 ){ // 受信 // IICIF0 = 0; WREL0 = 1; if( ( IIC0 == 0x4A ) && ( vreg_adrs == REG_INT_ADRS_TEMP7 ) ){ // 自己プログラム書き換えモード // // ここで分岐は美しくない気もします... vregs[ REG_INT_ADRS_MODE ] = 0x00; // 電源オフ時間を短くせんがため。 PM_set_VRSET(); self_programming(); // 帰ってきません }else{ // 通常アクセス(ライト) // LREL0 = 1; debug_led_on; vregs_write( vreg_adrs, IIC0 ); debug_led_off; return; // 受信おしまい // } }else if( STD0 ){ // 送信 // (スタートコンディション検出) pre_dat = vregs_read( vreg_adrs ); // mcu内部アドレスを渡す。一バイト目の準備 IIc0に書き込むとウェイト解除 // 自局をRで呼ばれるのを待つ wait_next; IICIF0 = 0; if( COI0 != 1 ){ // 被呼び出し? LREL0 = 1; // 呼ばれたのは他のID(あれ?) return; } IIC0 = pre_dat; // データを送る wait_next; // 4回目。(送信データ後の、ACK/NACK後) どうしても発生してしまう。 IICIF0 = 0; // おしまい LREL0 = 1; return; }else if( SPD0 ){ // 強制終了 LREL0 = 1; return; } } } /***************************************************************************** 基本API *****************************************************************************/ void IIC0_Init( void ) { IICE0 = 0; /* IIC0 disable */ IICMK0 = 1; /* INTIIC0 disable */ IICIF0 = 0; /* clear INTIIC0 interrupt flag */ IICPR0 = 0; /* set INTIIC0 high priority */ PM6 &= ~0x1; /* set clock pin for IIC0 */ P6 &= ~0x1; PM6 &= ~0x2; /* set data transfer I/O pin for IIC0 */ P6 &= ~0x2; IICCL0 = IICCL0_INITIALVALUE | IIC0_CLOCK4; // レジスタ初期化、高速モード IICX0 = IIC0_EXPENSION0; // 〃 SVA0 = IIC0_SLAVEADDRESS; STCEN = 1; // リスタートの許可 IICRSV = 1; // 通信予約をさせない:スレーブに徹する SPIE0 = 0; // ストップコンディションでの割り込みを禁止 WTIM0 = 1; // 自動でACKを返した後clkをLに固定する ACKE0 = 1; // ダメCPUは無視して次の通信をはじめるかもしれないんで早くclkを開放しないといけない IICMK0 = 0; // 割り込みを許可 IICE0 = 1; } //**************************************************************************** void IIC0_Stop( void ){ IICE0 = 0; /* IIC0 disable */ } void IIC0_SlaveReceiveStart(){ gIic0SlaveStatusFlag = 0; IICE0 = 1; LREL0 = 1; return; }