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.

Tiva SDA held low

Other Parts Discussed in Thread: TM4C1233H6PZ

Hi,

I'm working with a TM4C1233H6PZ on a board that I developed. I'm seeing an issue where I2C0SDA line on PB3 is held low after reset/power up. 

I do have 1.62k pull ups to 3.3VDC on both the SDA and SCL lines. 

I have found that it requires ~60mA at 3.3VDC to pull the SDA line high. If I write to the I2C bus while I have it pulled hard high, it fails arbitration, but the ~60mA drain disappears and I can remove the hard pull up. After this point the bus works properly until the Tiva is reset.  

The following is my configuration code and my writing code. This code works properly with the four other I2C busses I am using on the chip.

			if (!ROM_SysCtlPeripheralReady (SYSCTL_PERIPH_GPIOB))
			{
				DEBUG_PRINT2("GPIO B peripheral not enabled...\n");
				SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOB);
				while (!SysCtlPeripheralReady (SYSCTL_PERIPH_GPIOB)) {
					DEBUG_PRINT2("Waiting\n");
				}
			}
			DEBUG_PRINT2("Enabling I2C Bus 0...\n");

			ROM_GPIOPinTypeI2C (GPIO_PORTB_BASE, GPIO_PIN_3);
			GPIOPinTypeI2CSCL (GPIO_PORTB_BASE, GPIO_PIN_2);
			GPIOPinConfigure (GPIO_PB2_I2C0SCL);
			GPIOPinConfigure (GPIO_PB3_I2C0SDA);
			SysCtlPeripheralEnable (SYSCTL_PERIPH_I2C0);
			I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), true);
			I2CMasterEnable(I2C0_BASE);
			break;

void i2cWrite(uint32_t busNumber)
{
	uint32_t I2CBaseValue = 0;
	char i2cBusString[0];
	uint32_t count = 0;

	switch (busNumber)
	{
		case 0:
		{
			I2CBaseValue = I2C0_BASE;
			strcpy(i2cBusString, "0");

			break;
		}
		case 1:
		{
			I2CBaseValue = I2C1_BASE;
			strcpy(i2cBusString, "1");

			break;
		}
		case 2:
		{
			I2CBaseValue = I2C2_BASE;
			strcpy(i2cBusString, "2");

			break;
		}
		case 3:
		{
			I2CBaseValue = I2C3_BASE;
			strcpy(i2cBusString, "3");

			break;
		}
		case 4:
		{
			//Bus Not Used.
			return;
		}
		case 5:
		{
			I2CBaseValue = I2C5_BASE;
			strcpy(i2cBusString, "5");

			break;
		}
	}


	count = 0;
	UARTprintf("I2C Port ");
	UARTprintf(i2cBusString);
	UARTprintf("\n");

	ROM_I2CMasterSlaveAddrSet(I2CBaseValue, strtol(inputCommand.address, NULL, 16), false);
	ROM_I2CMasterDataPut(I2CBaseValue, inputCommand.data[count]);

	if(dataSize > 1)
	{
		DEBUG_PRINT4("DATASIZE BURST %d\n", dataSize);
		ROM_I2CMasterControl(I2CBaseValue, I2C_MASTER_CMD_BURST_SEND_START);
		count++;
		while(count < dataSize)
		{
			while(ROM_I2CMasterBusy(I2CBaseValue))
			{
			DEBUG_PRINT4("I2C3 Master Busy\n");
			}
			DEBUG_PRINT3("Current Data Byte: %u\n", count);
			ROM_I2CMasterDataPut(I2CBaseValue, inputCommand.data[count]);
			ROM_I2CMasterControl(I2CBaseValue, I2C_MASTER_CMD_BURST_SEND_CONT);
			count++;
		}

		ROM_I2CMasterControl(I2CBaseValue, I2C_MASTER_CMD_BURST_SEND_STOP);
	}
	else
	{
		if(strcmp(inputCommand.type, "I2CS") == 0)
		{
			ROM_I2CMasterControl(I2CBaseValue, I2C_MASTER_CMD_BURST_SEND_START);
		}
		else
		{
			ROM_I2CMasterControl(I2CBaseValue, I2C_MASTER_CMD_SINGLE_SEND);
		}
	}

	switch (I2CMasterErr(I2CBaseValue))
	{
		case I2C_MASTER_ERR_NONE:
		{
			UARTprintf("No I2C Error\n");
			break;
		}
		case I2C_MASTER_ERR_ADDR_ACK:
		{
			UARTprintf("I2C Address Ack Error\n");
			break;
		}
		case I2C_MASTER_ERR_DATA_ACK:
		{
			UARTprintf("I2C Data Ack Error\n");
			break;
		}
		case I2C_MASTER_ERR_ARB_LOST:
		{
			UARTprintf("I2C Arbitration Lost\n");
			break;
		}
	}
	return;
}

Any suggestions or recommendations will be gladly accepted.

Thanks,

Jed

  • Apparently I posted too soon. I found this recommendation by Dave Wilson in regards to bus hangs.

    "I've found that the slave peripheral can sometimes be stuck in a state where it holds SDA low because it is waiting for more clocks. After it's reset and you try to initiate a new transaction from the master, it detects that SDA is low and takes this to mean that some other master owns the bus. As a result, you end up in a stalemate where the slave is waiting for clocks and the master is thinking it can't generate the clock because it doesn't own the bus. 

    To avoid this, during I2C peripheral configuration, I would sample the state of the SDA line (configured as a GPIO at this point) and, if it's low, wiggle the SCL line (also configured as a GPIO) a few times until the SDA line goes high again indicating that the peripheral has released it. This has cured I2C bus hangs that reported as arbitration lost errors for me in the past."

    I manually pulled the SCL line low then released it and it solved the SDA being driven low problem. 

    To fix the problem I added the following lines of code to my init script.

    			ROM_GPIOPinTypeGPIOOutput (GPIO_PORTB_BASE, GPIO_PIN_2);
    			ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0);
    			SysCtlDelay(50);
    			ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2);

    Jed