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)
{
}
}
.
