• 2022/12/03
  • 通信

通信

RL-78のI2C操作例

距離センサとのIFをI2Cで行いました。距離センサは「MTOF171000C0」はRxDの操作でI2Cから切り離せて、複数のセンサを選択するCS信号として扱えると記載されています。ネット内ではTxDという説もありますが、どちらを操作してもCSとして機能しません
だまされた感はありますが、1ケであれば問題なく使えますし、クロック信号線に双方向バスバッファ(PCA9515Aなど)挿入して複数センサを扱うこともできます

ここでは、センサ1ケを対象にしたI2C通信例を説明します。通信仕様はいかのシーケンスに従います

・_gDistStateをenDistState_SndCmdにセットしてReadData関数をコールして読込みを開始します

・enDistState_SndCmd:バス解放・マスタ通信状態であればSST0をセットし、スタートコンディションを生成します(①)

・enDistState_SndCmdsStaWait:スタートコンディションを生成したら、シフトレジスタへスレーブアドレスを書込みます(②)

・enDistState_SndCmdWait:スレーブアドレスとコマンドが送信されるのを待ちます

・_I2c_Int関数のコメント欄③④⑤⑥と割込み内で処理されます。

・③は、スレーブアドレス送信に対するスレーブからのACK応答

・④は、ACK後のコマンド送信

・⑤は、コマンド送信に対するスレーブからのACK応答

・⑥は、⑤の応答で送信完了のフラグがセットされる

・enDistState_RcvDat:データ受信シーケンスのスタートコンディションをSST0をセットし生成します(⑦)

・enDistState_RcvDatStaWait:スタートコンディションを生成したら、シフトレジスタへスレーブアドレスを読込み条件にして書込みます(⑧)。この時データの読込み先ポインタを渡します(ここに受信データが格納されます)

・enDistState_RcvDatWait:_I2c_Int関数のコメント欄⑨➉⑪と割込み内で処理され、受信データが読込み先ポインタに格納されます

・外部からの完了判定は戻り値か_gDistState がenDistState_Standbyとなったら完了です

ReadData関数のコールはmain関数から連続でコールしてください

//*************************
// 距離センサタイミング
//*************************
typedef enum
{
	enDistState_Standby			= 0,					// 待機中
	enDistState_SndCmd,									// コマンド送信
	enDistState_SndCmdsStaWait,							// スタートコンディション生成待ち
	enDistState_SndCmdWait,								// コマンド送信完了待ち
	enDistState_RcvDat,									// データ受信
	enDistState_RcvDatStaWait,							// スタートコンディション生成待ち
	enDistState_RcvDatWait,								// データ受信完了待ち
	enDistState_Error									// エラー
} DIST_SENSOR_STATE;

static DIST_SENSOR_STATE _gDistState = enDistState_Standby;// 距離センサ読取りステート
static uint8_t gRcvData[ 2 ];							// 受信データ

//************************************************************************************************
//	機能概要:1つの距離センサのデータを読込む
//	引数	:なし
//	戻り値	:ステート
//	備考	:
//************************************************************************************************
static SENSOR_STATE __near ReadData( void )
{
	switch( _gDistState )
	{
		case enDistState_Standby:						// 待機中
			break;
		case enDistState_SndCmd:						// コマンド送信
			/* ---< バス解放・マスタ通信状態の場合 >--- */
			if(( IICBSY0 == 0 ) || ( MSTS0 == 1 ))
			{
				STT0 = 1U;								// ① スタートコンディション生成
				_gDistState = enDistState_SndCmdsStaWait;
			}
			/* ---< バス解放・マスタ通信状態でないならエラー >--- */
			else
			{
				_gDistState = enDistState_Error;
			}
			break;
		case enDistState_SndCmdsStaWait:				// スタートコンディション生成待ち
			/* ---< スタートコンディション移行検出 + スタートコンディション検出 >--- */
			if(( STD0 == 1 ) && ( MSTS0 == 1 ))	
			{
				/* ---< コマンド送信 >--- */
				_gpTxData     = _gCmd;					// コマンド送信データポインタセット
				_gTxDataCount = sizeof( _gCmd );		// コマンド送信データ数セット
				IICA0         = ( 0x52 << 1 ) & 0xFE;	// ② シフトレジスタへスレーブアドレス書込み

				_gStatus = 1;							// マスター動作中
				_gDistState = enDistState_SndCmdWait;
			}
			break;
		case enDistState_SndCmdWait:					// スレーブアドレスとコマンド_gCmdの送信完了待ち
			switch( _gStatus )
			{
				case 0:									// ⑥送信完了
					_gDistState = enDistState_RcvDat;
					break;
				case 1:
					/* Do Nothing */					// マスター動作中なので待つ
					break;
				case 2:									// エラーセット(Ack受信できず)
				default:
					_gDistState = enDistState_Error;
					break;
			}
			break;
		case enDistState_RcvDat:						// データ受信
			/* ---< バス解放・マスタ通信状態の場合 >--- */
			if(( IICBSY0 == 0 ) || ( MSTS0 == 1 ))
			{
				STT0 = 1U;								// ⑦ スタートコンディション生成
				_gDistState = enDistState_RcvDatStaWait;
			}
			/* ---< バス解放・マスタ通信状態でないならエラー >--- */
			else
			{
				_gDistState = enDistState_Error;
			}
			break;
		case enDistState_RcvDatStaWait:					// スタートコンディション生成待ち
			/* ---< スタートコンディション移行検出 + スタートコンディション検出 >--- */
			if(( STD0 == 1 ) && ( MSTS0 == 1 ))
			{
				/* ---< データ受信 >--- */
				_gpRxData     = gRcvData;				// 受信データポインタ
				_gRxDataLen   = sizeof( gRcvData);		// 目標受信データ数
				_gRxDataCount = 0U;						// 受信データ数
				IICA0         = ( 0x52 << 1 ) | 0x01;	// ⑧ シフトレジスタへスレーブアドレス書込み

				_gStatus = 1;							// マスター動作中
				_gDistState = enDistState_RcvDatWait;
			}
			break;
		case enDistState_RcvDatWait:					// データ受信完了待ち
			switch( _gStatus )
			{
				case 0:									// ⑪
//					_I2c_SetData( Name, gRcvData);
					_gDistState = enDistState_Standby;
					break;
				case 1:
					/* Do Nothing */					// マスター動作中なので待つ
					break;
				case 2:									// エラーセット(Ack受信できず)
				default:
					_gDistState = enDistState_Error;
					break;
			}
			break;
		case enDistState_Error:							// エラー
		default:
			_gDistState = enDistState_Error;
			break;
	}
	return _gDistState;
}
#pragma interrupt _I2c_Int( vect = INTIICA0 )

//************************************************************************************************
//	機能概要:I2C割込
//	引数	:なし
//	戻り値	:なし
//	備考	:
//************************************************************************************************
static void __near _I2c_Int( void )
{
	/* ---< 多重割込許可 >--- */
	EI();												// 多重割込許可

	/* ---< マスタ通信状態でないなら戻る >--- */
	if( MSTS0 != 1U )
	{
		return;
	}

	//*************************
	//   アドレス送信完割込み
	//*************************
	if( STD0 == 1 )										// スタートコンディション検出済(アドレス転送期間)
	{
		/* ---< アドレスに対するACK受信済 >--- */
		if( ACKD0 == 1 )								// ③⑤
		{
			//*************************
			//        マスタ送信
			//*************************					// Address + Write でアドレス送信完了
			if( TRC0 == 1 )
			{
				// アドレス送信後のデータ書込みの1バイト目はここで送信するが、2バイト目以降は STD0==0 となっているので
				// 下のマスター送信で送信される
				// Data0 の1ビット目の転送時に STD0=0 とされる
				// Address(W) + Data0 + Data1 ・・・
				if ( _gTxDataCount > 0 )
				{
					IICA0 = *_gpTxData;					// ④ スレーブへデータ送信
					_gpTxData++;						// 送信データポインタ更新
					_gTxDataCount--;					// 送信データ数減算
				}
				else
				{
					_gStatus = 0;						// ⑥ 送信完了
				}
			}
			//*************************
			//      マスタ受信開始
			//*************************					// Address + Read でアドレス送信完了
			else
			{
				WTIM0 = 0;								// 8クロック目ウエイトセット
				IICA0 = 0xFF;							// ウエイト解除し、受信状態にセット
			}
		}
		/* ---< アドレスに対するNACK受信済 >--- */
		else
		{
			SPT0     = 1;								// ストップコンディション生成
			_gStatus = 2;								// エラーセット(Ack受信できず)
		}
	}
	//*************************
	//  データ送受信完割込み
	//*************************
	else
	{
		//*************************
		//        マスタ送信
		//*************************
		if( TRC0 == 1 )
		{
			/* ---< Ack受信 >--- */
			if ( ACKD0 == 1 )
			{
				if( _gTxDataCount > 0 )					// 送信データ残の確認
				{
					IICA0 = *_gpTxData;					// 送信データセット
					_gpTxData++;						// 送信データポインタ更新
					_gTxDataCount--;					// 送信データ数減算
				}
				else
				{
					_gStatus = 0;						// 送信完了
				}
			}
			/* ---< Nack受信 >--- */
			else
			{
				SPT0     = 1;							// ストップコンディション生成
				_gStatus = 2;							// エラーセット(Ack受信できず)
			}
		}
		//*************************
		//      マスタ受信開始
		//*************************
		else
		{
			/* ---< 受信データ残がある場合 >--- */
			if( _gRxDataCount < _gRxDataLen )
			{
				*_gpRxData = IICA0;						// ➉ 受信データセット
				_gpRxData++;							// 受信データポインタ更新
				_gRxDataCount++;						// 受信データ数加算

				/* ---< 受信完了 >--- */
				// 送信状態(TRC0=1)で,9クロック目ウエイト期間中にWREL0ビットを1にセットした場合,SDAA0 ラインがハイインピーダンスになる → スレーブのウエイト要求を受け付けられる
				if( _gRxDataCount == _gRxDataLen )								
				{
					ACKE0 = 0;							// 最終データのNACK生成
					WTIM0 = 1;							// 9クロック目ウエイトセット
					WREL0 = 1;							// ウエイト解除
				}
				/* ---< 受信継続 >--- */
				else
				{
					ACKE0 = 1;							// ACK送信
					WREL0 = 1;							// ウエイト解除
				}
			}
			else
			{
				SPT0     = 1;							// ⑪ ストップコンディション生成
				_gStatus = 0;							// 受信完了
			}
		}
	}
}