Other Parts Discussed in Thread: PCF8575
Hi,
I am using F28069 Micro controller for my application.I am interfacing 3 slave i.e. PCF8575 I am getting the problem while doing continue read and write operation.I am able to do individual Read and write operation.Please find attached source and header file of i2c. I am using 4.7 K Pull up resister for SDA and SCL.
While debugging I found that it is stuck at following instruction.
// Check if bus busy
if (I2caRegs.I2CSTR.bit.BB == 1)
{
return (I2C_BUS_BUSY_ERROR);
}
Waiting for reply.
#include"I2C.h"
// Prototype statements for functions found within this file.
// Note: I2C Macros used in this example can be found in the
// F2806x_I2C_defines.h file
// Prototype statements for functions found within this file.
Uint8 volatile write_done = 0;
Uint8 volatile read_done = 0;
void I2CA_Init(void);
Uint16 I2CA_WriteData(struct I2CMSG *msg);
Uint16 I2CA_ReadData(struct I2CMSG *msg);
interrupt void i2c_int1a_isr(void);
void Read_Data(Uint8 dido_id);
void Write_Data(Uint8 dido_id);
struct I2CMSG I2cMsgOut1[8]={
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO1_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO2_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO3_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO4_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO5_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO6_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO7_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
{ I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_DIDO8_ADDR,
I2C_W_NUMBYTES,
I2C_EEPROM_HIGH_ADDR1,
I2C_EEPROM_LOW_ADDR1
},
};// Msg Byte 1
struct I2CMSG I2cMsgIn1[8]={
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO1_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO2_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO3_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO4_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO5_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO6_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO7_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
{ I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_DIDO8_ADDR,
I2C_R_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR
},
};// Msg Byte 1
struct I2CMSG *CurrentMsgPtr; // Used in interrupts
Uint16 Error;
void I2CA_Init(void)
{
// Initialize I2C
I2caRegs.I2CSAR = I2C_SLAVE_DIDO1_ADDR; // Slave address - EEPROM control code
I2caRegs.I2CPSC.all = 6; // Prescaler - need 7-12 Mhz on module clk
// I2caRegs.I2CCLKL = 10; // NOTE: must be non zero //400k
// I2caRegs.I2CCLKH = 5; // NOTE: must be non zero
I2caRegs.I2CCLKL = 75; // NOTE: must be non zero //100k
I2caRegs.I2CCLKH = 30; // NOTE: must be non zero
I2caRegs.I2CIER.all = 0x24; // Enable SCD & ARDY interrupts
I2caRegs.I2CMDR.all = 0x0020; // Take I2C out of reset
// Stop I2C when suspended
I2caRegs.I2CFFTX.all = 0x6000; // Enable FIFO mode and TXFIFO
I2caRegs.I2CFFRX.all = 0x2040; // Enable RXFIFO, clear RXFFINT,
}
void Write_Data(Uint8 dido_id)
{
// Check the outgoing message to see if it should be sent.
// In this example it is initialized to send with a stop bit.
if(I2cMsgOut1[dido_id].MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
{
Error = I2CA_WriteData(&I2cMsgOut1[dido_id]);
// If communication is correctly initiated, set msg status to busy
// and update CurrentMsgPtr for the interrupt service routine.
// Otherwise, do nothing and try again next loop. Once message is
// initiated, the I2C interrupts will handle the rest. Search for
// i2c_int1a_isr in this file.
if (Error == I2C_SUCCESS)
{
CurrentMsgPtr = &I2cMsgOut1[dido_id];
I2cMsgOut1[dido_id].MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
}
else
{
I2cMsgOut1[dido_id].MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
}
}
}// end of write section
void Read_Data(Uint8 dido_id)
{
if(I2cMsgIn1[dido_id].MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
{
// EEPROM address setup portion
while(I2CA_ReadData(&I2cMsgIn1[dido_id]) != I2C_SUCCESS)
{
// Maybe setup an attempt counter to break an infinite while
// loop. The EEPROM will send back a NACK while it is performing
// a write operation. Even though the write communique is
// complete at this point, the EEPROM could still be busy
// programming the data. Therefore, multiple attempts are
// necessary.
}
// Update current message pointer and message status
CurrentMsgPtr = &I2cMsgIn1[dido_id];
I2cMsgIn1[dido_id].MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY;
}
// Once message has progressed past setting up the internal address
// of the EEPROM, send a restart to read the data bytes from the
// EEPROM. Complete the communique with a stop bit. MsgStatus is
// updated in the interrupt service routine.
else if(I2cMsgIn1[dido_id].MsgStatus == I2C_MSGSTAT_RESTART)
{
// Read data portion
while(I2CA_ReadData(&I2cMsgIn1[dido_id]) != I2C_SUCCESS)
{
// Maybe setup an attempt counter to break an infinite while
// loop.
}
// Update current message pointer and message status
CurrentMsgPtr = &I2cMsgIn1[dido_id];
I2cMsgIn1[dido_id].MsgStatus = I2C_MSGSTAT_READ_BUSY;
}
else if(I2cMsgIn1[dido_id].MsgStatus == I2C_MSGSTAT_INACTIVE)
{
read_done = 1;
if(write_read == 0) //For Read Operation
{
I2cMsgIn1[i2c1_io_di_id].MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
}
switch(dido_id)
{
case DI_0 :
di_0.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_1 :
di_1.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_2 :
di_2.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_3 :
di_3.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_4 :
di_4.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_5 :
di_5.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_6 :
di_6.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
case DI_7 :
di_7.all = ( ModbusData[DI_READ_LOW] | (ModbusData[DI_READ_HIGH] << 8));
break;
default :
break;
}
}
}// end of read section
Uint16 I2CA_WriteData(struct I2CMSG *msg)
{
Uint16 i;
// Wait until the STP bit is cleared from any previous master communication.
// Clearing of this bit by the module is delayed until after the SCD bit is
// set. If this bit is not checked prior to initiating a new message, the
// I2C could get confused.
if (I2caRegs.I2CMDR.bit.STP == 1)
{
return (I2C_STP_NOT_READY_ERROR);
}
// Setup slave address
I2caRegs.I2CSAR = msg->SlaveAddress;
// Check if bus busy
if (I2caRegs.I2CSTR.bit.BB == 1)
{
return (I2C_BUS_BUSY_ERROR);
}
I2caRegs.I2CCNT = msg->NumOfBytes;
/*
I2caRegs.I2CCNT = msg->NumOfBytes+2;
// Setup data to send
I2caRegs.I2CDXR = msg->MemoryHighAddr;
I2caRegs.I2CDXR = msg->MemoryLowAddr;
*/
// for (i=0; i<msg->NumOfBytes-2; i++)
for (i=0; i<msg->NumOfBytes; i++)
{
I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
}
// Send start as master transmitter
I2caRegs.I2CMDR.all = 0x6E20;
return I2C_SUCCESS;
}
Uint16 I2CA_ReadData(struct I2CMSG *msg)
{
// Wait until the STP bit is cleared from any previous master communication.
// Clearing of this bit by the module is delayed until after the SCD bit is
// set. If this bit is not checked prior to initiating a new message, the
// I2C could get confused.
if (I2caRegs.I2CMDR.bit.STP == 1)
{
return I2C_STP_NOT_READY_ERROR;
}
I2caRegs.I2CSAR = msg->SlaveAddress;
if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)
{
// Check if bus busy
if (I2caRegs.I2CSTR.bit.BB == 1)
{
return I2C_BUS_BUSY_ERROR;
}
I2caRegs.I2CCNT = 2;
I2caRegs.I2CDXR = msg->MemoryHighAddr;
I2caRegs.I2CDXR = msg->MemoryLowAddr;
I2caRegs.I2CMDR.all = 0x2620; // Send data to setup EEPROM address
}
else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)
{
I2caRegs.I2CCNT = msg->NumOfBytes; // Setup how many bytes to expect
I2caRegs.I2CMDR.all = 0x2C20; // Send restart as master receiver
}
return I2C_SUCCESS;
}
interrupt void i2c_int1a_isr(void) // I2C-A
{
Uint16 IntSource, i;
// Read interrupt source
IntSource = I2caRegs.I2CISRC.all;
// Interrupt source = stop condition detected
if(IntSource == I2C_SCD_ISRC)
{
// If completed message was writing data, reset msg to inactive state
if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
if(read_flag == 1)
{
write_read = 0; //Start Read Opeartion
read_done = 0;
}
write_done = 1;
}
else
{
// If a message receives a NACK during the address setup portion of the
// EEPROM read, the code further below included in the register access ready
// interrupt source code will generate a stop condition. After the stop
// condition is received (here), set the message status to try again.
// User may want to limit the number of retries before generating an error.
if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
}
// If completed message was reading EEPROM data, reset msg to inactive state
// and read data from FIFO.
else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
ModbusData[92]++;
for(i=0; i < I2C_R_NUMBYTES; i++)
{
CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
ModbusData[DI_READ_LOW+i] = I2caRegs.I2CDRR;
}
}
}
} // end of stop condition detected
// Interrupt source = Register Access Ready
// This interrupt is used to determine when the EEPROM address setup portion of the
// read data communication is complete. Since no stop bit is commanded, this flag
// tells us when the message has been sent instead of the SCD flag. If a NACK is
// received, clear the NACK bit and command a stop. Otherwise, move on to the read
// data portion of the communication.
else if(IntSource == I2C_ARDY_ISRC)
{
if(I2caRegs.I2CSTR.bit.NACK == 1)
{
I2caRegs.I2CMDR.bit.STP = 1;
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
}
else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
}
} // end of register access ready
else
{
// Generate some error due to invalid interrupt source
asm(" ESTOP0");
}
// Enable future I2C (PIE Group 8) interrupts
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}
//===========================================================================
// No more.
//===========================================================================
{
for(;;)
{
switch(write_read)
{
case WRITE :
// write_done = 0;
if(read_done == 1)
{
Write_Data(i2c1_io_do_id);
}
break;
case READ :
if(write_done == 1)
{
ModbusData[94]++;
Read_Data(i2c1_io_di_id);
}
break;
default :
break;
}
} // end of for(;;)
} // end of main
//===========================================================================
// No more.
//===========================================================================
I2cMsgOut1[DO_1].MsgBuffer[0] = ( data & 0x00FF);
I2cMsgOut1[DO_1].MsgBuffer[1] = ( data >> 8);
i2c1_io_do_id = DO_1;
if(I2cMsgOut1[DO_1].MsgStatus == I2C_MSGSTAT_INACTIVE)
{
I2cMsgOut1[DO_1].MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
}
I2cMsgIn1[i2c1_io_di_id].MsgStatus = I2C_MSGSTAT_INACTIVE;
write_read = 1;
write_done = 0;
read_flag = 0;