/****************************************************************************** ソフトウェアI2C通信 de JHL 藤田@開技 '07 Aug, '07 Dec !!注意!! ・読み出し&書き込みを行うと (vol inc/dec) およそ1msかかります。 ・クロックのデューティーなどを要求しないでください。 ・割り込み禁止にしてないのでタイミングによっては割り込みが入ります。 ・波形の対称性など気にしていません。最速でパタパタしますが、もともと遅いです。 ・ウェイトコンディションをとりあえず気にしません。 ・通信相手のセットアップタイムを気にせずに読みに行きます。でもともと遅いです(およそ1.2us)。 ・通信中に割り込みなどでさらに通信が開始されることを想定していません。  (排他処理やバッファで受けたりしません)しないでください。 *******************************************************************************/ #include "macrodriver.h" #include "port.h" #include "user_define.h" #include "SW_I2C.h" #define iics_sda_H PM1.1 = 1 #define iics_sda_L { P1.1 = 0; PM1.1 = 0; } #define iics_scl_H PM1.0 = 1 #define iics_scl_L { P1.0 = 0; PM1.0 = 0; } #define iics_sda P1.1 #define iics_scl P1.0 #define iic2m_send_start { iics_sda_H; iics_scl_H; iics_sda_L; iics_scl_L; } #define iic2m_send_stop_0 { iics_sda_L; iics_scl_H; } // ここでウェイトコンディションチェック // #define iic2m_send_stop_1 { iics_sda_H; } #define iic2m_send_stop { iic2m_send_stop_0; iic2m_send_stop_1; } #define iic2m_send_nack { iics_sda_H; iics_scl_H; iics_scl_H; iics_scl_L; } /****************************************************************************** * スレーブアドレスアドレス slv_adrs の、レジスタ adrs (1バイト)返します。  * リードエラーとかケアしません。危険。 ******************************************************************************/ u8 iic2m_read_byte( u8 slv_adrs, u8 adrs ){ u8 b, tmp; iic2m_send_start; if( iic2m_w_byte( slv_adrs | 0x00 ) != 0x00 ){ // スレーブアドレス iic2m_send_stop; return( 0x5A ); } iic2m_w_byte( adrs ); iic2m_send_start; if( iic2m_w_byte( slv_adrs | 0x01 ) != 0x00 ){ // スレーブアドレス iic2m_send_stop; return( 0xA5 ); } // 実リード iics_sda_H; for( b = 0; b != 8; b++ ){ tmp <<= 1; iics_scl_H; if( iics_sda != 0 ){ tmp |= 0x01; } iics_scl_L; } iic2m_send_nack; // 最終バイトはNACKを返す。 iic2m_send_stop; return tmp; } /****************************************************************************** * スレーブアドレスアドレス slv_adrs の、レジスタ adrs に1バイト書きます。 * スレーブ呼び出しでNACKなら、0xFFで中断終了です。 ******************************************************************************/ unsigned char iic2m_write_data( u8 slv_adrs, u8 adrs, u8 dat ){ u8 status; iic2m_send_start; if( iic2m_w_byte( slv_adrs | 0x00 ) != 0x00 ){ // スレーブアドレス iic2m_send_stop; return( 0xFF ); } iic2m_w_byte( adrs ); // レジスタアドレス iic2m_w_byte( dat ); // データ1バイト iic2m_send_stop; return( 0 ); } #if 0 未使用です /****************************************************************************** * スレーブアドレスアドレス slv_adrs の、 * レジスタ adrs を先頭に、 * *strから * len文字書きます。 * エラーとかケアしません。危険。 ******************************************************************************/ void iic2m_write_nmem( u8 slv_adrs, u8 adrs, s8* str, u8 len ){ u8 i; iic2m_send_start; iic2m_w_byte( slv_adrs | 0x00 ); iic2m_w_byte( adrs ); for( i = 0; i < len; i++ ){ iic2m_w_byte( *str ); str++; } /* while( *str != "\0" ){ iic2m_w_byte( *str ); str++; } */ iic2m_send_stop; } #endif /****************************************************************************** バスのリセット ストップコンディションが出せそうだったらすかさず出す。 ******************************************************************************/ void iic2m_bus_reset(){ u8 count; for( count = 19; count != 0; count-- ){ iics_sda_H; iics_scl_H; PM1.1 = 1; // SDA if( iics_sda != 0 ){ PM1.1 = 0; iic2m_send_stop; return; } PM1.1 = 0; iics_scl_L; } return; } /****************************************************************************** I2C単機能API ほんとに1バイト書くだけ ******************************************************************************/ static unsigned char iic2m_w_byte( unsigned char dat ){ unsigned char b; unsigned int tot; // 引数の8bitを順々にだします。 for( b = 0; b != 8; b++ ){ if( ( dat & 0b10000000 ) != 0 ){ iics_sda_H; }else{ iics_sda_L; } iics_scl_H; dat <<= 1; // ついでに時間稼ぎ。アセンブラならもっと上手に書くのに! iics_scl_L; } iics_sda_H; iics_scl_H; #ifdef enable_swi2c_wait tot = 0; while( iics_scl == 0 ){ // ウェイトコンディション // まじめにやるとタイムアウトとかどうしようとか、何かスレーブが // バスを開放してくれなくなったら、もう全デバイスと通信できないじゃんとか if( ++tot > 10000 ){ iics_scl_L; return( 0xFE ); } } #endif if( iics_sda != 0 ){ // NACK iics_scl_L; return( 0xFF ); } iics_scl_L; return( 0 ); }