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.

I2C non-interrupt problem

Hi Folks,


I'm trying to figure out how to use the I2C module in the 27F chip and I think I almost have it working but I'm having a problem.  If I just write one byte to the external eeprom it will work just as advertised. But if I wrap a For () loop around it it won't work.. It gets hung up waiting for the Stop condition.

I've based my code on this post from 5 years ago: e2e.ti.com/.../416428


It works fine if I just do this:

i2cStatus = i2cWriteByte(halHandle->i2cHandle, addr, data);
   
eepromReadData = i2cReadByte(halHandle->i2cHandle, addr);

It only will work if I set a breakpoint and only execute a Write OR a Read.  If I let it run at speed it will hang.

Here's my write function:

char i2cWriteByte(I2C_Handle i2cHandle, uint_least8_t addr, char data)
{
	I2C_Obj *i2c = (I2C_Obj *)i2cHandle;

//	i2c->I2CMDR &= I2C_I2CMDR_IRS_BIT;			// reset I2C

	// Make sure I2C is not busy and has stopped
	while (i2c->I2CSTR & I2C_I2CSTR_BB_BITS);	// Check for Bus Busy

	i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS;			// Clear the SCD bit (stop condition bit)

	while(i2c->I2CMDR &= I2C_I2CMDR_STP_BIT);	// stop bit loop

	i2c->I2CSAR = 0x50;							// I2C slave address

	while (i2c->I2CSTR & I2C_I2CSTR_BB_BITS);	// still busy?

    i2c->I2CCNT = 2;							// assume register address = 1 byte, and data is 1 byte

	i2c->I2CMDR = 0x6E20;	 					// start, stop, no rm, reset i2c  01101110 00100000
//	I2caRegs.I2CMDR.bit.NACKMOD = 0;			// NACK mode bit
//	I2caRegs.I2CMDR.bit.FREE = 1;				// Run free I2C when suspended
//	I2caRegs.I2CMDR.bit.STT = 1;				// START condition bit
//												// bit 12 reserved don't care
//	I2caRegs.I2CMDR.bit.STP = 1;				// STOP condition bit
//	I2caRegs.I2CMDR.bit.MST = 1;				// Master mode
//	I2caRegs.I2CMDR.bit.TRX = 1;				// Transmitter mode
//	I2caRegs.I2CMDR.bit.XA = 0;					// 7-bit addressing mode
//	I2caRegs.I2CMDR.bit.RM = 0;					// Nonrepeat mode
//	I2caRegs.I2CMDR.bit.DLB = 0;				// Digital loopback mode is disabled
//	I2caRegs.I2CMDR.bit.IRS = 1;				// The I2C module is enabled
//	I2caRegs.I2CMDR.bit.STB = 0;				// The I2C module is not in the START byte mode
//	I2caRegs.I2CMDR.bit.FDF = 0;				// Free data format mode is disabled
//	I2caRegs.I2CMDR.bit.BC = 000;				// 8 bits per data byte

	i2c->I2CDXR = addr;							// data to be sent (1 byte)

	while ( !(i2c->I2CSTR & (I2C_I2CSTR_XRDY_BITS|I2C_I2CSTR_ARDY_BITS)) );
    i2c->I2CDXR = data;							// data to be sent (1 byte)

	i2c->I2CMDR |= I2C_I2CMDR_STP_BIT;			// stop bit when CNT=0

    while(!(i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS));// wait for STOP condition

	return I2C_SUCCESS;
}

Here's the Read function:

char i2cReadByte(I2C_Handle i2cHandle, uint_least8_t addr)
{
	I2C_Obj *i2c = (I2C_Obj *)i2cHandle;
	uint16_t tempdata;
	uint_least16_t i2cReadStatus;

	i2c->I2CMDR &= I2C_I2CMDR_IRS_BIT;

	// Make sure I2C is not busy and has stopped
	while (i2c->I2CSTR & I2C_I2CSTR_BB_BITS);	// Check for Bus Busy

	i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS;			// Clear the SCD bit (stop condition bit)

	while(i2c->I2CMDR &= I2C_I2CMDR_STP_BIT);	// stop bit loop

	i2c->I2CSAR = 0x50;							// I2C slave address

	while (i2c->I2CSTR & I2C_I2CSTR_BB_BITS);	// still busy?

	i2c->I2CMDR = 0x6620;			// start, no stop bit, master, tx, reset I2C 01100110

//	I2caRegs.I2CMDR.bit.NACKMOD = 0;			// bit 15 NACK mode bit
//	I2caRegs.I2CMDR.bit.FREE = 1;				// bit 14 Stop I2C when suspended
//	I2caRegs.I2CMDR.bit.STT = 1;				// bit 13 START condition bit
// 												// bit 12 reserved = don't care
//	I2caRegs.I2CMDR.bit.STP = 0;				// bit 11 STOP condition bit
//	I2caRegs.I2CMDR.bit.MST = 1;				// bit 10 Master mode
//	I2caRegs.I2CMDR.bit.TRX = 1;				// bit 9 Transmitter mode
//	I2caRegs.I2CMDR.bit.XA = 0;					// bit 8 7-bit addressing mode
//	I2caRegs.I2CMDR.bit.RM = 0;					// bit 7 Nonrepeat mode
//	I2caRegs.I2CMDR.bit.DLB = 0;				// bit 6 Digital loopback mode is disabled
//	I2caRegs.I2CMDR.bit.IRS = 1;				// bit 5 The I2C module is enabled
//	I2caRegs.I2CMDR.bit.STB = 0;				// bit 4 The I2C module is not in the START byte mode
//	I2caRegs.I2CMDR.bit.FDF = 0;				// bit 3 Free data format mode is disabled
//	I2caRegs.I2CMDR.bit.BC = 000;				// bit2 2-0 8 bits per data byte

	i2c->I2CCNT = 1;							// assume register address is one byte
	i2c->I2CDXR = addr;							// address of the data byte

	while(!(i2c->I2CSTR &= I2C_I2CSTR_ARDY_BITS));	// all ready?

	i2c->I2CMDR = 0x6C20;						// start, stop bit when CNT =0, master, rx, reset I2C 00101100

//	I2caRegs.I2CMDR.bit.NACKMOD = 0;			// NACK mode bit
//	I2caRegs.I2CMDR.bit.FREE = 1;				// Stop I2C when suspended
//	I2caRegs.I2CMDR.bit.STT = 1;				// START condition bit
// 												// bit 12 reserved = don't care
//	I2caRegs.I2CMDR.bit.STP = 1;				// STOP condition bit
//	I2caRegs.I2CMDR.bit.MST = 1;				// Master mode
//	I2caRegs.I2CMDR.bit.TRX = 0;				// Receiver mode
//	I2caRegs.I2CMDR.bit.XA = 0;					// 7-bit addressing mode
//	I2caRegs.I2CMDR.bit.RM = 0;					// Nonrepeat mode
//	I2caRegs.I2CMDR.bit.DLB = 0;				// Digital loopback mode is disabled
//	I2caRegs.I2CMDR.bit.IRS = 1;				// The I2C module is enabled
//	I2caRegs.I2CMDR.bit.STB = 0;				// The I2C module is not in the START byte mode
//	I2caRegs.I2CMDR.bit.FDF = 0;				// Free data format mode is disabled
//	I2caRegs.I2CMDR.bit.BC = 000;				// 8 bits per data byte

	i2c->I2CCNT = 1;							// only read one byte data
	if (i2c->I2CSTR & I2C_I2CSTR_NACK_BITS)	// If a NACK occurred then SCL is held low and STP bit cleared
	{
		i2c->I2CMDR = 0; 						// reset I2C so SCL isn't held low
		return i2cReadStatus = I2C_Status_NACK;
	}

	i2c->I2CMDR |= I2C_I2CMDR_STP_BIT;			// stop bit when CNT=0

	while(!(i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS));// stop bit detected?

	tempdata = i2c->I2CDRR;						// read one byte data

	return(tempdata);
}

Have I missed something that waits until something happens?  It will hang at the while(!(i2c->I2CSTR &=I2C_I2cSTR_SCD_BITS)); line #68.

Any help will be greatly appreciated.

Thanks,

Richard

  • Richard,

    You also need to wait for I2CMDR.STP to go low before starting a new message. Please try that and let me know if it works.

    Thanks,
  • Hi Adam,

    I thought I was doing that with this line:
    while(!(i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS)); // stop bit detected?

    This is in line 43 in the top code and line 68 in the bottom one.
    Is this not doing what you suggest?

    Thanks,

    Richard
  • You have to wait for both I2CSTR.SCD to go high and I2CMDR.STP to go low. It's something to do with the timing in the I2C state machine; I don't know the details. :-) This should be mentioned in the documentation for the STP bit.
  • Hi Adam,

    I was under the impression that the I2CMDR register just sets the I2C module up for different modes. So after I check for the SCD bit going high with while(!(i2c->I2CSTR &= I2C_I2CSTR_SCD_BITS)); // stop bit detected?

    would I test for the Stop bit going low with this:

    While (i2c->I2CMDR &= I2C_I2CMDR_STP_BIT); ?

    Thanks,

    Richard Cooke
  • I2CMDR is used to trigger the start and stop conditions. It's not just mode setup. The STT, STP, MST, and TRX bits are automatically cleared at various points in the I2C transfer.

    You don't need to try to clear STP. (I'm not sure what happens if you do.) You can monitor it like this:

    while (i2c->I2CMDR & I2C_I2CMDR_STP_BIT);