⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c state machine.c

📁 基于ADI BLACKFIN 561的I2C接口的驱动程序及应用实例
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "I2C State Machine.h"

//--------------------------------------------------------------------------//
// Variables for I2C state machine											//
//--------------------------------------------------------------------------//
t_I2C_Main_States	m_SM_State;			// current state
t_I2C_Main_States	m_SM_Next_State;	// determines the following state
t_I2C_Message		m_Current_Message;	// message to be transferred
t_I2C_Transfer		m_Current_Transfer;	// one byte to be transferred
t_I2C_SM_Path		m_Current_SM_Path;	// used to determine SM_Next_State
bool				m_ACK_Error;		// status of last acknowledge cycle

//--------------------------------------------------------------------------//
// Function:	I2C_Setup													//
//																			//
// Access:		Public														//
//																			//
// Parameters:	New_Message													//
//					New Message to be transmitted via I2C interface			//
//																			//
// Return:		None														//
//																			//
// Description:	This function is used to reset the internal state of the	//
//				state machine and to store the message passed as parameter	//
//				inside the SM.												//
//				After this function has been called, function				//
//				I2C_Advance_State() should be called repeatedly until it	//
//				returns TRUE (then the complete message has been			//
//				transferred or an error has occured).						//
//--------------------------------------------------------------------------//
void I2C_Setup(t_I2C_Message *New_Message)
{
	m_SM_State			= I2C_IDLE;
	m_SM_Next_State		= I2C_IDLE;
	m_Current_SM_Path	= I2C_SM_Write_Path;
	m_ACK_Error			= false;
	m_Current_Message	= *New_Message;

	I2C_Set_SDA_Output();
	I2C_Set_SCL_Output();
}

//--------------------------------------------------------------------------//
// Function:	Get_Error_Status											//
//																			//
// Access:		Public														//
//																			//
// Parameters:	None														//
//																			//
// Return:		None														//
//					false:	No error occured in previous state machine cycle//
//					true:	Error occured in previous state machine cycle	//
//																			//
// Description:	This function should be called after a state machine cycle	//
//				is finished to determine if an error (missing ACK from the	//
//				Slave) has occured.											//
//--------------------------------------------------------------------------//
bool I2C_Get_Error_Status(void)
{
	return(m_ACK_Error);
}

//--------------------------------------------------------------------------//
// Function:	Advance_State												//
//																			//
// Access:		Public														//
//																			//
// Parameters:	None														//
//																			//
// Return:		Status of operation											//
//					false:	State machine cycle not finished				//
//					true:	State machine cycle finished					//
//																			//
// Description:	This is called from the user and performs one state			//
//				transition in the I2C main state machine per call.			//
//				It needs to be called until it returns "true", then the SM	//
//				has finished one complete transfer (one message has been	//
//				sent/received).												//
//--------------------------------------------------------------------------//
bool I2C_Advance_State(void)
{
	bool Return_Value = false;

	switch(m_SM_State)
	{
		// state IDLE
		case I2C_IDLE:

			// state transition IDLE -> START
			m_SM_State			= I2C_START;
			m_Current_SM_Path	= I2C_SM_Write_Path;

			// set Device Address for next write
			m_Current_Transfer.Byte			= m_Current_Message.Dev_Addr & ~I2C_READ_WRITE_BIT;
			m_Current_Transfer.Bit_Count	= I2C_DEVICE_LENGTH;

			break;

		// state START
		case I2C_START:

			if(I2C_Execute_START())
			{
				// state transition START -> WRITE_DEV_ADDR
				m_SM_State = I2C_WRITE_DEV_ADDR;
			}

			break;

		// state WRITE_DEV_ADDR
		case I2C_WRITE_DEV_ADDR:

			if(I2C_Execute_WRITE())
			{
				// state transition WRITE_DEV_ADDR -> CHECK_ACK
				m_SM_State = I2C_CHECK_ACK;

				// determine if write or read cycle has to be performed
				if(m_Current_SM_Path == I2C_SM_Write_Path)
				{
					// prepare state transition CHECK_ACK -> WRITE_REG_ADDR
					m_SM_Next_State = I2C_WRITE_REG_ADDR;
			
					// set Register Address for next write
					m_Current_Transfer.Byte			= m_Current_Message.Reg_Addr;
					m_Current_Transfer.Bit_Count	= I2C_REGISTER_LENGTH;
				}
				else
				{
					// prepare state transition CHECK_ACK -> READ_DATA
					m_SM_Next_State = I2C_READ_DATA;
				}
			}

			break;

		// state WRITE_REG_ADDR
		case I2C_WRITE_REG_ADDR:

			if(I2C_Execute_WRITE())
			{
				// state transition WRITE_REG_ADDR -> CHECK_ACK
				m_SM_State = I2C_CHECK_ACK;

				// check if R/W bit is set; if it is set, then a read cycle is to be performed
				if(m_Current_Message.Dev_Addr & I2C_READ_WRITE_BIT)
				{
					// prepare state transition CHECK_ACK -> START
					m_SM_Next_State = I2C_START;

					// next time around the SM take the "read path"
					m_Current_SM_Path	= I2C_SM_Read_Path;

					// set Device Address for next write
					m_Current_Transfer.Byte			= m_Current_Message.Dev_Addr;
					m_Current_Transfer.Bit_Count	= I2C_DEVICE_LENGTH;
				}
				else
				{
					// prepare state transition CHECK_ACK -> WRITE_DATA
					m_SM_Next_State = I2C_WRITE_DATA;

					// set Data for next write
					m_Current_Transfer.Byte			= m_Current_Message.Data;
					m_Current_Transfer.Bit_Count	= I2C_DATA_LENGTH;
				}
			}

			break;

		// state WRITE_DATA
		case I2C_WRITE_DATA:

			if(I2C_Execute_WRITE())
			{
				// state transition WRITE_DATA -> CHECK_ACK
				m_SM_State		= I2C_CHECK_ACK;
				// prepare state transition CHECK_ACK -> STOP
				m_SM_Next_State	= I2C_STOP;
			}

			break;

		// state READ_DATA
		case I2C_READ_DATA:

			if(I2C_Execute_READ())
			{
				// state transition READ_DATA -> SEND_ACK
				m_SM_State = I2C_SEND_ACK;

				// set Acknowledge for next write
				m_Current_Transfer.Byte			= I2C_ACK_VALUE;
				m_Current_Transfer.Bit_Count	= I2C_ACK_LENGTH;
			}

			break;

		// state CHECK_ACK
		case I2C_CHECK_ACK:

			if(I2C_Execute_CHECK_ACK())
			{
				// check if Slave acknowledges access
				if(m_ACK_Error)
				{
					// state transition CHECK_ACK -> STOP (error occured)
					m_SM_State = I2C_STOP;
				}
				else
				{
					// perform (earlier) prepared state transition
					m_SM_State = m_SM_Next_State;
				}
			}

			break;

		// state SEND_ACK
		case I2C_SEND_ACK:

			if(I2C_Execute_WRITE())
			{
				// state transition SEND_ACK -> STOP
				m_SM_State = I2C_STOP;
			}

			break;

		// state STOP
		case I2C_STOP:

			if(I2C_Execute_STOP())
			{
				// state transition STOP -> IDLE
				m_SM_State = I2C_IDLE;

				Return_Value = true;				// SM is finished
			}

			break;
	}

	return(Return_Value);
}


//--------------------------------------------------------------------------//
// Function:	Execute_START												//
//																			//
// Access:		Private														//
//																			//
// Parameters:	None														//
//																			//
// Return:		Status of I2C Start condition								//
//					false:	I2C Start condition not finished				//
//					true:	I2C Start condition finished					//
//																			//
// Description:	This function is called from within the SPI main state		//
//				machine.													//
//				It executes a state machine that implements the I2C Stop	//
//				condition by setting SDA to 1 while SCL is 1.				//
//--------------------------------------------------------------------------//
bool I2C_Execute_START(void)
{
	bool					Return_Value		= false;
	static t_I2C_Sub_States	I2C_START_SM_State	= I2C_SET_HIGH_SCL_SDA;

	switch(I2C_START_SM_State)
	{
		// state SET_HIGH_SCL_SDA
		case I2C_SET_HIGH_SCL_SDA:

			// state transition SET_HIGH_SCL_SDA -> SET_LOW_SDA
			I2C_START_SM_State = I2C_SET_LOW_SDA;

			I2C_Set_High_SCL();
			I2C_Set_High_SDA();

			break;

		// state SET_LOW_SDA
		case I2C_SET_LOW_SDA:

			// state transition SET_LOW_SDA -> SET_LOW_SCL
			I2C_START_SM_State = I2C_SET_LOW_SCL;

			I2C_Set_Low_SDA();

			break;

		// state SET_LOW_SCL
		case I2C_SET_LOW_SCL:

			// state transition SET_LOW_SCL -> SET_HIGH_SCL_SDA
			I2C_START_SM_State = I2C_SET_HIGH_SCL_SDA;

			I2C_Set_Low_SCL();

			Return_Value = true;				// SM is finished

			break;
	}

	return(Return_Value);
}

//--------------------------------------------------------------------------//
// Function:	Execute_STOP												//
//																			//
// Access:		Private														//

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -