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.

RTOS/CC2650: How to handle multiple I2C tasks with the same I2C peripheral ?

Part Number: CC2650
Other Parts Discussed in Thread: OPT3001, TMP112

Tool/software: TI-RTOS

I am working with a custom CC2650MODA board. Starting from an empty example i got LED blink to work. Then i added one more task for I2C communication using OPT3001 sensor. Both the tasks worked fine. However when i added another I2C task to read TMP112 sensor, i couldn't compile my code because of errors. When i comment my OPT3001 task i can get the TMP112 to work. I referred to this post that says we cannot do multiple I2C_open() on the same peripheral without closing it first. After trying several variations in my code i still haven't been able to get it to work.

I know that Sensortag example codes easily mitigate this issue as even they have many I2C sensors on the same I2C peripheral. But the issue is that the sensortag code has so many files and codes that i couldn't figure out how they solve this issue i am having.

Can you please suggest how do i edit the following codes that i have written that work if only of the I2C tasks is active. How do i define and declare I2C functions and parameters/handles so that i can get it to compile even when using different tasks for different sensors ?

/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/runtime/System.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>

/* TI-RTOS Header files */
#include <ti/drivers/I2C.h>
#include <ti/drivers/PIN.h>
/* Board Header files */
#include "Board.h"
#include <math.h>
#define TASKSTACKSIZE   512

Task_Struct task0Struct;
Char task0Stack[TASKSTACKSIZE];
Task_Struct task1Struct;
Char task1Stack[TASKSTACKSIZE];
Task_Struct task2Struct;
Char task2Stack[TASKSTACKSIZE];

/* Pin driver handle */
static PIN_Handle ledPinHandle;
static PIN_State ledPinState;

/*
 * Application LED pin configuration table:
 *   - All LEDs board LEDs are off.
 */
PIN_Config ledPinTable[] = {
    IOID_9 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MED,//LED
    IOID_4 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,//OPT3001
    IOID_3 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,//TMP112
    PIN_TERMINATE
};

/*
 *  ======== heartBeatFxn ========
 *  Toggle the Board_LED0. The Task_sleep is determined by arg0 which
 *  is configured for the heartBeat Task instance.
 */
void heart_beat(){
    PIN_setOutputValue(ledPinHandle, IOID_9,!PIN_getOutputValue(IOID_9));
    Task_sleep(500000/Clock_tickPeriod);
    PIN_setOutputValue(ledPinHandle, IOID_9,!PIN_getOutputValue(IOID_9));
    Task_sleep(500000/Clock_tickPeriod);
}
Void heartBeatFxn(UArg arg0, UArg arg1)
{
    while (1) {
        heart_beat();
    }
}
Void opt300xfxn(){
    I2C_Handle opthandle;
    I2C_Params optparams;
    I2C_Params_init(&optparams);
    optparams.transferMode = I2C_MODE_BLOCKING;
    optparams.bitRate = I2C_400kHz;
    opthandle = I2C_open(Board_I2C0,&optparams);
    if (opthandle == NULL){
        System_abort("Error Initializing I2C");
    }else{
        System_printf("I2C initialized\n");
    }
    I2C_Transaction opttransaction;
    uint16_t lux;
    uint8_t txbuf[4];
    uint8_t rxbuf[4];
    opttransaction.slaveAddress = 0x44;
    while(1){ //Do this when you are doing single shot communication. As config register resets to 00(shutdown) after one conversion. You have to write to config everytime you want to make a reading.
    txbuf[0] = 0x01;
    txbuf[1] = 0xCA; //C4=100ms continuous, CC=800ms continuous, C2=100ms singleshot, CA=800ms singleshot
    txbuf[2] = 0x10;
    opttransaction.writeBuf = txbuf;
    opttransaction.readBuf = rxbuf;
    opttransaction.writeCount = 3;
    opttransaction.readCount = 0;
    if (I2C_transfer(opthandle, &opttransaction)){
        System_printf("Config write!\n");
    } else {
        System_printf("Config write fail!\n");
    }
    opttransaction.writeBuf = txbuf;
    opttransaction.readBuf = rxbuf;
    opttransaction.writeCount = 1;
    opttransaction.readCount = 2;
    txbuf[0] = 0x00;
    uint8_t i = 0;
    //for (i = 0; i<100; i++){// Do this in case of continuous conversion mode.

        if(I2C_transfer(opthandle,&opttransaction)){
            uint8_t e,m;
            float v;
            lux = rxbuf[0];
            lux = (lux<<8)|rxbuf[1];
            m = lux & 0x0FFF;
            System_printf("m = %d\n", m);
            e = (lux & 0xF000)>>12;
            System_printf("e = %d\n", e);
            v = (float)m*(0.01 * exp2(e));
            System_printf("Lux : %d\n",v);
        }
        I2C_close(opthandle);
        System_flush();
        Task_sleep(2000000/Clock_tickPeriod);
    }
    I2C_close(opthandle);
    System_printf("I2C Closed\n");
    System_flush();
}

Void tempfxn(){
    I2C_Handle tmphandle;
    I2C_Params tmpparams;
    I2C_Params_init(&tmpparams);
    tmpparams.transferMode = I2C_MODE_BLOCKING;
    tmpparams.bitRate = I2C_400kHz;
    tmphandle = I2C_open(Board_I2C0,&tmpparams);
    if (tmphandle == NULL){
            System_abort("Error Initializing I2C");
    }else{
        System_printf("I2C initialized\n");
    }
    I2C_Transaction tmptransaction;
    uint16_t temp;
    uint8_t txbuf[4];
    uint8_t rxbuf[4];
    tmptransaction.slaveAddress = 0x48;
    while(1){
    txbuf[0] = 0x01;
    txbuf[1] = 0xE1;
    txbuf[2] = 0x80;
    tmptransaction.writeBuf = txbuf;
    tmptransaction.readBuf = rxbuf;
    tmptransaction.writeCount = 3;
    tmptransaction.readCount = 0;
    if (I2C_transfer(tmphandle, &tmptransaction)){
        System_printf("Config write!\n");
    } else {
        System_printf("Config write fail!\n");
    }
        tmptransaction.writeBuf = txbuf;
        tmptransaction.readBuf = rxbuf;
        tmptransaction.writeCount = 1;
        tmptransaction.readCount = 2;
        txbuf[0] = 0x00;
        if(I2C_transfer(tmphandle,&tmptransaction)){
            temp = rxbuf[0];
            temp = (temp<<8)|rxbuf[1];
            temp = temp>>4;// & 0xFFF0;
            System_printf("Temp *C = %d\n", temp/16);
        }
        System_flush();
        Task_sleep(2000000/Clock_tickPeriod);
    }
    I2C_close(tmphandle);
    System_printf("I2C Closed\n");
    System_flush();
}

int main(void)
{
    Task_Params taskParams;
    Task_Params optparams;
    Task_Params tmpparams;
    /* Call board init functions */
    Board_initGeneral();
    Board_initI2C();
    /* Construct heartBeat Task  thread */
    Task_Params_init(&taskParams);
    taskParams.arg0 = 1000000 / Clock_tickPeriod;
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &task0Stack;
    Task_construct(&task0Struct, (Task_FuncPtr)heartBeatFxn, &taskParams, NULL);

    //Task_Params_init(&optparams);
    //optparams.stackSize = TASKSTACKSIZE;
    //optparams.stack = &task1Stack;
    //Task_construct(&task1Struct, (Task_FuncPtr)opt300xfxn, &optparams, NULL);

    Task_Params_init(&tmpparams);
    optparams.stackSize = TASKSTACKSIZE;
    optparams.stack = &task2Stack;
    Task_construct(&task2Struct, (Task_FuncPtr)tempfxn, &tmpparams, NULL);

    /* Open LED pins */
    ledPinHandle = PIN_open(&ledPinState, ledPinTable);
    if(!ledPinHandle) {
        System_abort("Error initializing board LED pins\n");
    }
    BIOS_start();

    return (0);
}

  • Hi Shantam,

    You are correct in that you can not open the same I2C peripheral (Board_I2C0 in your case). If both sensors are on the same I2C bus, what you have to do is to have a global shared I2C handle that both task use. In this case one task would have to do perform the open call and the other simply have to check that the handle is valid (not null).

    If doing this, you should probably protect access to the I2C bus using a semaphore to avoid problems between the two tasks when both want to access the bus at the same time.