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.

Adding I2C Functionality to Project Zero on the CC2650 Launchpad

Other Parts Discussed in Thread: CC2650

Hi, 

I've been developing an application that is based on Project Zero for the CC2650 LaunchPad for quite a while now, and I was hoping that I could add an LCD display to the project. The LCD display that I picked out uses I2C for communication, so I've been attempting to add the I2C driver that is available through TI-RTOS. I have been following the steps suggested on the TI-RTOS I2C driver reference page (here).  

The implementation seems to be almost identical to the SPI driver, which I was able to successfully add to my project not too long ago, but for some reason, the I2C driver is just not working for me. I have included the necessary header files (I2C.h and I2CC26XX.h) at the top of my ProjectZero.c file. I have also created data structures I2C_Handle, I2C_Params, and I2C_Transactions at the top of my ProjectZero.c file, where all other variables are defined, and I have created transmit and receive buffers for the I2C_Transaction data structure in this same location. I then call I2C_Params_Init() and pass it a pointer to my I2C_Params data structure. I then include the I2C_init() function. If I compile the code at this point, without actually specifying any I2C transactions,  I receive no errors. If I upload it to the CC2650, the MCU functions normally. 

The trouble comes when I try to use the I2C_open(), I2C_transfer(), and I2C_Close() functions. I include them in my program, and the program compiles without errors. But when I program the CC2650, it locks up completely. I see no output to the console (I'm utilizing the UART logging option for Project Zero). At first, I thought it was just the application that got tied up (possibly because I'm using I2C in blocking mode), but I soon noticed that the CC2650 is also not advertising during this time, which tells me that the problem probably extends beyond the application. 

Is there something that I am missing when I try to use the I2C driver in Project Zero? I'm wondering if this is a case where I need to change a configuration file or modify the stack in some way before I2C drivers can be utilized. Because I lose all MCU functionality, I have not been able to debug and attempt to find a reason for the problems that I'm having.

If anyone could point me in the right direction, I would really appreciate it! If anything is unclear or you need more information, let me know and I will gladly provide. Thank you!

  • Are you able to run the program in debug mode?

    Did you see a valid handle returned when you do I2C_open?

    Can you try adding the following code into your program?

        i2cHandle = I2C_open(Board_I2C, &i2cParams);
        if (i2cHandle == NULL) {
            while(1);
        }

    Can you try to implement exception handle to see if there is any HW bus fault? You can find the instruction in our software developer's guide, section 9.8

  • Hi Christin, 

    Thank you for your response. I'll try to answer your questions as best I can. 

    I am able to run the program in debug mode and step through the main.c file all the way through. I'm not entirely sure how to determine if a valid handle is being returned. This was the code I had in my application before your response:

    static void initLCD(void)
    {
    	// Initialize I2C_Params data structure
    	I2C_Params_init(&i2cParams);
    	i2cParams.transferMode = I2C_MODE_BLOCKING;
    	i2cParams.bitRate = I2C_400kHz;
    	I2C_init();
    	initI2CDone++;
    
    
    	// Create write buffer and read buffer
    	uint8_t i2cTxBuf[] = {0x7C, 0x00, 0x38, 0x39, 0x14, 0x78, 0x5E, 0x6D, 0x0C, 0x01, 0x06};
    	uint8_t i2cRxBuf[] = {NULL};
    
    
    	// Setup transaction parameters
    	i2cTransaction.writeBuf = i2cTxBuf;
    	i2cTransaction.writeCount = sizeof(i2cTxBuf);
    
    	i2cTransaction.readBuf = i2cRxBuf;
    	i2cTransaction.readCount = sizeof(i2cRxBuf);
    
    	i2cTransaction.slaveAddress = (unsigned char) ADDR;
    
    	// Open I2C and perform transfer
    	i2cHandle = I2C_open(LCD_INDEX_VALUE, &i2cParams);
    	if (i2cHandle == NULL)
    	{
    		Log_info0("I2C Open Error");
    	}
    	I2C_transfer(i2cHandle, &i2cTransaction);
    	I2C_close(i2cHandle);
    }

    As you can see, I was trying to use the Log_info0() function to determine if a handle was successfully returned. Is there an alternate way that I can find out if the handle was successfully returned given that my logging is not currently working?

    As you suggested, I added while(1); right below Log_info0("I2C Open Error"); and then tested the code again. When compiled, I still received no errors, so I started the debug process. I stepped all the way through main() and looked at the CFSR register value to determine if any flags were set. The CSFR register in the CPU_SCS register group had value 0x00000000 the entire time. When I stopped debugging, I still saw no output to the console, and the CC2650 was not advertising. 

    I then tried to implement a custom exception handler as the Software Developer's Guide (section 9.8.2) suggests, but I'm not sure exactly how this is done. I'm having problems navigating through the app_BLE_UartLog.cfg file. If this would be a good next step, I might need some help figuring out where to find the M3Hwi.excHandlerFunc = "&exceptionHandler" line that is seen in section 9.8.2 of the Software Developer's Guide. 

    I decided to create a software breakpoint at the beginning of my initLCD() function. I can step through this function in the debugger all the way until I call the I2C_open() function. As soon as I try to step over the I2C_open() function, the debugger stops working. I no longer have the option to Step Into, Step Over, or Step Return. I restarted the debugger and tried to step into the I2C_open() function instead of stepping over it. The result produced an error that read: "Can't find a source file at "/db/vtree/library/trees/zumaprod/zumaprod-g06/tirtos_simplelink_2_13_00_06/packages/ti/drivers/I2C.c". 

    I hope some of these details are helpful. Let me know where you think I should go from here. I sincerely appreciate your help!

  • Kevin,

    Since ti-rtos uses a pre compiled i2c library you can't debug that code. Can you try adding the non compiled i2c driver (located inside: C:\ti\tirtos_cc13xx_cc26xx_2_18_00_03\products\tidrivers_cc13xx_cc26xx_2_16_01_13\packages\ti\drivers\i2c if you're on windows) to the project, and set a break point on "I2CCC26XX_open" in that file? CCS should automaticly override the pre-compiled files with the added ones. From there you should be able to debug more accurately.

    Regards,

    Klas
  • Hi Klas,

    I have added the non compiled i2c driver to my project using:

    Project -> Build Settings -> Include Options -> Add...

    I am on a Windows computer, so finding the directory you're talking about was very easy to do. Thank you!

    I set a break point on the I2CCC26XX_open() function in the newly added I2CCC26XX.c file. I'm not sure, however, that CCS performed an automatic override of the pre-compiled files with the added ones. The only reason that I say this is that even though I am calling the generic API function I2C_open() (which I assume makes a call to the I2CCC26XX_open), CCS gives me this message:

    "No code is associated with 'C:/ti/tirtos_cc13xx_cc26xx_2_16_01_14/products/tidrivers_cc13xx_cc26xx_2_16_01_13/packages/ti/drivers/i2c/I2CCC26XX.c", line 546 in any loaded symbols"

    Is there a way that I can instruct CCS to directly overide the noncompiled I2C driver?

    I also noticed that the dates on my tirtos directories are different from yours. Should I update these directories to the latest version before continuing?

    Thank you for your help!
  • Hi Klas,

    I think I've just verified that CCS is not using the non-compiled I2CCC26XX.c file after I added it to the include path. When I try to open the declaration for I2CC26XX_open() in my ProjectZero.c file, I receive the message "Could not find symbol 'I2CCC26XX_open' in index.

    In the pre compiled version of I2CCC26XX.c, the function of I2CCC26XX_open() is not directly available. In the non compiled version, I2CCC26XX_open() is made directly available, so if this file was being referenced by my include statement (below), then I should be able to open the declaration for the function through ProjectZero.c.

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

    Because I cannot open the declaration, I am led to believe that I am still not referencing the correct file, and therefore cannot debug any further until I can find a way to ensure that the non compiled version of I2CCC26XX.h is being used within my application. 

    Let me know if anything I'm saying is incorrect or unclear. I'm going to keep trying to debug different parts of the I2C module to see if I can find out anything new.

    Thank you!

  • Hi Kevin,

    You should not need to #include the added i2c driver as it is called from within "ti/drivers/I2C.h".

    Before updating, try setting "Full symbolic debug (--symdebug:dwarf, -g)" in Project > Properties > Build > ARM Compiler > Advanced Options > Advanced Debug Options. If you still get the "No code is associated with ..." error, try upgrading your stack and also CCS to the newest version, and add the new i2c files by right clicking on the project name > add files, or by simply drag and drop them directly into the project.

    Regards,

    Klas
  • Hi Klas, 

    Oh okay, so the #include file for the added driver isn't necessary. That makes sense now that I see the #include line for the device specific I2C driver in the generic I2C.h file. Thank you for pointing that out!

    I took your suggestion and set Full Symbolic debug (--symdebug:dwarf, -g) in the Advanced Debug Options. Unfortunately, when I attempt to step into the I2C_open function, I still receive the "No code is associated with..." error. 

    I noticed that while I was stepping through the initLCD() function that I provided in one of my previous posts, the disassembly had the I2C_open function being called twice, so when I was debugging, I would reach the line 

    i2cHandle = I2C_open(LCD_INDEX_VALUE, &i2cParams);

    and then the debugger would jump back to one of the previous lines of code, then jump once again to the I2C_open line, where it would lock up. I changed the order of the code just to make sure that this second call to I2C_open wasn't a problem. The updated function is here:

    static void initLCD(void)
    {
    	static I2C_Handle i2cHandle;
    	static I2C_Params i2cParams;
    	I2C_Transaction i2cTransaction;
    	// Initialize I2C_Params data structure
    	I2C_Params_init(&i2cParams);
    	i2cParams.transferMode = I2C_MODE_BLOCKING;
    	i2cParams.bitRate = I2C_400kHz;
    	I2C_init();
    	//initI2CDone++;
    
    
    	// Create write buffer and read buffer
    	uint8_t i2cTxBuf[] = {0x7C, 0x00, 0x38, 0x39, 0x14, 0x78, 0x5E, 0x6D, 0x0C, 0x01, 0x06};
    	uint8_t i2cRxBuf[] = {NULL};
    
    	// Open I2C and perform transfer
    	i2cHandle = I2C_open(LCD_INDEX_VALUE, &i2cParams);
    	if (i2cHandle == NULL)
    	{
    		Log_info0("I2C Open Error");
    		while(1);
    	}
    
    	// Setup transaction parameters
    	i2cTransaction.writeBuf = i2cTxBuf;
    	i2cTransaction.writeCount = sizeof(i2cTxBuf);
    
    	i2cTransaction.readBuf = i2cRxBuf;
    	i2cTransaction.readCount = sizeof(i2cRxBuf);
    
    	i2cTransaction.slaveAddress = (unsigned char) ADDR;
    
    
    	I2C_transfer(i2cHandle, &i2cTransaction);
    	I2C_close(i2cHandle);
    }

    The disassembly for the I2C_open function looks like this: 

    1842      	i2cHandle = I2C_open(LCD_INDEX_VALUE, &i2cParams);
    00005284:   4629                mov        r1, r5
    00005286:   F004FBC5            bl         #0x9a14

    Using the "Step Over Assembly" command, I was able to step over line 00005284. When I tried to step over line 00005286, the controller locked up. I know nothing about assembly language, so line 0005286 doesn't mean anything to me, but I thought I would include these details just in case they were helpful in any way. I'd also like to include that when I try to "Assembly Step Into" line 00005286, I receive the same "Can't find a source file..." message. 

    I'm going to update CCS and the BLE Stack ad see if I can get it working after that. I've got a quick question, though. The Project Zero application that I've been working with is meant for the LaunchPad and not the CC2650 development board, so it uses UART logging to output to the console. I also happened to notice that on the TI-RTOS webpage for the I2C.h file (here), there is a line that says "The I2C driver interface produces log statements if instrumentation is enabled." Is it possible that the UART logging feature is somehow conflicting with the I2C driver? Could they be fighting for control of the same bus? 

    Thank you for your continued support. 

  • Hi Klas,

    I think I just stumbled on the solution to my problem.  I'm not sure why it's the solution, but all features of my application are now working (advertising and UART logging). Looking at this block of code:

    // Open I2C and perform transfer
    i2cHandle = I2C_open(LCD_INDEX_VALUE, &i2cParams);
    if (i2cHandle == NULL)
    {
    	Log_info0("I2C Open Error");
    	while(1);
    }

    the highlighted line includes LCD_INDEX_VALUE. At the top of my ProjectZero.c file, I had created an enumerated type called index_value to store index values for various peripherals in my system, as shown below:

    // Index value for SPI or I2C transmission
    typedef enum
    {
    	DAC_INDEX_VALUE = 0,
    	LCD_INDEX_VALUE,
    	SPEAKER_INDEX_VALUE
    } index_value;

    As you can see, LCD_INDEX_VALUE has value 1. It appears that when I passed a 1 as the index parameter of the I2C_open function, it was causing a problem. I replaced LCD_INDEX_VALUE with a 0 in my code:

    // Open I2C and perform transfer
    i2cHandle = I2C_open(0, &i2cParams);

    The function now works as it is supposed to!

    I'm sorry for causing so much commotion over what was probably just a bonehead mistake. I had assumed that the index value was simply a way for the user to create index values for each peripheral, and that the index value was not critical to the operation of the I2C peripheral. Do you have a good explanation for why this problem occurred when index was passed as 1? I'd be interested to know just in case I run into problems in the future. 

    Anyways, thank you for your help! 

  • Hi Kevin,

    No worries, I'm happy you found the error as i was trying to find the solution myself. The first argument is an index for which i2c interface you are using. Good practise would be to set it to "CC2650_I2C0" as it has index 0. The reason is because the same API can be used for several different boards. Have a nice weekend!

    Regards,

    Klas
  • Hi Klas, 

    Ah, that makes complete sense! Thank you for all of your help. Have a great weekend!

    Sincerely,

    Kevin