This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PZ: I2C slave mode

Part Number: TM4C123GH6PZ

HI,

                    I need to configure I2C slave mode in TM4c123GH6PZ controller.

Initially when i am transmitting data from slave board to master board it's working fine there is no any problem. Suppose if i reset only the master board power supply it giving problem. After resetting the power supply in master side, the data which is receiving in master side is interchanged. i mean (LSB and MSB data is interchanged).

I checked with debugger in slave board it showing correct data format only. when i connecting debugger in master board it showing the interchanged  data.

could you help any one about this issue?

Below i given the code. I may didn't included some variable declaration. sorry for the inconvenience


#include "fsi_smb.h"
#include "common_header.h"
#include "GPIO.h"

#define MAX_TX_BYTES			2 // Maximum Number of Bytes to be transmitted
#define Max_I2C_Tx_Size			2 // Maximum Number of Bytes to be transmitted

unsigned char Data_Tx_Buffer[6][MAX_TX_BYTES] = { '0' };
unsigned char Data_Rx_Buffer[MAX_TX_BYTES] = { '0' };

/// SMB related constants
#define SMB_BUFFER	32		// max SMB message size
#define SMB_TIMEOUT_LENGTH	    30		// ms - transaction timeout (any SMB transaction cannot be longer then this)
/// Size of SMB word
#define SMB_WORD				2		// bytes
#define SMB_BYTE                1
/// SMB channel flags
#define SMB_FLAG_PEC			( 1 << 0 )


#define SLAVE_ADDRESS   		0x0B

//Slave Board config

#define Bay1_CellA_I2C	1
#define Bay1_CellB_I2C	2
#define Bay2_CellA_I2C	3
#define Bay2_CellB_I2C	4

// I2C0 slave config

#define I2C0_SYSCTL_PERIPH_GPIOx			SYSCTL_PERIPH_GPIOB
#define I2C0_SYSCTL_PERIPH_I2Cx				SYSCTL_PERIPH_I2C0
#define I2C0_GPIO_PBx_I2CxSCL				GPIO_PB2_I2C0SCL						//	GPIO_PB2_I2C0SCL - Pin_map.h
#define I2C0_GPIO_PBx_I2CxSDA				GPIO_PB3_I2C0SDA						//	GPIO_PB3_I2C0SDA - Pin_map.h
#define I2C0_GPIO_PORTx_BASE				GPIO_PORTB_BASE
#define I2C0_SCL							GPIO_PIN_2
#define I2C0_DTA							GPIO_PIN_3
#define BASE_I2C0							I2C0_BASE
#define INT0_I2C							INT_I2C0

// I2C3 slave config

#define I2C3_SYSCTL_PERIPH_GPIOx			SYSCTL_PERIPH_GPIOG
#define I2C3_SYSCTL_PERIPH_I2Cx				SYSCTL_PERIPH_I2C3
#define I2C3_GPIO_PGx_I2CxSCL				GPIO_PG0_I2C3SCL						//	GPIO_PG0_I2C3SCL - Pin_map.h
#define I2C3_GPIO_PGx_I2CxSDA				GPIO_PG1_I2C3SDA						//	GPIO_PG1_I2C3SDA - Pin_map.h
#define I2C3_GPIO_PORTx_BASE				GPIO_PORTG_BASE
#define I2C3_SCL							GPIO_PIN_0
#define I2C3_DTA							GPIO_PIN_1
#define BASE_I2C3							I2C3_BASE
#define INT3_I2C							INT_I2C3

// I2C4 slave config

#define I2C4_SYSCTL_PERIPH_GPIOx			SYSCTL_PERIPH_GPIOG
#define I2C4_SYSCTL_PERIPH_I2Cx				SYSCTL_PERIPH_I2C4
#define I2C4_GPIO_PGx_I2CxSCL				GPIO_PG2_I2C4SCL						//	GPIO_PG2_I2C4SCL - Pin_map.h
#define I2C4_GPIO_PGx_I2CxSDA				GPIO_PG3_I2C4SDA						//	GPIO_PG3_I2C4SDA - Pin_map.h
#define I2C4_GPIO_PORTx_BASE				GPIO_PORTG_BASE
#define I2C4_SCL							GPIO_PIN_2
#define I2C4_DTA							GPIO_PIN_3
#define BASE_I2C4							I2C4_BASE
#define INT4_I2C							INT_I2C4

// I2C5 slave config

#define I2C5_SYSCTL_PERIPH_GPIOx			SYSCTL_PERIPH_GPIOG
#define I2C5_SYSCTL_PERIPH_I2Cx				SYSCTL_PERIPH_I2C5
#define I2C5_GPIO_PGx_I2CxSCL				GPIO_PG6_I2C5SCL						//	GPIO_PG6_I2C5SCL - Pin_map.h
#define I2C5_GPIO_PGx_I2CxSDA				GPIO_PG7_I2C5SDA						//	GPIO_PG7_I2C5SDA - Pin_map.h
#define I2C5_GPIO_PORTx_BASE				GPIO_PORTG_BASE
#define I2C5_SCL							GPIO_PIN_6
#define I2C5_DTA							GPIO_PIN_7
#define BASE_I2C5							I2C5_BASE
#define INT5_I2C							INT_I2C5


/// SMB channels
smbState smb[5];

unsigned char Data_Count_var = 0;
uint32 temp_data[5], LSB_data, MSB_data;

extern uint8 Bay1_Full, Bay1_Calib, Bay2_Full, Bay2_Calib;

/************************************************************************************************
 * I2C hardware initialization
 *    index - I2C channel index (I2C0 | OUTI2C)
 *    ownAddress - self SMB address
 *************************************************************************************************/
void initI2C(uint8 index ,uint8 ownAddress)
{
	if(index == Bay1_CellA_I2C) // I2C Zero channel			// Bay1 CellA
    {
        // SLAVE I2C0 INIT

        SysCtlPeripheralEnable(I2C0_SYSCTL_PERIPH_I2Cx);		//Enables a peripheral .
        SysCtlPeripheralEnable(I2C0_SYSCTL_PERIPH_GPIOx);		//Enables a peripheral.
    	GPIOPinConfigure(I2C0_GPIO_PBx_I2CxSCL);
    	GPIOPinConfigure(I2C0_GPIO_PBx_I2CxSDA);
        GPIOPinTypeI2CSCL(I2C0_GPIO_PORTx_BASE, I2C0_SCL);		// SCL
        GPIOPinTypeI2C(I2C0_GPIO_PORTx_BASE, I2C0_DTA);
        I2CSlaveInit(BASE_I2C0, ownAddress);					//Initializes the I2C Slave block
        I2CSlaveEnable(BASE_I2C0);								//Enables the I2C Slave block
        I2CSlaveIntEnable(BASE_I2C0);							//Enables the I2C Slave interrupt
        IntEnable(INT0_I2C);
    }
	else if(index == Bay1_CellB_I2C) // I2C Third channel		// Bay1 CellB
    {
        // SLAVE I2C3 INIT

        SysCtlPeripheralEnable(I2C3_SYSCTL_PERIPH_I2Cx);		//Enables a peripheral .
        SysCtlPeripheralEnable(I2C3_SYSCTL_PERIPH_GPIOx);		//Enables a peripheral.
    	GPIOPinConfigure(I2C3_GPIO_PGx_I2CxSCL);
    	GPIOPinConfigure(I2C3_GPIO_PGx_I2CxSDA);
        GPIOPinTypeI2CSCL(I2C3_GPIO_PORTx_BASE, I2C3_SCL);		// SCL
        GPIOPinTypeI2C(I2C3_GPIO_PORTx_BASE, I2C3_DTA);
        I2CSlaveInit(BASE_I2C3, ownAddress);					//Initializes the I2C Slave block
        I2CSlaveEnable(BASE_I2C3);								//Enables the I2C Slave block
        I2CSlaveIntEnable(BASE_I2C3);							//Enables the I2C Slave interrupt
        IntEnable(INT3_I2C);
    }
	else if(index == Bay2_CellA_I2C) // I2C Fourth channel		// Bay2 CellA
    {
        // SLAVE I2C4 INIT

        SysCtlPeripheralEnable(I2C4_SYSCTL_PERIPH_I2Cx);		//Enables a peripheral .
        SysCtlPeripheralEnable(I2C4_SYSCTL_PERIPH_GPIOx);		//Enables a peripheral.
    	GPIOPinConfigure(I2C4_GPIO_PGx_I2CxSCL);
    	GPIOPinConfigure(I2C4_GPIO_PGx_I2CxSDA);
        GPIOPinTypeI2CSCL(I2C4_GPIO_PORTx_BASE, I2C4_SCL);		// SCL
        GPIOPinTypeI2C(I2C4_GPIO_PORTx_BASE, I2C4_DTA);
        I2CSlaveInit(BASE_I2C4, ownAddress);					//Initializes the I2C Slave block
        I2CSlaveEnable(BASE_I2C4);								//Enables the I2C Slave block
        I2CSlaveIntEnable(BASE_I2C4);							//Enables the I2C Slave interrupt
        IntEnable(INT4_I2C);
    }
	else if(index == Bay2_CellB_I2C) // I2C Fifth channel		// Bay2 CellB
    {
        // SLAVE I2C5 INIT

        SysCtlPeripheralEnable(I2C5_SYSCTL_PERIPH_I2Cx);		//Enables a peripheral .
        SysCtlPeripheralEnable(I2C5_SYSCTL_PERIPH_GPIOx);		//Enables a peripheral.
    	GPIOPinConfigure(I2C5_GPIO_PGx_I2CxSCL);
    	GPIOPinConfigure(I2C5_GPIO_PGx_I2CxSDA);
        GPIOPinTypeI2CSCL(I2C5_GPIO_PORTx_BASE, I2C5_SCL);		// SCL
        GPIOPinTypeI2C(I2C5_GPIO_PORTx_BASE, I2C5_DTA);
        I2CSlaveInit(BASE_I2C5, ownAddress);					//Initializes the I2C Slave block
        I2CSlaveEnable(BASE_I2C5);								//Enables the I2C Slave block
        I2CSlaveIntEnable(BASE_I2C5);							//Enables the I2C Slave interrupt
        IntEnable(INT5_I2C);
    }

#endif
}

/************************************************************************************************
 * Returns corresponding SMBus base value
 *************************************************************************************************/
uint32 I2CBaseS(uint8 index)
{
	uint32 Slave_base = 0;
	switch(index)
	{
		case Bay1_CellA_I2C:
			Slave_base = BASE_I2C0;
			break;

		case Bay1_CellB_I2C:
			Slave_base = BASE_I2C3;
			break;

		case Bay2_CellA_I2C:
			Slave_base = BASE_I2C4;
			break;

		case Bay2_CellB_I2C:
			Slave_base = BASE_I2C5;
			break;
	}
	return Slave_base;
}

/************************************************************************************************
 * Returns corresponding SMBus cmd data to buffer
 *************************************************************************************************/
void smb_slave_tx_data(uint8 index, uint8 command)
{
	switch(command)
	{
		case SMB_SPECIFICATION_INFO:

			temp_data[index] = 0x0003;

			break;

		case SMB_CYCLE_COUNT:

			temp_data[index] = 0x0005;

			break;

		case SMB_MAX_ERROR:

			if(Bay1_Calib == ENABLE)
			{
				temp_data[Bay1_CellA_I2C] = 0x0A;
				temp_data[Bay1_CellB_I2C] = 0x0A;
			}
			else
			{
				temp_data[Bay1_CellA_I2C] = 0x02;
				temp_data[Bay1_CellB_I2C] = 0x02;
			}

			if(Bay2_Calib == ENABLE)
			{
				temp_data[Bay2_CellA_I2C] = 0x0A;
				temp_data[Bay2_CellB_I2C] = 0x0A;
			}
			else
			{
				temp_data[Bay2_CellA_I2C] = 0x02;
				temp_data[Bay2_CellB_I2C] = 0x02;
			}

			break;

		case SMB_BATTERY_MODE:

			temp_data[index] = 0x0002;

			break;

		case SMB_BATTERY_STATUS:

			if(Bay1_Full == ENABLE)
			{
				temp_data[Bay1_CellA_I2C] = 0x00A0;
				temp_data[Bay1_CellB_I2C] = 0x00A0;
			}
			else
			{
				temp_data[Bay1_CellA_I2C] = 0x0080;
				temp_data[Bay1_CellB_I2C] = 0x0080;
			}

			if(Bay2_Full == ENABLE)
			{
				temp_data[Bay2_CellA_I2C] = 0x00A0;
				temp_data[Bay2_CellB_I2C] = 0x00A0;
			}
			else
			{
				temp_data[Bay2_CellA_I2C] = 0x0080;
				temp_data[Bay2_CellB_I2C] = 0x0080;
			}

			break;

		case SMB_CHARGING_VOLTAGE:

			temp_data[index] = 0x41A0;				// 16800 mV

			break;

		case SMB_CHARGING_CURRENT:

			temp_data[index] = 0x0BB8;				// 3000 mA

			break;

		case SMB_VOLTAGE:

			temp_data[index] = 0x3A98;				// 15000 mV

			break;

		case SMB_CURRENT:

			temp_data[index] = 0x0B54;				// 2900 mA

			break;

		case SMB_AT_RATE_TIME_TO_FULL:

			temp_data[index] = 0x0050;

			break;

		case SMB_AT_RATE_TIME_TO_EMPTY:

			temp_data[index] = 0x0070;

			break;

		case SMB_RELATIVE_STATE_OF_CHARGE:

			temp_data[index] = 0x0041;

			break;

		case SMB_ABSOLUTE_STATE_OF_CHARGE:

			temp_data[index] = 0x003D;

			break;

		case SMB_TEMPERATURE:

			temp_data[index] = 0x0C1C;				// 31 * 100 deg cel

			break;
	}

	LSB_data = temp_data[index] & 0x00FF;
	MSB_data = temp_data[index] & 0xFF00;
	MSB_data = MSB_data >> 8;

	Data_Tx_Buffer[index][0] = MSB_data;
	Data_Tx_Buffer[index][1] = LSB_data;
}

/************************************************************************************************
 * Interrupt handler (index - SMB channel index)
 *************************************************************************************************/
void I2CHandler(uint8 index)
{
//    uint32 baseM = I2CBaseM (index);												// getting master register base
    uint32 baseS = I2CBaseS(index);													// getting slave register base
    uint8 status;
    uint8 data;
    
     /// SLAVE mode
	if(I2CSlaveIntStatus(baseS,true))												// I2CSlaveIntStatus() returns true => if I2C slave Interrupt status is active
	{
		// Clear the slave interrupt
		I2CSlaveIntClear(baseS);													// Clears I2C Slave interrupt sources.

		// Get status of the I2C Slave
		status = I2CSlaveStatus(baseS);												// Gets the current I2C Slave interrupt status.
		data = I2CSlaveDataGet(baseS);												// getting the data (This function reads a byte of data from the I2C Slave Data Register.)

		if(status == I2C_SLAVE_ACT_RREQ_FBR)										// Master has sent first byte
		{
			// handling that only if BUS is IDLE
			if(smb[index].state == SMB_IDLE)
			{
				smb[index].state = SMB_SLAVE;
				smb[index].index = 0;
				smb[index].pecCalculated = 0;
				smb[index].callback = smb[index].slaveCallback;						// if slave mode activated, setting a callback to be slaveCallback
				smb[index].count = SMB_WORD;										// we can only receive WORDs from a slave
				smb[index].cmd = I2CSlaveDataGet(baseS);							// first byte is a command

				if(smb[index].flags & SMB_FLAG_PEC)
				{
					smb[index].count += 1;
					CRC8_add((uint8 *) &smb[index].pecCalculated,smb[index].cmd);
				}
				timerRestart(smb[index].timeoutTimer);
			}
				// else
				// We are in the middle of something, need to drop it first
		}

		/// SLAVE Receiver
		else if(status == I2C_SLAVE_ACT_RREQ)										// Master has sent data
		{
			data = I2CSlaveDataGet(baseS);											// getting the data
			smb [index].count--;

			if(smb[index].count == 0)												// last byte received
			{
				if(smb [index].flags & SMB_FLAG_PEC)								// if PEC - last byte is a checksum
				smb [index].pecReceived = data;
				smb [index].state = SMB_DONE;										// we are done, need to handle the data
			}

			// adding byte to a buffer if it isn't last or if no PEC enabled
			if((smb[index].count > 0) || (!(smb[index].flags & SMB_FLAG_PEC)))
			{
				smb[index].que[smb[index].index++] = data;
				if(smb[index].flags & SMB_FLAG_PEC)
				CRC8_add((uint8 *) &smb [index].pecCalculated,data);
			}
		}

		/// SLAVE Transmitter
		if(status == I2C_SLAVE_ACT_TREQ)											// Master has requested data(TREQ bit is set)
	    {
			smb_slave_tx_data(index, smb[index].cmd);

	        if(Data_Count_var < Max_I2C_Tx_Size)									// Max_I2C_Tx_Size is the Maximum number of Bytes to be Sent
	        {
	            I2CSlaveDataPut(baseS, Data_Tx_Buffer[index][Data_Count_var]);		// Transmits one BYTE
	            Data_Count_var++;													// Increments for the next Byte

	            // Check if Tx is complete
	            if (Data_Count_var == Max_I2C_Tx_Size)								// Reset the Flags and other Variables
	            {
	                Data_Count_var = 0;
	                smb[index].state = SMB_IDLE;
	            }
	        }
	    }
	}
}

/************************************************************************************************
 * Real I2C interrupt handlers
 *************************************************************************************************/

// Slave Board I2C Interrupt

void I2C0IntHandler(void)	// Bay1 CellA Interrupt
{
    I2CHandler(Bay1_CellA_I2C);
}

void I2C3IntHandler(void)	// Bay1 CellB Interrupt
{
    I2CHandler(Bay1_CellB_I2C);
}

void I2C4IntHandler(void)	// Bay2 CellA Interrupt
{
    I2CHandler(Bay2_CellA_I2C);
}

void I2C5IntHandler(void)	// Bay2 CellB Interrupt
{
    I2CHandler(Bay2_CellB_I2C);
}

/*
 * main.c
 */
int main(void)
{
	SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |SYSCTL_XTAL_8MHZ);

	initI2C(Bay1_CellA_I2C, SLAVE_ADDRESS);		// Bay1 CellA
	initI2C(Bay1_CellB_I2C, SLAVE_ADDRESS);		// Bay1 CellB
	initI2C(Bay2_CellA_I2C, SLAVE_ADDRESS);		// Bay2 CellA
	initI2C(Bay2_CellB_I2C, SLAVE_ADDRESS);		// Bay2 CellB

    while(1)
    {

    }
}




 

  • Hello Yuvaraj

    Did you check the I2C Bus on a scope or LA to see what is happening. Also did you check with a debugger when a power supply reset is done on the master, how does the slave respond to the change?
  • Hi Amit,

    Thanks for your valuable reply. I checked I2C bus on scope. In that i seeing difference only in reading data from slave board. Below i attached one image for your reference of I2C bus checked in scope.

  • Hello Yuvaraj

    When the master is reset due to a power cycle, does the slave side is made aware of it? What I am thinking is that the slave still responds as per the older state of the transaction. As an experiment, connect a GPIO from the master to the slave device. The GPIO on master side is used to reset the slave device. Once the master is power cycled, it causes the slave to be reset. Then does the slave respond with correct data or incorrect data.

    Also what I noticed is that the low state is above the GND level. This suggest a very strong pull up is being used. I would ask you to correct the same as well.
  • Hi Amit,

    Sorry for the late reply. Its my blunder mistake. Now its working fine.

    Both (Master and slave) side i enabled PEC and also i counted one byte data extra for transmitting PEC in slave side, but i forget to transmit the PEC data. Due to that mistake, my LSB and MSB data is interchanged. Thanks for your valuable reply.

  • Hello Yuvaraj

    Glad that you were able to solve the issue.