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 driver getting stuck in blocking mode on MSP430F6779

Other Parts Discussed in Thread: MSP430F6779, SYSBIOS

Hi

I have a very strange problem with using the I2C_drivers on a MSP430F6779. I'm using Compiler 4.4.4, RTOS 2.12.1.33 and XDCTools 3.31.1.33.

I am calling I2C_transfer to talk to 4 other devices on our hardware. I have several references project where some work and some don't. It appears to get stuck in semaphore_pend(...WAIT_FOREVER)

I have taken one project that is working and talking to all devices on SPI, I2C, UART and GPIO and taken out the part that talks to our EEProm over I2C and put this into a separate project. This project does not work and is a good sample of it not working, but I can't for the life of me figure out why. There seems to be a pattern where I can do a write, read, write (here it gets stuck) to break it. Then I have to reset 3 times before it repeats this again...very odd!

The project settings, the linker, compilers, RTOS config file are all identical to one that is working. I've tried changing the data types I pass, the depth of the calls, the stack/heap sizes, putting them into dynamic rather than static tasks...none of it seems to identify the problem.

Any help would be appreciated.

Here is the code:

/*

/*
 *  ======== main.c ========
 */

#include "Board.h"

#include <xdc/std.h>

#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>

#include <xdc/cfg/global.h>

#include <ti/sysbios/knl/Task.h>

#include <ti/sysbios/BIOS.h>

#include <stdbool.h>

#include <ti/drivers/UART.h>
#include <ti/drivers/UART/UARTEUSCIA.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/SPI.h>

#include "hal/I2C/i2c.h"

#include <gpio.h>

void Main_Task();

//global to switch between LEDs
int LED_no = 0;

void Port1_Callback(void)
{
    ;
}

void Port2_Callback(void)
{
	;
}
/*
 *  ======== main ========
 */
Int main()
{

	/* Local Variables */
    Error_Block eb;
    Task_Params taskParams;

	/* Setup Board */
	Board_initGeneral();
	Board_initGPIO();
    Board_initUART();
    Board_initI2C();
    Board_initSPI();

    /*Enable/Disable Interrupts */
    GPIO_disableInt(MSP_430F6779_LS_INT1);
    GPIO_disableInt(MSP_430F6779_LS_INT2);
    GPIO_disableInt(MSP_430F6779_RF_GDO0);
    GPIO_disableInt(MSP_430F6779_RF_GDO2);
    GPIO_enableInt(MSP_430F6779_SW2);

	/* Initialise Components */
    System_flush();

    /* Turn OFF LEDs */
    GPIO_write(Board_LED0, 1);
    GPIO_write(Board_LED1, 1);
    GPIO_write(Board_LED2, 1);
    GPIO_write(Board_LED3, 1);


    //board_UART_init();

	//board_UART_open(UART_GSM);
	//board_UART_open(UART_GPS);
	//board_UART_open(UART_MCU);

	/* Create Test Task */
	Error_init(&eb);
    Task_Params_init(&taskParams);
    taskParams.stackSize = 0x300;
	Task_create(Main_Task, &taskParams, &eb);

    BIOS_start();    /* does not return */

    return(0);
}

void Main_Task()
{
    long i = 0;
	Bool i2cSuccess = FALSE;
	char ee_writeBuffer[20] = {0x00, 0x00, 0x4D, 0x61, 0x72, 0x6B, 0x20, 0x52, 0x75, 0x6C, 0x65, 0x73, 0x21, 0x0A};
	char ee_writeBuffer2[20] = {0x00, 0x00, 0x4C, 0x61, 0x72, 0x6B, 0x20, 0x52, 0x75, 0x6C, 0x65, 0x73, 0x21, 0x0A};
	char ee_readBuffer[20] = {0x11};
    uint16_t j = 0;

    board_i2c_init();
    i2c_eeprom_init(EEPROM_SlaveAddress);

    while(1)
    {
	if (i == 10000)
        {
	    i2cSuccess = board_i2c_open();

            if (i2cSuccess == FALSE)
            {
			    //error
                ;//UART_write(hdlMCU, "\r\nI2C Open Error", 17);
            }
            i++;
        }
        else if (i == 20000)
        {
            i2cSuccess = i2c_eeprom_writedata(ee_writeBuffer, sizeof(ee_writeBuffer));
            i++;
        }
        else if (i == 30000)
        {
            i2cSuccess = i2c_eeprom_readdata(ee_writeBuffer, 2, ee_readBuffer, sizeof(ee_readBuffer));
            i++;
        }
        else if (i == 40000)
        {
            i2cSuccess = i2c_eeprom_writedata(ee_writeBuffer2, sizeof(ee_writeBuffer2));
            i++;
        }
        else if (i == 50000)
        {
            i2cSuccess = i2c_eeprom_readdata(ee_writeBuffer2, 2, ee_readBuffer, sizeof(ee_readBuffer));
            i++;
        }
	else if (i == 60000)
	    {
            board_i2c_close();
            i = 0;
        }
        else
        {
	    i++;
        }
    }
}

RTOS CONFIG FILE:

var Defaults = xdc.useModule('xdc.runtime.Defaults');

var Diags = xdc.useModule('xdc.runtime.Diags');

var Error = xdc.useModule('xdc.runtime.Error');

var Main = xdc.useModule('xdc.runtime.Main');

var Memory = xdc.useModule('xdc.runtime.Memory')

var SysMin = xdc.useModule('xdc.runtime.SysMin');

var System = xdc.useModule('xdc.runtime.System');

var Text = xdc.useModule('xdc.runtime.Text');

var BIOS = xdc.useModule('ti.sysbios.BIOS');

var Clock = xdc.useModule('ti.sysbios.knl.Clock');

var Task = xdc.useModule('ti.sysbios.knl.Task');

var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');

var Hwi = xdc.useModule('ti.sysbios.family.msp430.Hwi');

var TIRTOS = xdc.useModule('ti.tirtos.TIRTOS');

var Swi = xdc.useModule('ti.sysbios.knl.Swi');

TIRTOS.libType = TIRTOS.LibType_Instrumented;

System.maxAtexitHandlers = 4;

BIOS.libType = BIOS.LibType_Custom;

/* System stack size (used by ISRs and Swis) */

Program.stack = 0x200;

/* Circular buffer size for System_printf() */

SysMin.bufSize = 0x200;

System.SupportProxy = SysMin;

TIRTOS.useUART = true;

TIRTOS.useGPIO = true;

TIRTOS.useI2C = true;

TIRTOS.useSPI = true;

/* Button 2 (P1), ALS Sensor (P1), ALS Sensor (P2) */

var hwi1Params = new Hwi.Params();

var hwi7Params = new Hwi.Params();

/* UART A0 */

var hwi2Params = new Hwi.Params();

/* UART A1 */

var hwi3Params = new Hwi.Params();

/* UART A2 */

var hwi4Params = new Hwi.Params();

/* SPI DMA */

var hwi6Params = new Hwi.Params();

/* I2C */

var hwi5Params = new Hwi.Params();

hwi1Params.arg = 0;
hwi1Params.instance.name ="hwi1";
Program.global.hwi1 = Hwi.create(45, "&Port1_Callback", hwi1Params);

hwi2Params.instance.name ="hwi2";
hwi2Params.arg = 0;
Program.global.hwi2 = Hwi.create(59, "&UARTEUSCIA_hwiIntFxn", hwi2Params);

hwi3Params.instance.name ="hwi3";
hwi3Params.arg = 2;
Program.global.hwi3 = Hwi.create(52, "&UARTEUSCIA_hwiIntFxn", hwi3Params);

hwi4Params.instance.name ="hwi4";
hwi4Params.arg = 1;
Program.global.hwi4 = Hwi.create(53, "&UARTEUSCIA_hwiIntFxn", hwi4Params);

hwi5Params.instance.name ="hwi5";
hwi5Params.arg = 0;
Program.global.hwi5 = Hwi.create(46, "&I2CEUSCIB_hwiIntFxn", hwi5Params);

hwi6Params.instance.name ="hwi6";
hwi6Params.arg = 0;
Program.global.hwi6 = Hwi.create(50, "&MSP_430F6779_isrDMA", hwi6Params);

hwi7Params.arg = 0;
hwi7Params.instance.name ="hwi7";
Program.global.hwi7 = Hwi.create(42, "&Port2_Callback", hwi7Params);

BIOS.cpuFreq.lo = 8192000;
Defaults.common$.diags_ASSERT = Diags.ALWAYS_ON;

I2C CONFIG IN MSP_430F6779.c

#if defined(__TI_COMPILER_VERSION__)

#pragma DATA_SECTION(I2C_config, ".const:I2C_config")

#pragma DATA_SECTION(i2cUSCIBHWAttrs, ".const:i2cUSCIBHWAttrs")

#endif

#include <ti/drivers/I2C.h>

#include <ti/drivers/i2c/I2CEUSCIB.h>

/* I2C objects */

I2CEUSCIB_Object i2cUSCIBObjects[MSP_430F6779_I2CCOUNT];

/* I2C configuration structure */

const I2CEUSCIB_HWAttrs i2cUSCIBHWAttrs[MSP_430F6779_I2CCOUNT] = {

{

EUSCI_B1_BASE,

EUSCI_B_I2C_CLOCKSOURCE_SMCLK

}

};

//

const I2C_Config I2C_config[] = {

{

&I2CEUSCIB_fxnTable,

&i2cUSCIBObjects[0],

&i2cUSCIBHWAttrs[0]

},

{NULL, NULL, NULL}

};

///*

// * ======== MSP_430F6779_initI2C ========

// */

void MSP_430F6779_initI2C(void)

{

/* USCIB1 */;

GPIO_setAsPeripheralModuleFunctionInputPin(

GPIO_PORT_P4, GPIO_PIN4 | GPIO_PIN5);

I2C_init();

}

Apologies for the formatting, it's quite a lot of text.

Thanks.

  • Hi Again

    I have a quick update. In the working project I have a GPIO_read function that reads Port 1, pin 3 - which we have a switch connected to. I poll this almost all the time as we have a test harness that listens for this being turned on. If I remove this code, then the I2C bus will fail after 3 transactions again.

    I have put this code into my broken project above and it fixes the issue. I have no idea why, but maybe this can shed some light on to what is going on? I suspected a delay was allowing it to work, but this doesn't seem to be the case as I have tried delaying with having a counter delay, task_sleep() and __delay_cycles().

    I have also noticed that if the I2C transaction fails then the task will block forever, shouldn't the drivers have a timeout?

    There is nothing in our PCB layout that would suggest the switch would affect any other hardware.

    Add this to the top and inside the while loop and it will work. If you stop calling this, the I2C will break.

    pin = GPIO_read(MSP_430F6779_SW2);

    It's worth noting that it has nothing to do with the pin, if you call GPIO_read with any other value, it still fixes it. It appears to be calling the function itself that works.


    Thanks again

  • I moved this to the (Missing Group) forum because it looked like an issue with TI-RTOS or SYS-BIOS drivers maybe...
    -Katie
  • Mark,

    I don't really know the exact nature of your setup, but the most likely cause for the I2C driver to get stuck in the Semaphore_pend(transferComplete, BIOS_WAIT_FOREVER); is that the EUSCI controller didn't fire an interrupt (perhaps on a bus fault) to finish its internal state-machine. The I2C driver prints log messages if you use the instrumented I2C driver with Logs enabled. The UART Echo example I think demonstrates the instrumentation with the UART. Following the Logs it might help find where it dies.

    Mark Anderton said:
    I have also noticed that if the I2C transaction fails then the task will block forever, shouldn't the drivers have a timeout?

    There is a bug ID for this, but it hasn't been prioritized as its possible to use the I2C driver in I2C_MODE_CALLBACK where you can add your own semaphore with a timeout. You'd block code execution after calling I2C_transfer() and then perform a Semaphore_post in its callback function.

    Mark Anderton said:
    There is nothing in our PCB layout that would suggest the switch would affect any other hardware.

    Was this determined by scoping out the I2C's SCL and SDA signals? It be interesting to see the difference in the working and non-working case.