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.

EK-TM4C1294XL I2C Stuck In Master Busy Loop

I'm having problem with I2C being stuck at the Master Busy loop. What's even weirder is that when I step through the code in the debugger, everything works perfectly. Note that this only works if I step through the function without stepping inside the function where it's executing the I2C commands. If I try to step into the function, it will get stuck at the Master Busy loop.

Here is my initialization code:

	//
	// Enable the peripherals to be used.
	//
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);

	//
	// Waits for peripherals to be ready.
	//
	while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0) &&
			!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB) &&
			!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOK));

    //
    // Select I2C function for PB2 and PB3
    //
    MAP_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    MAP_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);

	//
	// Configure PB2 and PB3 for I2C
	//
    MAP_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    MAP_GPIOPinConfigure(GPIO_PB3_I2C0SDA);

	//
	// Configure and enable master.
	//
	MAP_I2CMasterInitExpClk(I2C0_BASE, g_ui32SysClock, false);

	//
	// Configure pin PK0 as output.
	//
	MAP_GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_0);

Here's the function that it's getting stuck in:

	//
	// Set slave address.
	//
	MAP_I2CMasterSlaveAddrSet(I2C0_BASE, 0x30, false);

	//
	// Place data to be send into FIFO.
	//
	MAP_I2CMasterDataPut(I2C0_BASE, command);

	//
	// Set burst length.
	//
	MAP_I2CMasterBurstLengthSet(I2C0_BASE, 2);

	//
	// Initiate master burst send.
	//
	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);

	//
	// Wait for master to finish transaction.
	//
	while (!MAP_I2CMasterBusy(I2C0_BASE));
	while (MAP_I2CMasterBusy(I2C0_BASE));

	//
	// Place data to be send into FIFO.
	//
	MAP_I2CMasterDataPut(I2C0_BASE, value);

	//
	// End master burst send.
	//
	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

	//
	// Wait for master to finish transaction.
	//
	while (!MAP_I2CMasterBusy(I2C0_BASE)); // This one here
	while (MAP_I2CMasterBusy(I2C0_BASE));

The program get stuck specifically at the second "while (!MAP_I2CMasterBusy(I2C0_BASE));", which means it was able to get past the first one.

I do have two 4.7k pull-up resistors for the SCL and SDA line. 

Again, it only get stuck when I run the program, or when I try to step through the line "while (!MAP_I2CMasterBusy(I2C0_BASE));". If I step through the entire function completely without going inside, then it works as intended.

  • Hello Thomas,

    Instead of using while (!MAP_I2CMasterBusy(I2C0_BASE)); try using a delay loop of 100.
  • Hi Amit,

    Is that a loop of 100 counts or a delay of 100 ms?

    Thomas
  • Hello Thomas

    I meant a SysCtlDelay(100);
  • Hi Amit,

    That didn't work. What worked somewhat for me is providing a ~100 ms delay instead.

    I want to provide some extra information, which is that what I'm trying to communicate with is a 16x2 LCD.  I'm currently trying to turn on the backlight, but for some reason it doesn't work in a logical way. This is my code right now: (Note: this is with the delay of about 100 ms in place of the "while (!MAP_I2CMasterBusy(I2C0_BASE))")

    	initDisplay(g_ui32SysClock);
    	lcdSetBacklight(g_ui32SysClock, BACKLIGHT_ON);
    
    	while (1)
    	{
    		lcdClearScreen(g_ui32SysClock);
    		char str[] = "Hello World!";
    		uint8_t str_len = strlen(str);
    		uint8_t str_i = 0;
    		for (; str_i < str_len; ++str_i)
    		{
    			lcdWriteChar(g_ui32SysClock, str_i, 0, str[str_i]);
    		}
        }

    Doing it this way, the backlight doesn't turn on, but it does prints "ello World!" on the first loop, and then the entire "Hello World!" for the rest of the program.

    However, doing it the following way instead allowed the LCD to print the entire string "Hello World!" on the first loop.

    	initDisplay(g_ui32SysClock);
    	lcdSetBacklight(g_ui32SysClock, BACKLIGHT_OFF);
    	lcdSetBacklight(g_ui32SysClock, BACKLIGHT_ON);
    
    	while (1)
    	{
    		lcdClearScreen(g_ui32SysClock);
    		char str[] = "Hello World!";
    		uint8_t str_len = strlen(str);
    		uint8_t str_i = 0;
    		for (; str_i < str_len; ++str_i)
    		{
    			lcdWriteChar(g_ui32SysClock, str_i, 0, str[str_i]);
    		}
        }

    As you can guess, the backlight still doesn't turn on. If I want the backlight to turn on, I'd have to do it like this:

    	initDisplay(g_ui32SysClock);
    
    	while (1)
    	{
    		lcdSetBacklight(g_ui32SysClock, BACKLIGHT_ON);
    		delayMs(g_ui32SysClock, 2000);
    		lcdSetBacklight(g_ui32SysClock, BACKLIGHT_OFF);
    		delayMs(g_ui32SysClock, 2000);
        }

    Although even with this way, the backlight doesn't turn on until several loops later.

    As in the OP, all of these work perfectly the first time if I am stepping through the code line by line.

    Below are the functions that are calling the I2C commands to provide extra information on how I'm doing so:

    //*****************************************************************************
    //
    // Clear screen.
    //
    //*****************************************************************************
    inline void lcdClearScreen(uint32_t g_ui32SysClock)
    {
    	lcdWrite(g_ui32SysClock, 0x60);
    }
    
    //*****************************************************************************
    //
    // Write one character at given x and y position.
    //
    //*****************************************************************************
    inline void lcdWriteChar(uint32_t g_ui32SysClock, uint8_t x_pos, uint8_t y_pos,
    		uint8_t c)
    {
    	lcdBurst4Write(g_ui32SysClock, 0x61, y_pos, x_pos, c);
    }
    
    //*****************************************************************************
    //
    // Control backlight.
    //
    //*****************************************************************************
    inline void lcdSetBacklight(uint32_t g_ui32SysClock, uint8_t value)
    {
    	lcdBurst2Write(g_ui32SysClock, 0x62, value);
    }
    
    //*****************************************************************************
    //
    // Send a command to LCD.
    //
    //*****************************************************************************
    void lcdWrite(uint32_t g_ui32SysClock, uint8_t command)
    {
    	//
    	// Set slave address.
    	//
    	MAP_I2CMasterSlaveAddrSet(I2C0_BASE, 0x30, false);
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, command);
    
    	//
    	// Initiate master single send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    }
    
    //*****************************************************************************
    //
    // Send a command and a value to LCD.
    //
    //*****************************************************************************
    void lcdBurst2Write(uint32_t g_ui32SysClock, uint8_t command, uint8_t value)
    {
    	//
    	// Set burst length.
    	//
    	MAP_I2CMasterBurstLengthSet(I2C0_BASE, 2);
    
    	//
    	// Set slave address.
    	//
    	MAP_I2CMasterSlaveAddrSet(I2C0_BASE, 0x30, false);
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, command);
    
    	//
    	// Initiate master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, value);
    
    	//
    	// End master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    }
    
    //*****************************************************************************
    //
    // Send a command and three values to LCD.
    //
    //*****************************************************************************
    void lcdBurst4Write(uint32_t g_ui32SysClock, uint8_t command, uint8_t value_1,
    		uint8_t value_2, uint8_t value_3)
    {
    	//
    	// Set slave address.
    	//
    	MAP_I2CMasterSlaveAddrSet(I2C0_BASE, 0x30, false);
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, command);
    
    	//
    	// Set burst length.
    	//
    	MAP_I2CMasterBurstLengthSet(I2C0_BASE, 4);
    
    	//
    	// Initiate master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, value_1);
    
    	//
    	// End master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, value_2);
    
    	//
    	// End master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    
    	//
    	// Place data to be send into FIFO.
    	//
    	MAP_I2CMasterDataPut(I2C0_BASE, value_3);
    
    	//
    	// End master burst send.
    	//
    	MAP_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);
    
    	//
    	// Wait for master to finish transaction.
    	//
    	delayMs(g_ui32SysClock, 100);
    	while (MAP_I2CMasterBusy(I2C0_BASE));
    }

    Yes I understand that my implementation of the burst send isn't very efficient as I have 3 separate send functions. I'm just writing to make things work for now, and will optimize my code afterward.

    Thomas

  • Hello Thomas,

    I would suggest using the Interrupt mechanism along with Burst mode as described in the application note. It will help avoid this known issue with the I2C controller. Please refer to the following application note.

    www.ti.com/.../spma073.pdf