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.

CCS/CC1310: CC1310 I2C multiplexing

Part Number: CC1310
Other Parts Discussed in Thread: CC1350STK

Tool/software: Code Composer Studio

Hi all,

I've a CC1310 module and 2 identical sensors hooked up to it using I2C, with the same I2C address.

I need to be able to (sequentially, not at the same time) read a value from each of them.

The CC1310 only has 1 I2C bus, and I am using existing hardware, so a physical I2C multiplexer IC would be undesirable. This is why I am attempting to multiplex the bus in firmware.

There are 2 things I tried:

1. Sharing I2C line, switching power from sensors. When trying this the CC1310 hangs when attempting to access bus (I2C driver crashes I guess) and continues (no reset) when I disconnect one of the senors, probably the sensors aren't properly high-Z when off. Haven't explored this angle any further.
2. 2 sets of I2C lines, and switching configuration code, like below. But this only works for the first initialization.

The switching is implemented as follows in the board config H file:

typedef enum CC1310_LAUNCHXL_I2CName {
    CC1310_LAUNCHXL_I2C1 = 0,
    CC1310_LAUNCHXL_I2C2,
    CC1310_LAUNCHXL_I2CCOUNT
} CC1310_LAUNCHXL_I2CName;

And then in the C:

const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = {
		{ // This struct already was there
			.baseAddr = I2C0_BASE,
			.powerMngrId = PowerCC26XX_PERIPH_I2C0,
			.intNum = INT_I2C_IRQ,
			.intPriority = ~0,
			.swiPriority = 0,
			.sdaPin = Board_I2C0_SDA1,
			.sclPin = Board_I2C0_SCL1,
		},
		{ // I added this one
			.baseAddr = I2C0_BASE,
			.powerMngrId = PowerCC26XX_PERIPH_I2C0,
			.intNum = INT_I2C_IRQ,
			.intPriority = ~0,
			.swiPriority = 0,
			.sdaPin = Board_I2C0_SDA2,
			.sclPin = Board_I2C0_SCL2,
		}
};

So basically, I just added a 2nd I2C instance with same I2C base, and different pins.

Then, in my application code, I call I2C_open with either of the I2C names to open one of them, then close it using I2C_close when I'm done again, like this:

	I2C_Params_init(&i2cParams);
	i2cParams.transferMode = I2C_MODE_BLOCKING; // Note that my I2C is in blocking mode
	i2cParams.bitRate = I2C_100kHz;
	i2cHandle = I2C_open(/*I2C name thingy here */, &i2cParams);
	if (i2cHandle == NULL)
		return false;
	// Do I2C stuff here
	I2C_close(i2cHandle);

Whereas this works fine for the first I2C name, when I run the exact same code after this for the 2nd sensor, it won't interact with I2C (I don't see any signal on Logic Analyzer).

Note that the sensors are working fine, if I switch the 2 sensors, it reads the other one just fine. Also, if I put the sensor read code in reverse order, they read fine, so HW is fine.

I am suspecting that I2C_close does not fully "undo" I2C_open, can this be the case? Is there some way to "reset" the whole I2C bus?

Maybe this is possible by interacting with power management?

Regards,

Robert

  • Have you looked at the rfWsnDmNode example that you get for CC1350STK in the simplelink_cc13x0_sdk_1_00_00_13? The sensorTag has several sensors connected to the same I2C Bus.

    BR
    Siri
  • Thanks for the reply,

    Sorry for being unclear, with identical sensors I meant the 2 sensors have identical I2C addresses. So they cannot work at the same time on the same bus. The sensors do not have an enable channel or address select pin.
  • There is an error in the above code. Does it work when you change this line

    CC1310_LAUNCHXL_I2C2 = 0

    to

    CC1310_LAUNCHXL_I2C2 = 1

    ?

  • Correctly spotted, though not the issue. It's a typo in the post, in the actual code it says 1. (I modded some variable names to make code more abstract in post)
  • Thanks for all help!

    For those of you looking to multiplex I2C; it can be done, but it's using a dirty hack for now:

    comment:

    // #pragma DATA_SECTION(i2cCC26xxHWAttrs, ".const:i2cCC26xxHWAttrs")

    Removed const from:

    /* const */ I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC1310_LAUNCHXL_I2CCOUNT] = {
    
     {
    
      .baseAddr = I2C0_BASE,
    
      .powerMngrId = PowerCC26XX_PERIPH_I2C0,
    
      .intNum = INT_I2C_IRQ,
    
      .intPriority = ~0,
    
      .swiPriority = 0,
    
      .sdaPin = Board_I2C0_SDA1,
    
      .sclPin = Board_I2C0_SCL1,
    
     }
    
    };

    and make it available to your application code using extern, then change pins in application code:

       i2cCC26xxHWAttrs[0].sdaPin = Board_I2C0_SDA2;
    
       i2cCC26xxHWAttrs[0].sclPin = Board_I2C0_SCL2;

    I'm still shivering on the dirtyness of this.... but it's a solution.

    I am unsure of further impact of this mod, especially the pragma mod is the one I am not happy about.

  • Hi,

    you found a workaround, but the solution from your first post is expected to work. One more thing: It's not enough to add another instance of HWAttrsV1. You also need to add an instance of I2C_Config. This is the one for that you will use the index in I2C_open():

    const I2C_Config I2C_config[I2CCOUNT] = {
        {
            .fxnTablePtr = &I2CCC26XX_fxnTable,
            .object      = &i2cCC26xxObjects[I2C0],
            .hwAttrs     = &i2cCC26xxHWAttrs[I2C0]
        },
        {
            .fxnTablePtr = &I2CCC26XX_fxnTable,
            .object      = &i2cCC26xxObjects[I2C0],
            .hwAttrs     = &i2cCC26xxHWAttrs[I2C1]
        },
    };

    You don't need two instances of I2CCC26XX_Object since you cannot create concurrent driver instances anyway. The beauty of the whole driver configuration system is questionable, but that is, how it is supposed to work in TI-RTOS.

    You also can omit this pragma directive. This was from the time when the TI-RTOS toolchain was not able to throw away unreferenced data symbols. It's already removed in the new CC13x0 SDK and the board files have got a face lift.

  • Hi, thanks for this reply, really useful :)

    I will try this soon when I have time, for now I leave it be and continue on master unit firmware :)

    Most likely my MCU crashed because it could not find I2C_Config then (so it attempted to read incorrect data).

    Regards,
    Robert