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.

TMS320F28027: Question about I2C initial states using GPIOs 32 and 33

Part Number: TMS320F28027
Other Parts Discussed in Thread: CONTROLSUITE, TLC59116, C2000WARE

We're attempting to address an I2C slave device and have found that SCL is always high and SDA is always low right out of the boot state.  We're running the code from flash and using the ControlSUITE templates.

At the very top of my main function, I added this code:  while(1==1);  So none of the rest of the code is doing anything and the CPU simply spins.

Then I hooked up a scope to GPIOs 32/33.  I don't know much about I2C, honestly, but doesn't the I2C spec say that both signals are supposed to be high by default?  I don't find any information in the data sheet regarding jumpers that might alter this behavior.

Thanks!

Mike

  • Hi Mike,

    Your while loop is at the very top of main before any GPIO configuration is executed? You probably have to configure the GPIOs being used for I2C first to see what you're expecting. See init function below:

    //
    // InitI2CGpio - This function initializes GPIO pins to function as I2C pins
    //
    // Each GPIO pin can be configured as a GPIO pin or up to 3 different
    // peripheral functional pins. By default all pins come up as GPIO
    // inputs after reset.
    //
    // Caution:
    // Only one GPIO pin should be enabled for SDAA operation.
    // Only one GPIO pin shoudl be enabled for SCLA operation.
    // Comment out other unwanted lines.
    //
    void
    InitI2CGpio()
    {
        EALLOW;
    
        //
        // Enable internal pull-up for the selected pins
        // Pull-ups can be enabled or disabled disabled by the user.
        // This will enable the pullups for the specified pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPAPUD.bit.GPIO28 = 0;    // Enable pull-up for GPIO28 (SDAA)
        GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;    // Enable pull-up for GPIO29 (SCLA)
    
        //GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;   // Enable pull-up for GPIO32 (SDAA)
        //GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;   // Enable pull-up for GPIO33 (SCLA)
    
        //
        // Set qualification for selected pins to asynch only
        // This will select asynch (no qualification) for the selected pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPAQSEL2.bit.GPIO28 = 3;  // Asynch input GPIO28 (SDAA)
        GpioCtrlRegs.GPAQSEL2.bit.GPIO29 = 3;  // Asynch input GPIO29 (SCLA)
    
        //GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
        //GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)
    
        //
        // Configure I2C pins using GPIO regs
        // This specifies which of the possible GPIO pins will be I2C 
        // functional pins. Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 2;   // Configure GPIO28 for SDAA
        GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 2;   // Configure GPIO29 for SCLA
    
        //GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 for SDAA
        //GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 for SCLA
    
        EDIS;
    }

    best,

    Kevin

  • Hi Kevin:

    I added your initialization code just before the while loop and retested. No difference. I should have mentioned before that this happens with the Piccolo unattached to our slave device, running out of the box, if that matters.

    I had tested similar initialization code before but had not supplied the EALLOW/EDIS lines and was hopeful that maybe the GPIOs weren't actually being initialized.

    Mike
  • Hi Mike,

    Hmm OK. I was thinking the GPIOs would be configured as inputs up until this configuration, as stated in the comments, but maybe the signals don't get pulled up until the I2C module is taken out of reset.

    Can you see if the signals get pulled up after initializing the I2C module?

    //
    // I2CA_Init -
    //
    void
    I2CA_Init(void)
    {
        //
        // Initialize I2C
        //
        I2caRegs.I2CSAR = 0x0050;        // Slave address - EEPROM control code
    
        //
        // I2CCLK = SYSCLK/(I2CPSC+1)
        //
    #if (CPU_FRQ_40MHZ||CPU_FRQ_50MHZ)
        I2caRegs.I2CPSC.all = 4;       // Prescaler - need 7-12 Mhz on module clk
    #endif
    
    #if (CPU_FRQ_60MHZ)
        I2caRegs.I2CPSC.all = 6;       // Prescaler - need 7-12 Mhz on module clk
    #endif
        I2caRegs.I2CCLKL = 10;           // NOTE: must be non zero
        I2caRegs.I2CCLKH = 5;            // NOTE: must be non zero
        I2caRegs.I2CIER.all = 0x24;      // Enable SCD & ARDY interrupts
    
        //
        // Take I2C out of reset. Stop I2C when suspended
        //
        I2caRegs.I2CMDR.all = 0x0020;
    
        I2caRegs.I2CFFTX.all = 0x6000;   // Enable FIFO mode and TXFIFO
        I2caRegs.I2CFFRX.all = 0x2040;   // Enable RXFIFO, clear RXFFINT,
    
        return;
    }

    Or if that doesn't do the trick after the I2C module is set to a master transmitter:

        //
        // Send start as master transmitter
        //
        I2caRegs.I2CMDR.all = 0x6E20;

    Is there a reason your not wanting to use external pull-up resistors on your I2C bus? Typically that is the better option rather than using the internal pull-up resistors.

    Best,

    Kevin

  • Nope, I tried both snippets of code and see no difference.

    Our slave device does have pull-ups but after we determined that we were seeing these signaling problems, we disconnected it from the Piccolo and tried the code using only the out-of-box board, expecting that the on-board pull-ups would be sufficient.

    We've tried single-stepping through the initialization code and watching the scope to see if anything changes.  It doesn't, no matter if the I2C is in reset or not.

    Given the number of people who've shown examples of using the I2C on this platform, it's very frustrating that we can't make any headway on this issue.

    Mike

  • New information!  I was wrong about single-stepping.  (There are two of us looking at this problem in different offices.)

    If I single-step the attached code, I find that the signals indeed are both high after rebooting, as we'd expect.  As the code progresses, the clock and data signals change as I noted.  If I let the code run freely, it hangs in the last busy loop and the clock signal stays low.

    Uint16 I2CA_WriteData(Uint16 addr, Uint16 reg, Uint16 data)
    {
    I2caRegs.I2CMDR.bit.IRS = 1; // I2C is enabled
    while (I2caRegs.I2CSTR.bit.BB == 1);
    I2caRegs.I2CSTR.bit.SCD = 1; // Clear stop condition bit
    while (I2caRegs.I2CMDR.bit.STP == 1);
    I2caRegs.I2CSAR = addr;
    while (I2caRegs.I2CSTR.bit.BB == 1);
    I2caRegs.I2CCNT = 2; // Register address = 1 byte, data = 1 byte

    I2caRegs.I2CMDR.bit.NACKMOD = 0; // NACK mode bit
    I2caRegs.I2CMDR.bit.FREE = 0; // Do not free run I2C when suspended
    I2caRegs.I2CMDR.bit.STT = 1; // START condition bit
    I2caRegs.I2CMDR.bit.STP = 1; // STOP condition bit

    // ***************************************************
    // NOTE: CLK goes low, DATA stays high after this line
    // ***************************************************
    I2caRegs.I2CMDR.bit.MST = 1; // Master mode: this is the line where CLK goes low but DATA stays high

    I2caRegs.I2CMDR.bit.TRX = 1; // Transmitter mode

    // ***************************************************
    // NOTE: DATA goes low after this line
    // ***************************************************
    I2caRegs.I2CMDR.bit.XA = 0; // 7-bit addressing mode
    I2caRegs.I2CMDR.bit.RM = 0; // Nonrepeat mode
    I2caRegs.I2CMDR.bit.DLB = 0; // Digital loopback mode is disabled
    I2caRegs.I2CMDR.bit.IRS = 1; // The I2C module is enabled
    I2caRegs.I2CMDR.bit.STB = 0; // The I2C module is not in the START byte mode

    // ***************************************************
    // NOTE: DATA goes high again after this line
    // ***************************************************
    I2caRegs.I2CMDR.bit.FDF = 0; // Free data format mode is disabled
    I2caRegs.I2CMDR.bit.BC = 0; // 8 bits per data byte

    // ***************************************************
    // NOTE: Both go high after this line
    // ***************************************************
    I2caRegs.I2CMDR.bit.STP = 1; // Stop bit when CNT=0
    I2caRegs.I2CDXR = reg; // TLC59116 register address
    I2caRegs.I2CDXR = data; // Data for this register

    while (!I2caRegs.I2CSTR.bit.SCD);

    return I2C_SUCCESS;
    }

  • Hi Mike,

    It is hanging at the Bus Busy check after setting the slave address register? This is occurring when no breakpoints are set and the slave device is not connected?

    I2caRegs.I2CSAR = addr;
    while (I2caRegs.I2CSTR.bit.BB == 1);
    I2caRegs.I2CCNT = 2; // Register address = 1 byte, data = 1 byte

    Can you provide a screenshot of the SCL/SDA waveforms when this occurrence happens for me?

    Some explanations of why SCL could be held low are provided in the I2C chapter of the f2802x TRM.

    http://www.ti.com/lit/sprui09

    Best,

    Kevin

  • No, if I single-step the code, it doesn't hang in any of the busy-waits, but doesn't seem to work right.  That is, the data I'm sending should turn on a series of LEDs attached to the slave device and this doesn't happen.

    If I let the code run freely, it hangs at the last busy-wait *while(!I2caRegs.I2CSTR.bit.SCD);*  when sending the first byte.  In other words, the code appears to hang and I pause execution; the CPU is then looping in this busy-wait.  I don't know much about I2C but perhaps there's a bus timeout involved, such that if I'm single-stepping, the long delay between writes to the bus masks the problem in some way.

    I've asked our hardware engineer to take a look at the bus signals using a logic analyzer.

    We used this identical I2C slave device (namely a TLC59116 LED lighting driver) with an Arduino last year, so I'm pretty confident that I'm using the proper addressing and trying to send the right configuration bytes.

    -- Mike

  • Hi Mike,

    Getting stuck at *while(!I2caRegs.I2CSTR.bit.SCD);* would indicate that a STOP condition is not being generated. Maybe I2CCNT is not reaching 0 in order for the STOP condition to be generated. Looking at the I2CCNT register value in the "expressions window" of CCS when at the while loop would tell you if that's the issue.

    However looking at the waveforms will be the easiest way to debug this issue. You're wanting to see the following:

    START condition --> Slave Address + 0 (LSB write bit) + ACK --> Register being written to + ACK --> Data being written + ACK --> STOP condition

    Best,
    Kevin

  • Kevin, I looked at I2CCNT and I2CSTR when the code hangs at the busy-wait.

    The count register does not decrement.  I also tried sending only one byte (previously the function set I2CCNT=2 and tried to send two) and it's still set to 1.

    The I2CSTR register contents are interesting.  The code is setting up like this: *I2caRegs.I2CMDR.all = 0x2620; // Set: STT, MST, TRX, IRS bits to start the transmission*.  When I look at this register using the debugger, it's set to 0x0400 after writing the data register, with only MST set.

    Is this expected?

    Our hardware guy is looking into this but is having some equipment problem today.

    -- Mike

  • Hi Mike,

    That doesn't sound right. You're checking the value of I2CMDR in the expressions window? The register should be set to 0x2620 after executing that line of code.

    You provided a writeData function earlier, do you have a I2C_Init function called before this you could share?

    Best,
    Kevin
  • Kevin, I made an error in my earlier post.  That was the status register I viewed, not the mode register.

    Below I'll paste the simplest program I can imagine.  I'm trying to write 1 byte to our slave device.  The hardware engineer tells me that nothing is getting onto the bus.

    The output I see in the console window is below.  I never see any bits except XSMT and XRDY set in the status register after starting the transmission.

    I2COAR=0x0000

    I2CIER=0x0000

    I2CSTR=0x0410

    I2CCLKL=0x002D

    I2CCLKH=0x002D

    I2CCNT=0x0000

    I2CDRR=0x0000

    I2CSAR=0x0060

    I2CDXR=0x0000

    I2CDXR=0x0000

    I2CISRC=0x0000

    I2CEMDR=0x0001

    I2CPSC=0x0005

    I2CFFTX=0x0000

    I2CFFRX=0x0000

    XSMT
    XRDY (19 more lines showing only XSMT and XRDY)

    Code:

    #include <stdio.h>
    #include "DSP28x_Project.h"     // DSP28x header file
    #include "f2802x_common/include/F2802x_SWPrioritizedIsrLevels.h"
    #include "f2802x_common/include/clk.h"
    #include "f2802x_common/include/gpio.h"
    #include "f2802x_common/include/pll.h"
    #include "f2802x_common/include/pie.h"
    #include "f2802x_common/include/timer.h"
    #define TLC59116_SLAVE_ADDR     0x60
    
    PLL_Handle myPll;
    CLK_Handle myClk;
    GPIO_Handle myGpio;
    extern Uint16 RamfuncsLoadStart;
    extern Uint16 RamfuncsLoadEnd;
    extern Uint16 RamfuncsRunStart;
    
    
    int main(void)
    {
        int i;
        void set_up_device_handles(void);
        void I2CA_Init(void);
        void dump_i2c_regs(void);
        void dump_status_reg(void);
        char buf[20];
    
        // Copy RAM only functions to RAM, load factory calibration, set up device handles.
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
        InitSysCtrl();
        set_up_device_handles();
        CLK_setOscSrc(myClk, CLK_OscSrc_Internal);  // Select the internal oscillator 1 (10 MHz) as the clock source
        PLL_setup(myPll, PLL_Multiplier_12, PLL_DivideSelect_ClkIn_by_2);   // Set up the PLL for (10 MHz * 12)/2 = 60 MHz.
    
        // Configure GPIOs 32 and 33 for use by I2C.
        EALLOW;
        GPIO_setPullUp(myGpio, GPIO_Number_32, GPIO_PullUp_Enable);
        GPIO_setPullUp(myGpio, GPIO_Number_33, GPIO_PullUp_Enable);
        GPIO_setQualification(myGpio, GPIO_Number_32, GPIO_Qual_ASync);
        GPIO_setQualification(myGpio, GPIO_Number_33, GPIO_Qual_ASync);
        GPIO_setMode(myGpio, GPIO_Number_32, GPIO_32_Mode_SDAA);
        GPIO_setMode(myGpio, GPIO_Number_33, GPIO_33_Mode_SCLA);
        EDIS;
    
        // Initialize the I2C hardware.
        I2CA_Init();
    
        // Display register contents.
        dump_i2c_regs();
    
        // Write one byte to slave device.
        I2caRegs.I2CMDR.bit.IRS = 1;        // Enable I2C
        I2caRegs.I2CCNT = 1;                // Count=1
        I2caRegs.I2CDXR = 0x80;             // Write first byte to data register
        I2caRegs.I2CMDR.all = 0x2600;       // Set: STT, MST, TRX bits to start the transmission
        for (i=0; i<20; i++)
        {
            dump_status_reg();
            DELAY_US(1000);
        }
        return 0;
    }
    
    void dump_status_reg(void)
    {
        if (I2caRegs.I2CSTR.bit.SDIR == 1)
        {
            puts("SDIR ");
        }
        if (I2caRegs.I2CSTR.bit.NACKSNT == 1)
        {
            puts("NACKSNT ");
        }
        if (I2caRegs.I2CSTR.bit.BB == 1)
        {
            puts("BB ");
        }
        if (I2caRegs.I2CSTR.bit.RSFULL == 1)
        {
            puts("RSFULL ");
        }
        if (I2caRegs.I2CSTR.bit.XSMT == 1)
        {
            puts("XSMT ");
        }
        if (I2caRegs.I2CSTR.bit.AAS == 1)
        {
            puts("AAS ");
        }
        if (I2caRegs.I2CSTR.bit.AD0 == 1)
        {
            puts("AD0 ");
        }
        if (I2caRegs.I2CSTR.bit.SCD == 1)
        {
            puts("SCD ");
        }
        if (I2caRegs.I2CSTR.bit.XRDY == 1)
        {
            puts("XRDY ");
        }
        if (I2caRegs.I2CSTR.bit.RRDY == 1)
        {
            puts("RRDY ");
        }
        if (I2caRegs.I2CSTR.bit.ARDY == 1)
        {
            puts("ARDY ");
        }
        if (I2caRegs.I2CSTR.bit.NACK == 1)
        {
            puts("NACK ");
        }
    //    if (I2caRegs.I2CSTR.bit.AL == 1) // ?Listed in SPRUFZ9D but not actually available
    //    {
    //        puts("AL ");
    //    }
        puts("\r\n");
    }
    
    void dump_i2c_regs(void)
    {
        char buf[20];
        sprintf(buf, "I2COAR=0x%04X\r\n", I2caRegs.I2COAR);
        puts(buf);
        sprintf(buf, "I2CIER=0x%04X\r\n", I2caRegs.I2CIER.all);
        puts(buf);
        sprintf(buf, "I2CSTR=0x%04X\r\n", I2caRegs.I2CSTR.all);
        puts(buf);
        sprintf(buf, "I2CCLKL=0x%04X\r\n", I2caRegs.I2CCLKL);
        puts(buf);
        sprintf(buf, "I2CCLKH=0x%04X\r\n", I2caRegs.I2CCLKH);
        puts(buf);
        sprintf(buf, "I2CCNT=0x%04X\r\n", I2caRegs.I2CCNT);
        puts(buf);
        sprintf(buf, "I2CDRR=0x%04X\r\n", I2caRegs.I2CDRR);
        puts(buf);
        sprintf(buf, "I2CSAR=0x%04X\r\n", I2caRegs.I2CSAR);
        puts(buf);
        sprintf(buf, "I2CDXR=0x%04X\r\n", I2caRegs.I2CDXR);
        puts(buf);
        sprintf(buf, "I2CDXR=0x%04X\r\n", I2caRegs.I2CDXR);
        puts(buf);
        sprintf(buf, "I2CISRC=0x%04X\r\n", I2caRegs.I2CISRC.all);
        puts(buf);
        sprintf(buf, "I2CEMDR=0x%04X\r\n", I2caRegs.I2CEMDR.all);
        puts(buf);
        sprintf(buf, "I2CPSC=0x%04X\r\n", I2caRegs.I2CPSC.all);
        puts(buf);
        sprintf(buf, "I2CFFTX=0x%04X\r\n", I2caRegs.I2CFFTX.all);
        puts(buf);
        sprintf(buf, "I2CFFRX=0x%04X\r\n", I2caRegs.I2CFFRX.all);
        puts(buf);
     }
    
    void I2CA_Init(void)
    {
        I2caRegs.I2CMDR.all = 0;                // Disable I2C module and clear all options
        I2caRegs.I2CSAR = TLC59116_SLAVE_ADDR;  // Slave address of LED driver chip
        I2caRegs.I2CFFTX.all = 0;
        I2caRegs.I2CFFRX.all = 0;
    
        // Set the clock rates:
        //    Module clock rate: (CPU clock)/(IPSC + 1) = 10 MHz.
        //    I2C bus clock divider registers: 10 MHz/((ICCL+d)+(ICCH+d))
        //      where'd'=5 (see sprufz9d.pdf) produces bus clock at 100 KHz.
        I2caRegs.I2CPSC.all = 5;                // 60 MHz/(IPSC+1) = 10 MHz
        I2caRegs.I2CCLKL = 45;                  // ICCL+d = 50
        I2caRegs.I2CCLKH = 45;                  // ICCH+d = 50
        CLK_enableI2cClock(myClk);
        I2caRegs.I2CMDR.bit.IRS = 1;            // Enable I2C module
        return;
    }
    
    void set_up_device_handles(void)
    {
        myClk = CLK_init((void *) CLK_BASE_ADDR, sizeof(CLK_Obj));
        myPll = PLL_init((void *)PLL_BASE_ADDR, sizeof(PLL_Obj));
        myGpio = GPIO_init((void *) GPIO_BASE_ADDR, sizeof(GPIO_Obj));
    }
    

  • Hi Mike,

    Wanted to point out in case you weren't already aware that there's an easier way to view the registers within CCS while debugging rather than printing them out to a terminal. While debugging your program in CCS you can use the expressions or registers window to check the current value of registers. See the screenshot below:

    I'll try and provide you some simple code to get you started sending bytes in the next few days (I'll shoot for Monday at the latest). Do you have a preference of not using the I2C FIFO in your application? Not sure if you've already referenced the i2c_eeprom example program in C2000ware already or not, it's written to use the I2C FIFO however.

    C:\ti\c2000\C2000Ware_1_00_06_00\device_support\f2802x\examples\structs\i2c_eeprom

    Best,

    Kevin

  • Kevin, thanks for the info.  I put debugging statements into the code because I need to copy/paste the output, so I can email it to our hardware engineer, who works in another office.

    Although I didn't hear from him late yesterday, I'm almost positive there is a hardware bug that would explain why we're not getting signals onto the wires.  He built several boards and apparently only one is working right.  I expect he'll ship me a fix early next week.

    But I would welcome some simple code that shows how to write data.  The EEPROM example is hard to follow due to the way it distributes processing between interrupt and non-interrupt time.

    I thought I read somewhere that the FIFO on the F28027 really holds only 4 instead of 16 bytes, is that true?

    I do need to update the LEDs very rapidly, though, so after getting simple writes to work I'll probably switch to using the TX FIFO.

    -- Mike

  • Hi Mike,

    OK, please keep me updated if it does end up being a hardware issue. It could be that the slave isn't receiving the address correctly and a NACK is being received during the initial slave addressing portion. This would prevent any additional bytes to be sent over the I2C bus.

    I have some sample code written, but do not have a sufficient setup right now to test (need a good slave device to use...). Once I have something tested and presentable I'll share it. Yes I agree that the EEPROM example can be hard to follow and it's really only geared towards using an EEPROM slave device.

    That's correct, the F28027 FIFO is only 4 bytes deep. You'd have to keep filling the TX FIFO or emptying the RX FIFO.

    Best,
    Kevin
  • False alarm on the hardware issue.  The hardware guy thought that perhaps our pull-ups were using non-spec'd values but upon re-reading it, he says they are fine.

    If you could paste your initial code, even if not pretty, I'd appreciate it.

    Thanks -- Mike

  • Hi Mike,

    This is still a work in progress that I'd like to improve, but the I2CA_WriteToReg() function works properly for the time being. You can import the 2802xI2C_eeprom example within C2000ware into CCS and replace the main.c file with this one to test it. You'll likely need to tweak the slave address, control register, and data buffer bytes used for your own application

    //###########################################################################
    //
    // FILE:    2802xI2C_non_FIFO_main.c
    //
    // TITLE:   2802x_I2C_non_FIFO_example
    //
    // ASSUMPTIONS:
    //
    //    Add description here... TODO
    //
    //    $Boot_Table
    //    While an emulator is connected to your device, the TRSTn pin = 1,
    //    which sets the device into EMU_BOOT boot mode. In this mode, the
    //    peripheral boot modes are as follows:
    //
    //      Boot Mode:   EMU_KEY        EMU_BMODE
    //                   (0xD00)         (0xD01)
    //      ---------------------------------------
    //      Wait         !=0x55AA        X
    //      I/O          0x55AA          0x0000
    //      SCI          0x55AA          0x0001
    //      Wait         0x55AA          0x0002
    //      Get_Mode     0x55AA          0x0003
    //      SPI          0x55AA          0x0004
    //      I2C          0x55AA          0x0005
    //      OTP          0x55AA          0x0006
    //      Wait         0x55AA          0x0007
    //      Wait         0x55AA          0x0008
    //      SARAM        0x55AA          0x000A   <-- "Boot to SARAM"
    //      Flash        0x55AA          0x000B
    //      Wait         0x55AA          Other
    //
    //   Write EMU_KEY to 0xD00 and EMU_BMODE to 0xD01 via the debugger
    //   according to the Boot Mode Table above. Build/Load project,
    //   Reset the device, and Run example
    //
    //   $End_Boot_Table
    //
    // DESCRIPTION:
    //
    //    This program will write 1-14 words to EEPROM and read them back.
    //    The data written and the EEPROM address written to are contained
    //    in the message structure, I2cMsgOut1. The data read back will be
    //    contained in the message structure I2cMsgIn1.
    //
    //    This program will work with the on-board I2C EEPROM supplied on
    //    the F2802x eZdsp.
    //
    //
    //###########################################################################
    // $TI Release: F2802x Support Library v3.02.00.00 $
    // $Release Date: Tue Jun 26 03:12:17 CDT 2018 $
    // $Copyright:
    // Copyright (C) 2009-2018 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    //
    // Included Files
    //
    #include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
    
    //
    // Function Prototypes
    //
    void   I2CA_Init(void);
    uint16_t I2CA_WriteToReg(uint16_t slave_addr, uint16_t reg_value,
                             uint16_t data[], uint16_t data_size);
    uint16_t I2CA_ReadFromReg(uint16_t slave_addr, uint16_t reg_value, uint16_t data[]);
    void InitI2CAGpio();
    
    //
    // Defines
    //
    #define I2C_SLAVE_ADDR        0x50
    #define NACK_CHECK            1
    
    //
    // Globals
    //
    
    
    //
    // Main
    //
    void main(void)
    {
        uint16_t Error;
    
        //
        // WARNING: Always ensure you call memcpy before running any functions from
        // RAM InitSysCtrl includes a call to a RAM based function and without a 
        // call to memcpy first, the processor will go "into the weeds"
    #ifdef _FLASH
        memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
    #endif
    
        //
        // Initialize System Control:
        // PLL, WatchDog, enable Peripheral Clocks
        // This example function is found in the f2802x_SysCtrl.c file.
        //
        InitSysCtrl();
        
        //
        // Setup only the GP I/O only for I2C functionality
        //
        InitI2CGpio();
    
        //
        // Clear all interrupts and initialize PIE vector table:
        // Disable CPU interrupts
        //
        DINT;
    
        //
        // Initialize PIE control registers to their default state.
        // The default state is all PIE interrupts disabled and flags
        // are cleared.
        // This function is found in the f2802x_PieCtrl.c file.
        //
        InitPieCtrl();
    
        //
        // Disable CPU interrupts and clear all CPU interrupt flags
        //
        IER = 0x0000;
        IFR = 0x0000;
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        // This will populate the entire table, even if the interrupt
        // is not used in this example.  This is useful for debug purposes.
        // The shell ISR routines are found in f2802x_DefaultIsr.c.
        // This function is found in f2802x_PieVect.c.
        //
        InitPieVectTable();
    
        //
        // Initialize all the Device Peripherals
        //
        I2CA_Init();    // I2C-A only
    
        uint16_t reg_value, data_buff[5];
    
        reg_value = 0x01;
    
        data_buff[0] = 0x05;
        data_buff[1] = 0x06;
        data_buff[2] = 0x07;
        data_buff[3] = 0x08;
        data_buff[4] = 0x09;
    
        //
        // User specific code
        //
        I2CA_WriteToReg(I2C_SLAVE_ADDR, reg_value, data_buff, sizeof(data_buff));
    
        __asm("   ESTOP0");
    
    }
    
    //
    // I2CA_Init -
    //
    void
    I2CA_Init(void)
    {
        //
        // I2CCLK = SYSCLK/(I2CPSC+1)
        //
    #if (CPU_FRQ_40MHZ||CPU_FRQ_50MHZ)
        I2caRegs.I2CPSC.all = 4;       // Prescaler - need 7-12 Mhz on module clk
    #endif
    
    #if (CPU_FRQ_60MHZ)
        I2caRegs.I2CPSC.all = 6;       // Prescaler - need 7-12 Mhz on module clk
    #endif
        // Set I2CCLKL/I2CCLKH for 100KHz SCL clock
        I2caRegs.I2CCLKL = 38;           // NOTE: must be non zero
        I2caRegs.I2CCLKH = 38;            // NOTE: must be non zero
        I2caRegs.I2CIER.all = 0x0;      // Disable interrupts
    
        //
        // Take I2C out of reset. Stop I2C when suspended
        //
        I2caRegs.I2CMDR.all = 0x0020;
    
        return;
    }
    
    //
    // InitI2CGpio - This function initializes GPIO pins to function as I2C pins
    //
    // Each GPIO pin can be configured as a GPIO pin or up to 3 different
    // peripheral functional pins. By default all pins come up as GPIO
    // inputs after reset.
    //
    // Caution:
    // Only one GPIO pin should be enabled for SDAA operation.
    // Only one GPIO pin shoudl be enabled for SCLA operation.
    // Comment out other unwanted lines.
    //
    void
    InitI2CAGpio()
    {
        EALLOW;
    
        //
        // Enable internal pull-up for the selected pins
        // Pull-ups can be enabled or disabled disabled by the user.
        // This will enable the pullups for the specified pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;   // Enable pull-up for GPIO32 (SDAA)
        GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;   // Enable pull-up for GPIO33 (SCLA)
    
        //
        // Set qualification for selected pins to asynch only
        // This will select asynch (no qualification) for the selected pins.
        // Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
        GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)
    
        //
        // Configure I2C pins using GPIO regs
        // This specifies which of the possible GPIO pins will be I2C
        // functional pins. Comment out other unwanted lines.
        //
        GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 for SDAA
        GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 for SCLA
    
        EDIS;
    }
    
    //
    // I2CA_WriteToReg - This function writes data bytes to a slave
    //                   device's register.
    //
    // INPUTS:
    //      - slave_addr ==> Address of slave device being written to
    //      - reg_value ==> Slave device register being written to
    //      - data[] ==> data buffer of bytes to be written to the slave
    //                      device register
    //      - data_size ==> # of bytes being written, size of data buffer
    //
    uint16_t I2CA_WriteToReg(uint16_t slave_addr, uint16_t reg_value,
                             uint16_t data[], uint16_t data_size)
    {
        uint16_t i;
    
        //
        // Wait until the STP bit is cleared from any previous master communication
        // Clearing of this bit by the module is delayed until after the SCD bit is
        // set. If this bit is not checked prior to initiating a new message, the
        // I2C could get confused.
        //
        if (I2caRegs.I2CMDR.bit.STP == 1)
        {
            return I2C_STP_NOT_READY_ERROR;
        }
    
        //
        // Setup slave address
        //
        I2caRegs.I2CSAR = slave_addr;
    
        //
        // Check if bus busy
        //
        if (I2caRegs.I2CSTR.bit.BB == 1)
        {
            return I2C_BUS_BUSY_ERROR;
        }
    
        //
        // Set up as master transmitter and send START condition
        // FREE + MST + TRX + IRS
        //
        I2caRegs.I2CMDR.all = 0x4620;
    
        //
        // Setup number of bytes to send
        // == (# of register bytes) + (# of data[] buffer bytes)
        //
        I2caRegs.I2CCNT = 1 + data_size;
    
        I2caRegs.I2CMDR.bit.STT = 0x1; // Start condition
        I2caRegs.I2CMDR.bit.STP = 0x1; // Stop condition will be
    //                                   // generated when I2CCNT is zero
    
        //
        // I2C module will send the following:
        // register bytes ==> data bytes ==> STOP condition
        //
    
        while(!I2caRegs.I2CSTR.bit.XRDY){} // Make sure data
                                           // is ready to be written
        I2caRegs.I2CDXR = reg_value;
    
        #if NACK_CHECK // check if NACK was received
            if(I2caRegs.I2CSTR.bit.NACK == 1)
            {
                I2caRegs.I2CMDR.bit.STP = 1;
                I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
            }
        #endif
    
    
        for (i=0; i< data_size; i++)
        {
            while(!I2caRegs.I2CSTR.bit.XRDY){} // Make sure data
                                               // is ready to be written
            I2caRegs.I2CDXR = data[i];
    
            #if NACK_CHECK // check if NACK was received
                if(I2caRegs.I2CSTR.bit.NACK == 1)
                {
                    I2caRegs.I2CMDR.bit.STP = 1;
                    I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
                }
            #endif
        }
    
        // Data successfully written
        return I2C_SUCCESS;
    }
    
    //
    // I2CA_ReadFromReg - This function reads data bytes from a slave
    //                   device's register.
    //
    // INPUTS:
    //      - slave_addr ==> Address of slave device being read from
    //      - reg_value ==> Slave device register being read from
    //      - data[] ==> data buffer to store the bytes read from the
    //                      slave device register
    //
    uint16_t I2CA_ReadFromReg(uint16_t slave_addr, uint16_t reg_value, uint16_t data[])
    {
        //
        // Wait until the STP bit is cleared from any previous master communication
        // Clearing of this bit by the module is delayed until after the SCD bit is
        // set. If this bit is not checked prior to initiating a new message, the
        // I2C could get confused.
        //
        if (I2caRegs.I2CMDR.bit.STP == 1)
        {
            return I2C_STP_NOT_READY_ERROR;
        }
    
        // Data successfully read
        return I2C_SUCCESS;
    }
    
    //
    // End of File
    //
    
    

    Hope this helps,

    Kevin

  • Hi Kevin:
    I tried to post this earlier but I don't think it worked.  Long story short, I got it working based on your example code.  Thanks for the help.

    Here's a snippet of what I'm doing.
        I2caRegs.I2CSAR = TLC59116_SLAVE_ADDR;
        I2caRegs.I2CMDR.all = 0x4620;       // FREE, MST, TRX, IRS
        I2caRegs.I2CCNT = LEN_LIGHT_MSG;
        I2caRegs.I2CMDR.bit.STT = 1;
        I2caRegs.I2CMDR.bit.STP = 1;
        for (i=0; i<LEN_LIGHT_MSG; i++)
        {
            I2caRegs.I2CDXR = light_msg[i];
            while (I2caRegs.I2CSTR.bit.XRDY == 0);
        }